Add event management features to API, including event cancellation, deletion, registration closure, and workflow balance generation. Introduce new roster management endpoints and enhance participant handling with avoided player preferences. Update database schema and service logic to support these changes.
This commit is contained in:
@@ -24,8 +24,14 @@ type Store interface {
|
||||
GetEvent(context.Context, string) (domain.Event, error)
|
||||
UpdateEvent(context.Context, domain.Event) (domain.Event, error)
|
||||
ListEvents(context.Context, time.Time) ([]domain.Event, error)
|
||||
SaveEventWorkflow(context.Context, domain.Event, int) (domain.Event, error)
|
||||
SaveRoster(context.Context, domain.RosterDraft, int) (domain.RosterDraft, error)
|
||||
GetRoster(context.Context, string) (domain.RosterDraft, error)
|
||||
StartScrim(context.Context, domain.Event, int, []domain.Series, *domain.Tournament) error
|
||||
DeleteEvent(context.Context, string) error
|
||||
UpsertRSVP(context.Context, domain.RSVP) (domain.RSVP, error)
|
||||
ListRSVPs(context.Context, string) ([]domain.RSVP, error)
|
||||
DeleteRSVP(context.Context, string, string) error
|
||||
SaveTeams(context.Context, string, []domain.Team) error
|
||||
ListTeams(context.Context, string) ([]domain.Team, error)
|
||||
AssignCaptain(context.Context, string, string) (domain.Team, error)
|
||||
@@ -67,7 +73,7 @@ func (s *Service) Authenticate(ctx context.Context, session string) (domain.Acco
|
||||
return s.Store.AccountBySession(ctx, session)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateOwnProfile(ctx context.Context, actor domain.Account, current domain.Player, displayName string, ratings domain.Ratings, preferredRoles []domain.Role, preferredPlayerIDs []string) (domain.Player, error) {
|
||||
func (s *Service) UpdateOwnProfile(ctx context.Context, actor domain.Account, current domain.Player, displayName string, ratings domain.Ratings, preferredRoles []domain.Role, preferredPlayerIDs, avoidedPlayerIDs []string) (domain.Player, error) {
|
||||
if actor.ID != current.AccountID {
|
||||
return domain.Player{}, domain.ErrForbidden
|
||||
}
|
||||
@@ -80,6 +86,7 @@ func (s *Service) UpdateOwnProfile(ctx context.Context, actor domain.Account, cu
|
||||
current.Ratings = ratings
|
||||
current.PreferredRoles = preferredRoles
|
||||
current.PreferredPlayerIDs = preferredPlayerIDs
|
||||
current.AvoidedPlayerIDs = avoidedPlayerIDs
|
||||
current.UpdatedAt = s.Now()
|
||||
if err := current.ValidatePreferences(); err != nil {
|
||||
return domain.Player{}, err
|
||||
@@ -97,7 +104,16 @@ func (s *Service) UpdateOwnProfile(ctx context.Context, actor domain.Account, cu
|
||||
return domain.Player{}, fmt.Errorf("%w: preferred teammate does not exist", domain.ErrInvalid)
|
||||
}
|
||||
}
|
||||
return s.Store.UpdatePlayer(ctx, current)
|
||||
for _, playerID := range current.AvoidedPlayerIDs {
|
||||
if !knownPlayers[playerID] {
|
||||
return domain.Player{}, fmt.Errorf("%w: avoided teammate does not exist", domain.ErrInvalid)
|
||||
}
|
||||
}
|
||||
out, err := s.Store.UpdatePlayer(ctx, current)
|
||||
if err == nil {
|
||||
s.Bus.Publish("players", out)
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (s *Service) CreateEvent(ctx context.Context, actor domain.Account, event domain.Event) (domain.Event, error) {
|
||||
@@ -108,6 +124,10 @@ func (s *Service) CreateEvent(ctx context.Context, actor domain.Account, event d
|
||||
event.RegistrationDeadline = event.StartsAt
|
||||
}
|
||||
event.ID, event.CreatedBy, event.CreatedAt, event.UpdatedAt = NewID(), actor.ID, s.Now(), s.Now()
|
||||
event.State, event.Version = domain.RegistrationOpen, 0
|
||||
if event.RulesetID == "" {
|
||||
event.RulesetID = "standard-control-hybrid-control"
|
||||
}
|
||||
if err := event.Validate(); err != nil {
|
||||
return domain.Event{}, err
|
||||
}
|
||||
@@ -161,6 +181,9 @@ func (s *Service) SetRSVP(ctx context.Context, actor domain.Account, actorPlayer
|
||||
if err != nil {
|
||||
return domain.RSVP{}, err
|
||||
}
|
||||
if event.State != domain.RegistrationOpen {
|
||||
return domain.RSVP{}, fmt.Errorf("%w: registration is closed", domain.ErrConflict)
|
||||
}
|
||||
if !actor.IsAdmin() && s.Now().After(event.RegistrationDeadline) {
|
||||
return domain.RSVP{}, fmt.Errorf("%w: registration deadline has passed", domain.ErrConflict)
|
||||
}
|
||||
@@ -176,6 +199,25 @@ func (s *Service) SetRSVP(ctx context.Context, actor domain.Account, actorPlayer
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (s *Service) RemoveParticipant(ctx context.Context, actor domain.Account, eventID, playerID string) error {
|
||||
if !actor.IsAdmin() {
|
||||
return domain.ErrForbidden
|
||||
}
|
||||
event, err := s.Store.GetEvent(ctx, eventID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if event.State != domain.RegistrationOpen {
|
||||
return fmt.Errorf("%w: registration is closed", domain.ErrConflict)
|
||||
}
|
||||
if err := s.Store.DeleteRSVP(ctx, eventID, playerID); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = s.Store.AppendAudit(ctx, actor.ID, "participant.removed", eventID, map[string]string{"playerId": playerID})
|
||||
s.Bus.Publish("event:"+eventID, map[string]string{"removedPlayerId": playerID})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) CreateParticipant(ctx context.Context, actor domain.Account, eventID, displayName string, ratings domain.Ratings, status domain.RSVPStatus) (domain.Player, domain.RSVP, error) {
|
||||
if !actor.IsAdmin() {
|
||||
return domain.Player{}, domain.RSVP{}, domain.ErrForbidden
|
||||
@@ -187,9 +229,13 @@ func (s *Service) CreateParticipant(ctx context.Context, actor domain.Account, e
|
||||
if err := ratings.Validate(); err != nil {
|
||||
return domain.Player{}, domain.RSVP{}, err
|
||||
}
|
||||
if _, err := s.Store.GetEvent(ctx, eventID); err != nil {
|
||||
event, err := s.Store.GetEvent(ctx, eventID)
|
||||
if err != nil {
|
||||
return domain.Player{}, domain.RSVP{}, err
|
||||
}
|
||||
if event.State != domain.RegistrationOpen {
|
||||
return domain.Player{}, domain.RSVP{}, fmt.Errorf("%w: registration is closed", domain.ErrConflict)
|
||||
}
|
||||
now := s.Now()
|
||||
player := domain.Player{
|
||||
ID: NewID(),
|
||||
@@ -209,10 +255,11 @@ func (s *Service) CreateParticipant(ctx context.Context, actor domain.Account, e
|
||||
if err := rsvp.Validate(); err != nil {
|
||||
return domain.Player{}, domain.RSVP{}, err
|
||||
}
|
||||
player, rsvp, err := s.Store.CreateParticipant(ctx, player, rsvp)
|
||||
player, rsvp, err = s.Store.CreateParticipant(ctx, player, rsvp)
|
||||
if err == nil {
|
||||
_ = s.Store.AppendAudit(ctx, actor.ID, "participant.created", eventID, map[string]any{"player": player, "rsvp": rsvp})
|
||||
s.Bus.Publish("event:"+eventID, rsvp)
|
||||
s.Bus.Publish("players", player)
|
||||
}
|
||||
return player, rsvp, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user