Add Discord event announcement functionality to backend
This commit introduces a new Discord event announcer to the backend, allowing for event announcements via Discord. It includes the addition of new environment variables for Discord configuration in `.env.example` and `compose.yaml`. The `main.go` file has been updated to initialize the announcer, and a new `discord` package has been created, containing the announcer logic and tests. Additionally, the service layer has been modified to support bracket draft management, enhancing the overall event workflow. Integration tests have been updated to ensure proper functionality of the new features.
This commit is contained in:
@@ -47,6 +47,13 @@ func TestMigrationsAndReadiness(t *testing.T) {
|
||||
if !rosterTable {
|
||||
t.Fatal("event_rosters table is missing")
|
||||
}
|
||||
var bracketTable bool
|
||||
if err := store.pool.QueryRow(ctx, `SELECT to_regclass('public.event_bracket_drafts') IS NOT NULL`).Scan(&bracketTable); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bracketTable {
|
||||
t.Fatal("event_bracket_drafts table is missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFullScrimPipeline(t *testing.T) {
|
||||
@@ -84,7 +91,7 @@ func TestFullScrimPipeline(t *testing.T) {
|
||||
_, _ = store.pool.Exec(ctx, `DELETE FROM accounts WHERE id=$1`, accountID)
|
||||
}()
|
||||
|
||||
service := application.New(store, discardPublisher{})
|
||||
service := application.New(store, discardPublisher{}, nil)
|
||||
admin := domain.Account{ID: accountID, Role: domain.RoleAdmin}
|
||||
now := time.Now().UTC()
|
||||
event, err := service.CreateEvent(ctx, admin, domain.Event{
|
||||
@@ -130,6 +137,18 @@ func TestFullScrimPipeline(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
draft, err := service.InitializeBracket(ctx, admin, eventID, event.Version)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
draft, err = service.ConfirmBracket(ctx, admin, eventID, draft.Version)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
event, err = store.GetEvent(ctx, eventID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
started, err := service.StartScrim(ctx, admin, eventID, event.Version)
|
||||
if err != nil || started.Series == nil {
|
||||
t.Fatalf("start failed: %#v, %v", started, err)
|
||||
@@ -200,7 +219,7 @@ func TestParallelTournamentHydratesLiveSeriesAndFinal(t *testing.T) {
|
||||
_, _ = store.pool.Exec(ctx, `DELETE FROM events WHERE id=$1`, eventID)
|
||||
_, _ = store.pool.Exec(ctx, `DELETE FROM accounts WHERE id=$1`, accountID)
|
||||
}()
|
||||
service := application.New(store, discardPublisher{})
|
||||
service := application.New(store, discardPublisher{}, nil)
|
||||
event, err := service.CreateEvent(ctx, domain.Account{ID: accountID, Role: domain.RoleAdmin}, domain.Event{
|
||||
ID: eventID, Name: "Parallel tournament", StartsAt: time.Now().Add(time.Hour), EndsAt: time.Now().Add(3 * time.Hour),
|
||||
RegistrationDeadline: time.Now(), RulesetID: "standard-control-hybrid-control",
|
||||
@@ -213,15 +232,15 @@ func TestParallelTournamentHydratesLiveSeriesAndFinal(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tournament, err := domain.NewTournament(tournamentID, eventID, event.Name, []string{"team-a", "team-b", "team-c", "team-d"})
|
||||
draft, err := domain.NewBracketDraft(eventID, []string{"team-a", "team-b", "team-c", "team-d"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = store.SaveTournament(ctx, *tournament); err != nil {
|
||||
tournament, err := domain.NewGraphTournament(tournamentID, eventID, event.Name, *draft)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for match := range tournament.Rounds[0] {
|
||||
slot := tournament.Rounds[0][match]
|
||||
for match, slot := range tournament.ReadyMatches() {
|
||||
series, createErr := domain.NewSeries(slot.ID, eventID, tournamentID, [2]string{slot.TeamAID, slot.TeamBID}, rules)
|
||||
if createErr != nil {
|
||||
t.Fatal(createErr)
|
||||
@@ -234,6 +253,16 @@ func TestParallelTournamentHydratesLiveSeriesAndFinal(t *testing.T) {
|
||||
if _, createErr = store.SaveSeries(ctx, *series); createErr != nil {
|
||||
t.Fatal(createErr)
|
||||
}
|
||||
for index := range tournament.Matches {
|
||||
if tournament.Matches[index].ID == slot.ID {
|
||||
tournament.Matches[index].SeriesID = series.ID
|
||||
tournament.Matches[index].Series = series
|
||||
}
|
||||
}
|
||||
}
|
||||
tournament.BuildRounds()
|
||||
if _, err = store.SaveTournament(ctx, *tournament); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hydrated, err := store.GetTournamentByEvent(ctx, eventID)
|
||||
if err != nil {
|
||||
@@ -242,17 +271,23 @@ func TestParallelTournamentHydratesLiveSeriesAndFinal(t *testing.T) {
|
||||
if hydrated.Rounds[0][0].Phase != domain.MapBanPhase || hydrated.Rounds[0][1].Phase != domain.CoinTossPending {
|
||||
t.Fatalf("parallel series were not hydrated independently: %s / %s", hydrated.Rounds[0][0].Phase, hydrated.Rounds[0][1].Phase)
|
||||
}
|
||||
for match := range hydrated.Rounds[0] {
|
||||
hydrated.Rounds[0][match].WinnerTeamID = hydrated.Rounds[0][match].TeamAID
|
||||
hydrated.Rounds[0][match].Phase = domain.SeriesComplete
|
||||
if err = hydrated.Advance(0, match); err != nil {
|
||||
for index := range hydrated.Matches {
|
||||
if hydrated.Matches[index].Round != 0 || hydrated.Matches[index].Series == nil {
|
||||
continue
|
||||
}
|
||||
completed := *hydrated.Matches[index].Series
|
||||
completed.WinnerTeamID, completed.Phase, completed.Version = completed.TeamAID, domain.SeriesComplete, completed.Version+1
|
||||
if _, err = store.SaveSeries(ctx, completed); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = hydrated.ApplySeries(completed); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = store.SaveTournament(ctx, hydrated); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if _, err = store.SaveTournament(ctx, hydrated); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
finalSlot := hydrated.Rounds[1][0]
|
||||
finalSlot := hydrated.ReadyMatches()[0]
|
||||
final, err := domain.NewSeries(finalSlot.ID, eventID, tournamentID, [2]string{finalSlot.TeamAID, finalSlot.TeamBID}, rules)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -261,8 +296,8 @@ func TestParallelTournamentHydratesLiveSeriesAndFinal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hydrated, err = store.GetTournamentByEvent(ctx, eventID)
|
||||
if err != nil || hydrated.Rounds[1][0].Phase != domain.CoinTossPending {
|
||||
t.Fatalf("final was not persisted and hydrated: phase=%s err=%v", hydrated.Rounds[1][0].Phase, err)
|
||||
if err != nil || hydrated.Matches[len(hydrated.Matches)-1].Series == nil || hydrated.Matches[len(hydrated.Matches)-1].Series.Phase != domain.CoinTossPending {
|
||||
t.Fatalf("final was not persisted and hydrated: err=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user