feat(supervisor): add invite, bind, and read-only overview

This commit is contained in:
nepiedg
2026-04-16 11:42:53 +08:00
parent a32ec911a1
commit 0eaf3a206a
7 changed files with 496 additions and 0 deletions
@@ -0,0 +1,104 @@
package service
import (
"context"
"testing"
"time"
usermodel "wx_service/internal/model"
quitmodel "wx_service/internal/quitcheckin/model"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func setupSupervisorTestDB(t *testing.T) *gorm.DB {
t.Helper()
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
t.Fatalf("open sqlite: %v", err)
}
if err := db.AutoMigrate(
&usermodel.User{},
&quitmodel.Profile{},
&quitmodel.DailyStatus{},
&quitmodel.RelapseEvent{},
&quitmodel.HPChangeLog{},
&quitmodel.SupervisorInvite{},
&quitmodel.SupervisorBinding{},
&quitmodel.RewardGoal{},
&quitmodel.DreamPreset{},
); err != nil {
t.Fatalf("auto migrate: %v", err)
}
return db
}
func TestSupervisorInviteBindAndOverview(t *testing.T) {
t.Parallel()
db := setupSupervisorTestDB(t)
svc := NewService(db)
ctx := context.Background()
ownerUID := 3001
supervisorUID := 3002
now := time.Date(2026, 4, 16, 10, 0, 0, 0, time.Local)
// seed users
if err := db.Create(&usermodel.User{ID: uint(ownerUID), NickName: "owner"}).Error; err != nil {
t.Fatalf("seed owner user: %v", err)
}
if err := db.Create(&usermodel.User{ID: uint(supervisorUID), NickName: "supervisor"}).Error; err != nil {
t.Fatalf("seed supervisor user: %v", err)
}
startDate := time.Date(2026, 4, 10, 0, 0, 0, 0, time.Local)
if _, err := svc.UpsertProfile(ctx, ownerUID, UpsertProfileRequest{
QuitStartDate: &startDate,
PackPriceCent: intPtr(2500),
BaselineCigsPerDay: intPtr(10),
}, "owner", "", now); err != nil {
t.Fatalf("upsert profile: %v", err)
}
invite, err := svc.CreateSupervisorInvite(ctx, ownerUID, now, 7)
if err != nil {
t.Fatalf("create invite: %v", err)
}
if invite.Token == "" {
t.Fatalf("invite token empty")
}
if err := svc.BindSupervisorInvite(ctx, supervisorUID, invite.Token, now); err != nil {
t.Fatalf("bind: %v", err)
}
overview, err := svc.GetSupervisorOverview(ctx, supervisorUID, now)
if err != nil {
t.Fatalf("overview: %v", err)
}
if len(overview.Items) != 1 {
t.Fatalf("overview items=%d, want=1", len(overview.Items))
}
if overview.Items[0].Owner.UserID != ownerUID {
t.Fatalf("owner uid=%d, want=%d", overview.Items[0].Owner.UserID, ownerUID)
}
if overview.Items[0].Home.Summary.HPCurrent <= 0 {
t.Fatalf("hp_current=%d, want > 0", overview.Items[0].Home.Summary.HPCurrent)
}
status, err := svc.GetSupervisorStatus(ctx, ownerUID)
if err != nil {
t.Fatalf("status: %v", err)
}
if len(status.Items) != 1 || status.Items[0].UserID != supervisorUID {
t.Fatalf("status=%v, want one supervisor uid=%d", status.Items, supervisorUID)
}
}