feat: 社区准则改为数据库存储
- AuthController 注入 SiteSettings 依赖,RegisterPage 优先从 DB 读取准则 - DB 中 site.guidelines 为空时 fallback 到静态 guidelines.html 文件 - 管理后台站点设置页新增「内容管理」分区,textarea 编辑社区准则 - 添加准则编辑区垂直布局样式
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"metazone.cc/metalab/internal/common"
|
"metazone.cc/metalab/internal/common"
|
||||||
@ -17,11 +18,12 @@ type AuthController struct {
|
|||||||
sessionManager *session.Manager
|
sessionManager *session.Manager
|
||||||
rateLimiter rateLimiter
|
rateLimiter rateLimiter
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
|
siteSettings *config.SiteSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAuthController 构造函数
|
// NewAuthController 构造函数
|
||||||
func NewAuthController(authService authUseCase, sm *session.Manager, limiter rateLimiter, cfg *config.Config) *AuthController {
|
func NewAuthController(authService authUseCase, sm *session.Manager, limiter rateLimiter, cfg *config.Config, siteSettings *config.SiteSettings) *AuthController {
|
||||||
return &AuthController{authService: authService, sessionManager: sm, rateLimiter: limiter, cfg: cfg}
|
return &AuthController{authService: authService, sessionManager: sm, rateLimiter: limiter, cfg: cfg, siteSettings: siteSettings}
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterPage 注册页面(已登录用户重定向到首页)
|
// RegisterPage 注册页面(已登录用户重定向到首页)
|
||||||
@ -30,11 +32,19 @@ func (ac *AuthController) RegisterPage(c *gin.Context) {
|
|||||||
c.Redirect(http.StatusFound, "/")
|
c.Redirect(http.StatusFound, "/")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guidelines, err := theme.LoadContent("templates/MetaLab-2026/guidelines.html")
|
// 优先从 DB 读取社区准则,为空时 fallback 到静态文件
|
||||||
|
guidelinesHTML := ac.siteSettings.Get("site.guidelines", "")
|
||||||
|
var guidelines template.HTML
|
||||||
|
if guidelinesHTML != "" {
|
||||||
|
guidelines = template.HTML(guidelinesHTML)
|
||||||
|
} else {
|
||||||
|
content, err := theme.LoadContent("templates/MetaLab-2026/guidelines.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusInternalServerError, "加载准则失败")
|
c.String(http.StatusInternalServerError, "加载准则失败")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
guidelines = content
|
||||||
|
}
|
||||||
c.HTML(http.StatusOK, "auth/register.html", common.BuildPageData(c, gin.H{
|
c.HTML(http.StatusOK, "auth/register.html", common.BuildPageData(c, gin.H{
|
||||||
"Title": "注册",
|
"Title": "注册",
|
||||||
"ExtraCSS": "/static/css/auth.css",
|
"ExtraCSS": "/static/css/auth.css",
|
||||||
|
|||||||
@ -78,7 +78,7 @@ func buildDepsCore(db *gorm.DB, cfg *config.Config, siteSettings *config.SiteSet
|
|||||||
sessionMgr := session.NewManager(sessionStore, userRepo, cfg)
|
sessionMgr := session.NewManager(sessionStore, userRepo, cfg)
|
||||||
authService := service.NewAuthService(userRepo, sessionMgr, cfg, siteSettings)
|
authService := service.NewAuthService(userRepo, sessionMgr, cfg, siteSettings)
|
||||||
rateLimiter := middleware.NewRateLimiter()
|
rateLimiter := middleware.NewRateLimiter()
|
||||||
authCtrl := controller.NewAuthController(authService, sessionMgr, rateLimiter, cfg)
|
authCtrl := controller.NewAuthController(authService, sessionMgr, rateLimiter, cfg, siteSettings)
|
||||||
avatarSvc := service.NewAvatarService(userRepo)
|
avatarSvc := service.NewAvatarService(userRepo)
|
||||||
authMdw := middleware.NewAuthMiddleware(cfg, sessionMgr)
|
authMdw := middleware.NewAuthMiddleware(cfg, sessionMgr)
|
||||||
return userRepo, sessionMgr, authService, rateLimiter, authCtrl, avatarSvc, authMdw
|
return userRepo, sessionMgr, authService, rateLimiter, authCtrl, avatarSvc, authMdw
|
||||||
|
|||||||
@ -115,6 +115,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 内容管理 -->
|
||||||
|
<div class="settings-section">
|
||||||
|
<div class="section-title">内容管理</div>
|
||||||
|
<div class="section-body">
|
||||||
|
<div class="setting-item setting-item-vertical">
|
||||||
|
<div class="setting-info">
|
||||||
|
<span class="setting-label">社区准则</span>
|
||||||
|
<span class="setting-desc">注册时需用户阅读并同意,支持 HTML 格式</span>
|
||||||
|
</div>
|
||||||
|
<div class="setting-input-block">
|
||||||
|
<textarea id="setting-site-guidelines" class="setting-textarea" rows="12" placeholder="留空则使用默认准则文件"></textarea>
|
||||||
|
<button class="btn btn-sm btn-primary btn-save-block" data-key="site.guidelines" data-input="setting-site-guidelines">保存准则</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 通用设置 -->
|
<!-- 通用设置 -->
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<div class="section-title">其他设置</div>
|
<div class="section-title">其他设置</div>
|
||||||
|
|||||||
@ -58,6 +58,35 @@
|
|||||||
.btn-save { width: 56px; text-align: center; }
|
.btn-save { width: 56px; text-align: center; }
|
||||||
.btn-save:disabled { opacity: 0.5; cursor: not-allowed; }
|
.btn-save:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||||
|
|
||||||
|
/* --- 垂直布局设置项(用于准则等大文本) --- */
|
||||||
|
.setting-item-vertical {
|
||||||
|
flex-direction: column; align-items: stretch;
|
||||||
|
}
|
||||||
|
.setting-item-vertical .setting-info {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.setting-input-block {
|
||||||
|
display: flex; flex-direction: column; gap: 10px;
|
||||||
|
}
|
||||||
|
.setting-textarea {
|
||||||
|
padding: 10px 12px;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 13px; line-height: 1.6;
|
||||||
|
font-family: 'Courier New', Consolas, monospace;
|
||||||
|
resize: vertical;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
.setting-textarea:focus { border-color: var(--primary); }
|
||||||
|
.btn-save-block {
|
||||||
|
align-self: flex-end;
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
.btn-save-block:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||||
|
|
||||||
/* --- 空状态 --- */
|
/* --- 空状态 --- */
|
||||||
.settings-empty {
|
.settings-empty {
|
||||||
text-align: center; padding: 28px 20px;
|
text-align: center; padding: 28px 20px;
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
// 已有专属 UI 的设置 key,不在"其他设置"中重复显示
|
// 已有专属 UI 的设置 key,不在"其他设置"中重复显示
|
||||||
var DEDICATED_KEYS = {
|
var DEDICATED_KEYS = {
|
||||||
'site.framework': true, 'site.copyright_start': true,
|
'site.framework': true, 'site.copyright_start': true,
|
||||||
|
'site.guidelines': true,
|
||||||
'maintenance.enabled': true,
|
'maintenance.enabled': true,
|
||||||
'registration.enabled': true,
|
'registration.enabled': true,
|
||||||
'audit.enabled': true, 'audit.username_audit': true, 'audit.avatar_audit': true, 'audit.bio_audit': true
|
'audit.enabled': true, 'audit.username_audit': true, 'audit.avatar_audit': true, 'audit.bio_audit': true
|
||||||
@ -51,6 +52,18 @@
|
|||||||
// 文本输入保存按钮
|
// 文本输入保存按钮
|
||||||
bindSaveButtons();
|
bindSaveButtons();
|
||||||
|
|
||||||
|
// 社区准则文本域
|
||||||
|
var guidelinesEl = document.getElementById('setting-site-guidelines');
|
||||||
|
if (guidelinesEl) {
|
||||||
|
guidelinesEl.value = allSettings['site.guidelines'] || '';
|
||||||
|
var guidelinesBtn = document.querySelector('[data-key="site.guidelines"]');
|
||||||
|
if (guidelinesBtn) {
|
||||||
|
guidelinesBtn.addEventListener('click', function() {
|
||||||
|
updateTextSetting('site.guidelines', guidelinesEl.value, guidelinesBtn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 其他设置(过滤已有专属UI的key)
|
// 其他设置(过滤已有专属UI的key)
|
||||||
renderOtherSettings(allSettings);
|
renderOtherSettings(allSettings);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user