Files
ttstd-infinite-canvas/backend/internal/auth/registration_agreement_test.go
✨await 672bb0be73 feat(auth): 注册服务协议 - 名称与条款改为后台可配置并同步注册页展示
后端:
- RegistrationSettingRequest 协议字段改为可选指针,注册开关单独保存不再覆盖协议正文
- 新增 RegistrationAgreement / AgreementTitleForMessage:标题未配置时跟随品牌名生成,读取失败返回空标题而非猜一个不存在的协议名
- PublicAuthSettings 下发 agreementTitle / agreementContent,首用户分支同样携带
- 新增 registration_agreement_test.go 覆盖品牌名兜底、存储合并与失败降级

前端:
- 注册页协议标题与条款改为消费后台配置;读取失败时隐藏协议入口并支持重新读取
- 验证码获取按钮内联到输入框右侧,联系方式为空即禁用;sms_email 双通道合并为单输入框
- 协议弹窗重排:条目标题独立成行加重、空态虚线提示、底部补充同意说明;深浅主题适配
- 协议勾选行改为状态化区域,复选框适配 AntD 6 结构(方框在 .ant-checkbox 本体,修正深色主题白底白勾)
- 后台「服务协议名称与条款」区块补齐表单内边距并对齐区块头/页脚,协议名称限宽

文档:http-api.mdx 更新协议字段语义与失败降级说明;pending-test.mdx 增加手工验证清单
2026-09-24 16:56:44 +08:00

141 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package auth
import (
"testing"
"infinite-canvas/backend/internal/kernel"
"infinite-canvas/backend/internal/model"
"infinite-canvas/backend/internal/repository"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func TestRegistrationAgreementFollowsBrandNameWhenUnset(t *testing.T) {
svc := New(repository.New(newAgreementTestDB(t)), brandHost{name: "星野"}, nil)
title, content := svc.RegistrationAgreement()
if title != "星野服务协议" {
t.Fatalf("default agreement title = %q", title)
}
if content != "" {
t.Fatalf("default agreement content = %q", content)
}
settings, err := svc.PublicAuthSettings()
if err != nil {
t.Fatal(err)
}
if settings.AgreementTitle != "星野服务协议" || settings.AgreementContent != "" {
t.Fatalf("public settings agreement = %q / %q", settings.AgreementTitle, settings.AgreementContent)
}
}
func TestUpdateRegistrationSettingStoresAgreement(t *testing.T) {
db := newAgreementTestDB(t)
svc := New(repository.New(db), brandHost{name: "星野"}, nil)
if err := db.Create(&model.User{ID: "admin", Username: "admin", Role: model.UserRoleAdmin, Status: model.UserStatusActive}).Error; err != nil {
t.Fatal(err)
}
admin := &model.User{ID: "admin", Username: "admin", Role: model.UserRoleAdmin, Status: model.UserStatusActive}
saved, err := svc.UpdateRegistrationSetting(admin, RegistrationSettingRequest{
Enabled: true,
AgreementTitle: strPtr("《星野平台服务条款》"),
AgreementContent: strPtr("第一条 服务说明\n\n第二条 内容合规"),
})
if err != nil {
t.Fatal(err)
}
if !saved.Enabled || saved.AgreementTitle != "《星野平台服务条款》" {
t.Fatalf("saved setting = %#v", saved)
}
reloaded, err := svc.AdminRegistrationSetting(admin)
if err != nil {
t.Fatal(err)
}
if reloaded.AgreementContent != "第一条 服务说明\n\n第二条 内容合规" {
t.Fatalf("reloaded content = %q", reloaded.AgreementContent)
}
// 展示用标题去掉书名号,避免注册页出现双书名号。
title, content := svc.RegistrationAgreement()
if title != "星野平台服务条款" || content != "第一条 服务说明\n\n第二条 内容合规" {
t.Fatalf("agreement = %q / %q", title, content)
}
settings, err := svc.PublicAuthSettings()
if err != nil {
t.Fatal(err)
}
if settings.AgreementTitle != "星野平台服务条款" || settings.AgreementContent != "第一条 服务说明\n\n第二条 内容合规" {
t.Fatalf("public settings agreement = %q / %q", settings.AgreementTitle, settings.AgreementContent)
}
}
func TestRegistrationToggleKeepsSavedAgreement(t *testing.T) {
db := newAgreementTestDB(t)
svc := New(repository.New(db), brandHost{name: "星野"}, nil)
admin := &model.User{ID: "admin", Username: "admin", Role: model.UserRoleAdmin, Status: model.UserStatusActive}
if _, err := svc.UpdateRegistrationSetting(admin, RegistrationSettingRequest{Enabled: true, AgreementContent: strPtr("条款正文")}); err != nil {
t.Fatal(err)
}
enabled, err := svc.RegistrationEnabled()
if err != nil || !enabled {
t.Fatalf("RegistrationEnabled() = %v, %v", enabled, err)
}
// 管理面板切换注册开关时只提交 enabled,已保存的协议正文不能被清空。
switched, err := svc.UpdateRegistrationSetting(admin, RegistrationSettingRequest{Enabled: false})
if err != nil {
t.Fatal(err)
}
if switched.Enabled || switched.AgreementContent != "条款正文" {
t.Fatalf("toggle wiped agreement: %#v", switched)
}
cleared, err := svc.UpdateRegistrationSetting(admin, RegistrationSettingRequest{Enabled: true, AgreementContent: strPtr("")})
if err != nil {
t.Fatal(err)
}
if cleared.AgreementContent != "" {
t.Fatalf("explicit clear ignored: %#v", cleared)
}
}
func strPtr(value string) *string { return &value }
// 配置损坏时不能再返回品牌名兜底标题:注册页会据此展示,与后台真实配置不符。
func TestRegistrationAgreementDegradesWhenSettingUnreadable(t *testing.T) {
db := newAgreementTestDB(t)
svc := New(repository.New(db), brandHost{name: "星野"}, nil)
if err := db.Create(&model.SystemSetting{Key: registrationSettingKey, ValueJSON: "{not-json"}).Error; err != nil {
t.Fatal(err)
}
title, content := svc.RegistrationAgreement()
if title != "" || content != "" {
t.Fatalf("broken setting should degrade to empty, got %q / %q", title, content)
}
// 错误提示仍需给出可读文案,但不能是凭空拼出来的协议名。
if message := svc.AgreementTitleForMessage(); message != "服务协议" {
t.Fatalf("fallback message title = %q", message)
}
}
func newAgreementTestDB(t *testing.T) *gorm.DB {
t.Helper()
db, err := gorm.Open(sqlite.Open("file:"+kernel.NewID()+"?mode=memory&cache=shared"), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
if err := db.AutoMigrate(&model.User{}, &model.SystemSetting{}); err != nil {
t.Fatal(err)
}
return db
}