Add player profiles and community settings
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / compose (push) Has been cancelled

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-19 21:43:48 +03:00
parent 5e0825f43f
commit fa4edc0df5
23 changed files with 1280 additions and 57 deletions

View File

@@ -121,6 +121,85 @@ func TestCreateEventCanAnnounceWithoutEveryonePing(t *testing.T) {
}
}
type communitySettingsStore struct {
Store
saved domain.CommunitySettings
audits int
}
func (s *communitySettingsStore) UpdateCommunitySettings(_ context.Context, settings domain.CommunitySettings) (domain.CommunitySettings, error) {
s.saved = settings
return settings, nil
}
func (s *communitySettingsStore) AppendAudit(_ context.Context, _, _, _ string, _ any) error {
s.audits++
return nil
}
func TestUpdateCommunitySettingsRequiresAdminAndAudits(t *testing.T) {
store := &communitySettingsStore{}
service := New(store, &recordingPublisher{}, nil)
now := time.Date(2026, time.July, 19, 12, 0, 0, 0, time.UTC)
service.Now = func() time.Time { return now }
if _, err := service.UpdateCommunitySettings(context.Background(), domain.Account{Role: domain.RoleModerator}, ""); !errors.Is(err, domain.ErrForbidden) {
t.Fatalf("moderator must be forbidden, got %v", err)
}
out, err := service.UpdateCommunitySettings(context.Background(), domain.Account{ID: "admin", Role: domain.RoleAdmin}, " https://discord.gg/mixmaker ")
if err != nil {
t.Fatal(err)
}
if out.DiscordInviteURL != "https://discord.gg/mixmaker" || out.UpdatedBy != "admin" || !out.UpdatedAt.Equal(now) {
t.Fatalf("unexpected settings: %+v", out)
}
if store.audits != 1 {
t.Fatalf("expected one audit entry, got %d", store.audits)
}
}
type playerProfileStore struct {
Store
players []domain.Player
saved domain.Player
err error
}
func (s *playerProfileStore) ListPlayers(context.Context) ([]domain.Player, error) {
return s.players, nil
}
func (s *playerProfileStore) UpdatePlayer(_ context.Context, player domain.Player) (domain.Player, error) {
s.saved = player
return player, s.err
}
func TestUpdateOwnProfileTrimsIdentityAndClearsBattleTag(t *testing.T) {
store := &playerProfileStore{players: []domain.Player{{ID: "player"}}}
service := New(store, &recordingPublisher{}, nil)
name, battleTag := " New Name ", ""
out, err := service.UpdateOwnProfile(context.Background(),
domain.Account{ID: "account"},
domain.Player{ID: "player", AccountID: "account", DisplayName: "Old", BattleTag: "Old#1234"},
UpdateOwnProfileInput{
DisplayName: &name, BattleTag: &battleTag,
Ratings: domain.Ratings{Tank: 1, Damage: 20, Support: 40},
},
)
if err != nil {
t.Fatal(err)
}
if out.DisplayName != "New Name" || out.BattleTag != "" {
t.Fatalf("identity was not normalized and cleared: %+v", out)
}
if _, err = service.UpdateOwnProfile(context.Background(),
domain.Account{ID: "other"}, domain.Player{AccountID: "account"},
UpdateOwnProfileInput{},
); !errors.Is(err, domain.ErrForbidden) {
t.Fatalf("profile updates must remain self-only, got %v", err)
}
}
func validEvent(now time.Time) domain.Event {
return domain.Event{
Name: "Sunday Mix",