refactor: CSP nonce替代unsafe-inline, HSTS始终启用, router/api拆分, 管理后台+用户设置页拆分, DB健康降级, 时区配置, UID统一解析, CI接入
Some checks failed
CI / Lint + Build (push) Has been cancelled

审计修复:
- CSP: unsafe-inline移除, nonce替代; unsafe-eval保留供Vditor使用
- HSTS: 始终启用(不再依赖release模式)
- Controller Exp: common.GetGinExp包装, 不再直接读context
- UID解析: common.ParseUIDParam统一, follow/admin controller改用

重构:
- router/api.go(198行)拆为7个域文件: auth/settings/posts/comments/reactions/social/studio
- 管理后台站点设置: 单页拆为4个子页(brand/security/registration/content)+子菜单
- 前台用户设置页: 1201行拆为6个独立模板+6个独立JS文件

新增:
- DB健康检测中间件(middleware/db_health.go): 5s ping+降级页面
- 时区配置: config.yaml server.timezone→time.Local初始化
- .gitea/workflows/ci.yml: strict模式CI流水线
This commit is contained in:
2026-06-22 03:06:24 +08:00
parent e7185f58fb
commit 2449a27eb5
43 changed files with 2157 additions and 226 deletions

View File

@ -0,0 +1,152 @@
{{template "admin/layout/base.html" .}}
<div class="page-header">
<h1>站点设置</h1>
<p class="page-desc">管理站点基本配置和合规信息</p>
</div>
{{template "admin/site-settings/_menu.html" .}}
<!-- 基本设置 -->
<div class="settings-section">
<div class="section-title">基本设置</div>
<div class="section-body">
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">站点名称</span>
<span class="setting-desc">全站品牌名(导航栏、标题、页脚等位置)</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-name" class="setting-input" placeholder="MetaLab" value="{{.SiteName}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.name" data-input="setting-site-name">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">站点标语</span>
<span class="setting-desc">首页 Hero 区域的副标题</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-tagline" class="setting-input" placeholder="下一代开发者社区" value="{{.SiteTagline}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.tagline" data-input="setting-site-tagline">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">联系邮箱</span>
<span class="setting-desc">申诉/联系邮箱,显示在社区准则等页面</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-email" class="setting-input" placeholder="metazone@foxmail.com" value="{{.ContactEmail}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.contact_email" data-input="setting-site-email">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">附加信息</span>
<span class="setting-desc">页脚附加信息,留空则隐藏(如 "Framework: MetaGenesis"</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-framework" class="setting-input" placeholder="留空则不显示" value="{{.Framework}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.framework" data-input="setting-site-framework">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">版权起始年份</span>
<span class="setting-desc">页脚版权标起始年(如 2024 → © 2024-当前年)</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-copyright" class="setting-input" placeholder="2024" value="{{.CopyrightStart}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.copyright_start" data-input="setting-site-copyright">保存</button>
</div>
</div>
</div>
</div>
<!-- 合规信息 -->
<div class="settings-section">
<div class="section-title">合规信息</div>
<div class="section-body">
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">运营主体</span>
<span class="setting-desc">页脚展示的运营方名称</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-operator" class="setting-input" placeholder="留空则不显示" value="{{.OperatorName}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.operator_name" data-input="setting-site-operator">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">隐私政策</span>
<span class="setting-desc">纯手写 HTML&lt;a href="/privacy"&gt;隐私政策&lt;/a&gt;</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-privacy" class="setting-input" placeholder="留空则不显示" value="{{.PrivacyURL}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.privacy_url" data-input="setting-site-privacy">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">服务条款</span>
<span class="setting-desc">纯手写 HTML&lt;a href="/terms"&gt;服务条款&lt;/a&gt;</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-terms" class="setting-input" placeholder="留空则不显示" value="{{.TermsURL}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.terms_url" data-input="setting-site-terms">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">ICP 备案</span>
<span class="setting-desc">纯手写 HTML&lt;a href="https://beian.miit.gov.cn"&gt;京ICP备XXXX号&lt;/a&gt;</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-icp" class="setting-input" placeholder="留空则不显示" value="{{.ICPNumber}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.icp_number" data-input="setting-site-icp">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">ICP 经营许可证</span>
<span class="setting-desc">纯手写 HTML留空则不显示</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-icp-license" class="setting-input" placeholder="留空则不显示" value="{{.ICPLicense}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.icp_license" data-input="setting-site-icp-license">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">公安备案</span>
<span class="setting-desc">纯手写 HTML留空则不显示</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-police" class="setting-input" placeholder="留空则不显示" value="{{.PoliceNumber}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.police_number" data-input="setting-site-police">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">文网文</span>
<span class="setting-desc">纯手写 HTML留空则不显示</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-wenwangwen" class="setting-input" placeholder="留空则不显示" value="{{.WenWangWen}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.wenwangwen" data-input="setting-site-wenwangwen">保存</button>
</div>
</div>
<div class="setting-item">
<div class="setting-info">
<span class="setting-label">算法备案</span>
<span class="setting-desc">纯手写 HTML留空则不显示</span>
</div>
<div class="setting-input-wrap">
<input type="text" id="setting-site-algorithm-filing" class="setting-input" placeholder="留空则不显示" value="{{.AlgorithmFiling}}">
<button class="btn btn-sm btn-primary btn-save" data-key="site.algorithm_filing" data-input="setting-site-algorithm-filing">保存</button>
</div>
</div>
</div>
</div>
{{template "admin/layout/footer.html" .}}