Files
Scoreboard/server/passwd.go
T
AskaEth 005b51b2ec fix: 数据目录移出安装目录,修掉「覆盖安装/卸载即丢数据」
根因:数据目录是 <安装目录>\data(config.yaml 的 dataDir 相对服务端工作目录),
而 electron-builder 的卸载器结尾执行 RMDir /r $INSTDIR,且覆盖安装会先跑旧卸载器
(installSection.nsh:52 的 uninstallOldVersion)→ 赛事库/规则/用户/审计/上传图片
连同安装目录被整个删除,再装新版。卸载一次同样如此。

- 服务端新增 -data <dir>(主命令、backup、passwd 三处),非空时覆盖 config.yaml 的
  dataDir;不传时行为完全不变(兼容便携/手工运行)
- Console 把数据指到当前用户目录 %LOCALAPPDATA%\ScoreboardConsole\data(卸载器不会碰
  这里;没有用 app.getPath('userData'),因为 %APPDATA%\<AppName> 正是被删的那个)
- 一次性迁移:目标为空且 <安装目录>\data 有数据时整体改名过去;两边都有数据时不动作
  只记警告;任何失败都保留原地数据、绝不删除
- passwd 也带 -data(否则重置的是安装目录下那个空库里的账号)
- deploy/backup.bat 指向同一数据目录
- 文档:部署指南新增「数据放在哪里(升级/卸载都不会删)」+ 备份/恢复/迁移路径改写,
  上线检查清单与使用手册同步

自检:服务端 12 包全绿;console 语法 14 文件 + datadir 单测 11/11;backup.bat 保持纯 ASCII。
2026-09-10 09:17:56 +08:00

73 lines
2.1 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"git.yeij.top/AskaEth/Scoreboard/server/internal/auth"
"git.yeij.top/AskaEth/Scoreboard/server/internal/config"
"git.yeij.top/AskaEth/Scoreboard/server/internal/store"
)
// runPasswd 实现 `scoreboard passwd` 子命令:重置用户密码并作废其全部会话。
// 初始密码是首次启动随机生成的,只能用日志找回;忘了就用这个命令重置。
func runPasswd(args []string) error {
fs := flag.NewFlagSet("passwd", flag.ExitOnError)
configPath := fs.String("config", "config.yaml", "配置文件路径")
dataDir := fs.String("data", "", "数据目录;非空时覆盖配置文件里的 dataDir")
username := fs.String("user", "admin", "用户名")
newUsername := fs.String("new-username", "", "同时把用户名改成这个(留空则不改)")
password := fs.String("password", "", "新密码;留空则随机生成并打印")
if err := fs.Parse(args); err != nil {
return err
}
cfg, err := config.Load(*configPath)
if err != nil {
return err
}
// Console 拉起服务端时用 -data 把数据指到安装目录之外;这里必须用同一份,
// 否则改的是安装目录下那个空库里的账号。
cfg.ApplyDataDir(*dataDir)
st, err := store.Open(cfg.DataDir)
if err != nil {
return err
}
defer func() { _ = st.Close() }()
if err := st.Migrate(); err != nil {
return err
}
pwd := *password
generated := pwd == ""
if generated {
pwd, err = auth.RandomPassword(16)
if err != nil {
return err
}
}
svc := auth.New(st.DB(), auth.Options{})
if *newUsername != "" && *newUsername != *username {
if err := svc.SetUsername(context.Background(), *username, *newUsername); err != nil {
return err
}
fmt.Printf("已将用户名 %s 改为 %s\n", *username, *newUsername)
*username = *newUsername
}
if err := svc.SetPassword(context.Background(), *username, pwd, generated); err != nil {
return err
}
if generated {
fmt.Printf("已重置用户 %s 的密码:%s\n请登录后立即修改(已要求下次登录强制改密)。\n", *username, pwd)
} else {
fmt.Printf("已重置用户 %s 的密码。\n", *username)
}
return nil
}