!82 feat: 自定义logo功能

* !1 fixed-bug:更正操作结果提示信息与操作页面不一致,更改为都在/admin/config/settings 页面上
* fixed-bug:更正操作结果提示信息与操作页面不一致,更改为都在/admin/config/settings 页面上
* refactor(admin): 移动自定义logo上传表单位置
* style: 还原管理后台仪表盘模板代码格式
* style: 调整注释格式和规范国际化语言文件的标签文本
* style: 还原管理后台仪表盘模板代码格式
* feat: 添加单个设置的获取和设置函数
* feat: 自定义logo功能
This commit is contained in:
away
2025-06-27 06:04:14 +00:00
repo.diff.committed_by 孟宁
repo.diff.parent aa01ae3e39
repo.diff.commit 8b77dbb369
repo.diff.stats_desc%!(EXTRA int=8, int=112, int=1)

repo.diff.view_file

@@ -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

repo.diff.view_file

@@ -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

repo.diff.view_file

@@ -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=检查所有仓库统计

repo.diff.view_file

@@ -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")
}

repo.diff.view_file

@@ -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)

repo.diff.view_file

@@ -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)
})
}

repo.diff.view_file

@@ -1,4 +1,36 @@
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}}
<!-- 自定义logo upload -->
<h4 class="ui top attached header">
{{ctx.Locale.Tr "admin.dashboard.app_logo_config"}}
</h4>
<div class="ui attached segment">
<form
class="ui form"
action="{{ AppSubUrl }}/admin/logo"
method="post"
enctype="multipart/form-data"
>
{{.CsrfTokenHtml}}
<div class="inline field tw-pl-4">
<label
for="avatar"
>{{ctx.Locale.Tr "admin.dashboard.choose_new_logo"}}</label
>
<input
name="avatar"
type="file"
accept="image/png,image/jpeg,image/gif,image/webp"
/>
</div>
<div class="field">
<button class="ui primary button">
{{ctx.Locale.Tr "admin.dashboard.update_logo"}}
</button>
</div>
</form>
</div>
<h4 class="ui top attached header">
{{ctx.Locale.Tr "admin.config.picture_config"}}
</h4>

repo.diff.view_file

@@ -7,7 +7,7 @@
<div class="navbar-left">
<!-- the logo -->
<a class="item" id="navbar-logo" href="{{AppSubUrl}}/" aria-label="{{if .IsSigned}}{{ctx.Locale.Tr "dashboard"}}{{else}}{{ctx.Locale.Tr "home"}}{{end}}">
<img width="auto" height="30" src="{{AssetUrlPrefix}}/img/logo.svg" alt="{{ctx.Locale.Tr "logo"}}" aria-hidden="true">
<img width="auto" height="30" src="{{if .CustomLogoPath}}{{.CustomLogoPath}}{{else}}{{AssetUrlPrefix}}/img/logo.svg{{end}}" alt="{{ctx.Locale.Tr "logo"}}" aria-hidden="true">
</a>
<!-- mobile right menu, it must be here because in mobile view, each item is a flex column, the first item is a full row column -->