feat(v1.4): 初始管理员(id=1)可修改其他管理员的用户名、昵称和密码
build / build-and-test (push) Successful in 3m25s

- 设置 → 管理员:仅 id=1 的账户在“其他人”那一行看到「编辑」入口,自己那行不显示
- 新增编辑页 /settings/users/{id}/edit:可改用户名、显示名称,密码留空则不修改
- 重置密码后立即清除该账户的所有登录会话,强制对方用新密码重新登录;只改昵称/用户名不影响会话
- 服务端三重校验:非 id=1 拒绝、不能编辑自己、用户名 3-32 字符且唯一、密码 ≥6 位且两次一致
- 所有修改写入操作日志(旧用户名/昵称 → 新值,是否重置密码)
- 设置页根据当前账户显示不同提示:超管看到可编辑说明,其他人只看到“只有初始管理员可以修改”

数据库:无需变更(复用 users 表与 sessions 表)
测试:
- 新增单测 TestUpdateUserByAdmin:昵称更新、会话保留、改密后旧会话失效、新密码可登录旧密码失效、重名返回 ErrDuplicate、空用户名拒绝
- 功能验证 20 项:入口显示/隐藏、普通管理员与自我编辑被拒、改密踢下线、新旧密码、长度/一致性/重名校验、留空密码、日志记录
- 原有 119 项验收回归全绿;go vet / go test ./... 通过;版本号 1.4.0
This commit is contained in:
subtrack
2026-10-19 00:21:47 +08:00
parent 8cfc9f5891
commit 95fa4fd6fd
8 changed files with 244 additions and 1 deletions
@@ -26,6 +26,7 @@
<section class="section card">
<h2>管理员</h2>
<p class="muted small">所有账户权限相同,任何操作都会记在日志里。每个管理员的颜色用于日历左侧竖条和待办标识。</p>
<p class="muted small">{{if eq .User.ID 1}}你是初始管理员,可以点「编辑」修改其他管理员的用户名、昵称和密码。{{else}}只有初始管理员(首个账号)可以修改其他管理员的资料。{{end}}</p>
<div class="table-wrap">
<table class="table tight">
<thead><tr><th>用户名</th><th>显示名称</th><th>打手颜色</th><th>状态</th><th>创建时间</th><th>最近登录</th><th></th></tr></thead>
@@ -48,6 +49,9 @@
{{if eq .ID $me.ID}}
<span class="muted small">当前账户</span>
{{else}}
{{if eq $me.ID 1}}
<a class="btn btn-sm" href="/settings/users/{{.ID}}/edit">编辑</a>
{{end}}
<form method="post" action="/settings/users/{{.ID}}/toggle">
<button class="btn btn-sm btn-ghost">{{if .IsActive}}停用{{else}}启用{{end}}</button>
</form>
@@ -0,0 +1,39 @@
{{define "content"}}
<div class="page narrow">
<header class="page-head">
<div>
<h1>编辑管理员</h1>
<p class="muted">修改 {{.D.Target.Username}} 的登录名、昵称,或重置密码。</p>
</div>
<div class="page-actions">
<a class="btn btn-ghost" href="/settings">返回设置</a>
</div>
</header>
<form method="post" action="/settings/users/{{.D.Target.ID}}/edit" class="form card">
<div class="grid-2">
<label class="field"><span>用户名 <i>*</i></span>
<input type="text" name="username" value="{{.D.Target.Username}}" required minlength="3" maxlength="32" autocomplete="off">
</label>
<label class="field"><span>显示名称</span>
<input type="text" name="display_name" value="{{.D.Target.DisplayName}}" maxlength="32" autocomplete="off">
</label>
</div>
<div class="grid-2">
<label class="field"><span>新密码</span>
<input type="password" name="password" minlength="6" autocomplete="new-password" placeholder="留空则不修改">
</label>
<label class="field"><span>再输一次</span>
<input type="password" name="password2" minlength="6" autocomplete="new-password" placeholder="与上面一致">
</label>
</div>
<p class="muted small">重置密码后该账户的登录会话会立即失效,需要用新密码重新登录。当前账户:{{.User.Username}}</p>
<div class="actions">
<button class="btn btn-primary" type="submit">保存修改</button>
<a class="btn btn-ghost" href="/settings">取消</a>
</div>
</form>
</div>
{{end}}