diff --git a/routers/web/admin/branding.go b/routers/web/admin/branding.go index 59acfc3c6b..b4d5affb1c 100644 --- a/routers/web/admin/branding.go +++ b/routers/web/admin/branding.go @@ -32,9 +32,66 @@ func Branding(ctx *context.Context) { ctx.Data["HasLogo"] = fileExists(filepath.Join(imgDir, "logo.png")) ctx.Data["HasFavicon"] = fileExists(filepath.Join(imgDir, "favicon.png")) + ctx.Data["MetaDescription"] = setting.UI.Meta.Description + ctx.Data["MetaAuthor"] = setting.UI.Meta.Author + ctx.Data["HelpURL"] = setting.HelpURL + ctx.Data["SupportURL"] = setting.SupportURL + ctx.HTML(http.StatusOK, tplBranding) } +// BrandingSettings handles the text branding form submission. +func BrandingSettings(ctx *context.Context) { + appName := ctx.FormString("app_name") + description := ctx.FormString("description") + helpURL := ctx.FormString("help_url") + supportURL := ctx.FormString("support_url") + author := ctx.FormString("author") + + // Update in-memory settings + if appName != "" { + setting.AppName = appName + } + if description != "" { + setting.UI.Meta.Description = description + } + setting.HelpURL = helpURL + setting.SupportURL = supportURL + if author != "" { + setting.UI.Meta.Author = author + } + + // Persist to app.ini + cfg, err := setting.NewConfigProviderFromFile(setting.CustomConf) + if err != nil { + ctx.Flash.Error("Failed to load config: " + err.Error()) + ctx.Redirect(setting.AppSubURL + "/-/admin/branding") + return + } + + if appName != "" { + cfg.Section("").Key("APP_NAME").SetValue(appName) + } + if description != "" { + cfg.Section("ui.meta").Key("DESCRIPTION").SetValue(description) + } + cfg.Section("").Key("HELP_URL").SetValue(helpURL) + cfg.Section("").Key("SUPPORT_URL").SetValue(supportURL) + if author != "" { + cfg.Section("ui.meta").Key("AUTHOR").SetValue(author) + } + + if err := cfg.SaveTo(setting.CustomConf); err != nil { + ctx.Flash.Error("Failed to save config: " + err.Error()) + log.Error("SaveTo %s: %v", setting.CustomConf, err) + } else { + ctx.Flash.Success("Branding settings saved") + log.Info("Branding settings updated: AppName=%s, Author=%s", appName, author) + } + + ctx.Redirect(setting.AppSubURL + "/-/admin/branding") +} + // BrandingUpload handles branding image uploads. func BrandingUpload(ctx *context.Context) { imageType := ctx.FormString("type") @@ -66,14 +123,12 @@ func BrandingUpload(ctx *context.Context) { } defer file.Close() - // Validate file size (max 2MB) if header.Size > 2*1024*1024 { ctx.Flash.Error("File too large (max 2MB)") ctx.Redirect(setting.AppSubURL + "/-/admin/branding") return } - // Ensure the custom image directory exists imgDir := brandingImageDir() if err := os.MkdirAll(imgDir, 0o755); err != nil { ctx.Flash.Error("Failed to create image directory") @@ -82,7 +137,6 @@ func BrandingUpload(ctx *context.Context) { return } - // Write the file destPath := filepath.Join(imgDir, filename) dest, err := os.Create(destPath) if err != nil { @@ -100,11 +154,10 @@ func BrandingUpload(ctx *context.Context) { return } - // Also remove SVG override if present (PNG should take priority) + // Remove SVG override if present svgPath := filepath.Join(imgDir, filename[:len(filename)-4]+".svg") if fileExists(svgPath) { os.Remove(svgPath) - log.Info("Removed SVG override: %s", svgPath) } ctx.Flash.Success("Branding image updated: " + imageType) diff --git a/routers/web/web.go b/routers/web/web.go index 4b24034a1c..ff6f18a99a 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -768,6 +768,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Group("/branding", func() { m.Get("", admin.Branding) m.Post("/upload", admin.BrandingUpload) + m.Post("/settings", admin.BrandingSettings) }) m.Group("/monitor", func() { diff --git a/templates/admin/branding.tmpl b/templates/admin/branding.tmpl index 10f3f2b707..d1010ca31d 100644 --- a/templates/admin/branding.tmpl +++ b/templates/admin/branding.tmpl @@ -4,67 +4,110 @@ {{svg "octicon-paintbrush" 16}} Branding
Upload custom branding images. Changes take effect immediately.
- -
-
- Changes take effect immediately.
+| Setting | +Upload | +Preview | +
|---|---|---|
|
+ Nav Icon {{if .HasNavIcon}}Custom{{else}}Default{{end}}
+ Top-left corner across all pages. Square, 30x30px.
+ |
+ + + | +
+
+ |
+
|
+ Login Logo {{if .HasLogo}}Custom{{else}}Default{{end}}
+ Login page and homepage. Wide format, max 220px display.
+ |
+ + + | +
+
+ |
+
|
+ Favicon {{if .HasFavicon}}Custom{{else}}Default{{end}}
+ Browser tab and PWA app icon. Square, 256x256px.
+ |
+ + + | +
+ |
+