diff --git a/models/system/setting.go b/models/system/setting.go index 4472b4c228..d737589e2b 100644 --- a/models/system/setting.go +++ b/models/system/setting.go @@ -99,6 +99,21 @@ func SetSettings(ctx context.Context, settings map[string]string) error { }) } +func SetSetting(ctx context.Context, key, value string) error { + return SetSettings(ctx, map[string]string{key: value}) +} + +func GetSetting(ctx context.Context, key string) (string, error) { + setting, exist, err := db.Get[Setting](ctx, builder.Eq{"setting_key": key}) + if err != nil { + return "", err + } + if !exist { + return "", nil + } + return setting.SettingValue, nil +} + type dbConfigCachedGetter struct { mu sync.RWMutex diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 7f845486e2..d88c49c290 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2885,6 +2885,9 @@ dashboard.delete_missing_repos.started = Delete all repositories missing their G dashboard.delete_generated_repository_avatars = Delete generated repository avatars dashboard.sync_repo_branches = Sync missed branches from git data to databases dashboard.sync_repo_tags = Sync tags from git data to database +dashboard.app_logo_config = Application Logo Configuration +dashboard.choose_new_logo = Choose New Logo +dashboard.update_logo = Update Logo dashboard.update_mirrors = Update Mirrors dashboard.repo_health_check = Health check all repositories dashboard.check_repo_stats = Check all repository statistics diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index d502940981..83b42148d6 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -2880,6 +2880,9 @@ dashboard.delete_missing_repos.started=删除所有丢失 Git 文件的仓库任 dashboard.delete_generated_repository_avatars=删除生成的仓库头像 dashboard.sync_repo_branches=将缺少的分支从 git 数据同步到数据库 dashboard.sync_repo_tags=从 git 数据同步标签到数据库 +dashboard.app_logo_config = 应用图标设置 +dashboard.choose_new_logo = 选择新的图标 +dashboard.update_logo = 更新图标 dashboard.update_mirrors=更新镜像仓库 dashboard.repo_health_check=健康检查所有仓库 dashboard.check_repo_stats=检查所有仓库统计 diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index 6fc97c949e..f0208906c9 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -6,14 +6,19 @@ package admin import ( "fmt" + "io" "net/http" + "os" + "path/filepath" "runtime" "sort" + "strconv" "strings" "time" activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" + system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/graceful" @@ -277,3 +282,46 @@ func MonitorStats(ctx *context.Context) { ctx.Data["StatsCounter"] = statsCounter ctx.HTML(http.StatusOK, tplStats) } + +func LogoPost(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.AvatarForm) + if form.Avatar == nil || form.Avatar.Filename == "" { + ctx.Flash.Error("No file uploaded") + ctx.Redirect(setting.AppSubURL + "/admin/config/settings") + return + } + + ext := filepath.Ext(form.Avatar.Filename) + if ext != ".png" && ext != ".jpg" && ext != ".jpeg" && ext != ".gif" && ext != ".webp" { + ctx.Flash.Error("Invalid file type") + ctx.Redirect(setting.AppSubURL + "/admin/config/settings") + return + } + + // 生成唯一文件名 + filename := "logo_" + strconv.FormatInt(time.Now().Unix(), 10) + ext + savePath := filepath.Join(setting.CustomPath, "public", "assets", "img", filename) + os.MkdirAll(filepath.Dir(savePath), os.ModePerm) + out, err := os.Create(savePath) + if err != nil { + ctx.Flash.Error("Failed to save file") + ctx.Redirect(setting.AppSubURL + "/admin/config/settings") + return + } + defer out.Close() + fr, _ := form.Avatar.Open() + defer fr.Close() + io.Copy(out, fr) + + // 保存路径到数据库 + relPath := "/assets/img/" + filename + err = system_model.SetSetting(ctx, "custom_logo_path", relPath) + if err != nil { + ctx.Flash.Error("Failed to update database") + ctx.Redirect(setting.AppSubURL + "/admin/config/settings") + return + } + + ctx.Flash.Success("Logo updated successfully") + ctx.Redirect(setting.AppSubURL + "/admin/config/settings") +} diff --git a/routers/web/web.go b/routers/web/web.go index d0a1ddca79..702aa6b588 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -733,6 +733,7 @@ func registerRoutes(m *web.Router) { m.Get("", admin.Dashboard) m.Get("/system_status", admin.SystemStatus) m.Post("", web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost) + m.Post("/logo", web.Bind(forms.AvatarForm{}), admin.LogoPost) m.Get("/self_check", admin.SelfCheck) m.Post("/self_check", admin.SelfCheckPost) diff --git a/services/context/context.go b/services/context/context.go index cd381f3d09..73e90da52f 100644 --- a/services/context/context.go +++ b/services/context/context.go @@ -17,6 +17,8 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" + system_model "code.gitea.io/gitea/models/system" + "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/httpcache" @@ -220,6 +222,13 @@ func Contexter() func(next http.Handler) http.Handler { ctx.Data["ManifestData"] = setting.ManifestData ctx.Data["AllLangs"] = translation.AllLangs() + // 保存logo路径到模板数据 + if logoPath, _ := system_model.GetSetting(ctx, "custom_logo_path"); logoPath != "" { + ctx.Data["CustomLogoPath"] = logoPath + } else { + ctx.Data["CustomLogoPath"] = "" + } + next.ServeHTTP(ctx.Resp, ctx.Req) }) } diff --git a/templates/admin/config_settings.tmpl b/templates/admin/config_settings.tmpl index 02ab5fd0fb..6f6d9eaac4 100644 --- a/templates/admin/config_settings.tmpl +++ b/templates/admin/config_settings.tmpl @@ -1,4 +1,36 @@ {{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}} + +