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.
98 lines
3.2 KiB
Go
98 lines
3.2 KiB
Go
package discord
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"mixmaker/backend/internal/domain"
|
|
)
|
|
|
|
func TestAnnounceEventCreated(t *testing.T) {
|
|
var received messagePayload
|
|
server := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
|
|
if request.Method != http.MethodPost || request.URL.Path != "/channels/channel-123/messages" {
|
|
t.Errorf("unexpected request: %s %s", request.Method, request.URL.Path)
|
|
}
|
|
if authorization := request.Header.Get("Authorization"); authorization != "Bot secret-token" {
|
|
t.Errorf("unexpected Authorization header: %q", authorization)
|
|
}
|
|
if err := json.NewDecoder(request.Body).Decode(&received); err != nil {
|
|
t.Errorf("decode payload: %v", err)
|
|
}
|
|
response.WriteHeader(http.StatusCreated)
|
|
}))
|
|
defer server.Close()
|
|
|
|
announcer, err := New(Config{
|
|
BotToken: "secret-token",
|
|
ChannelID: "channel-123",
|
|
PublicURL: "https://mix.example.com",
|
|
Locale: "ru",
|
|
APIBaseURL: server.URL,
|
|
HTTPClient: server.Client(),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
start := time.Date(2026, time.July, 20, 18, 0, 0, 0, time.UTC)
|
|
event := domain.Event{
|
|
ID: "event-456",
|
|
Name: "Воскресный микс",
|
|
Description: "Собираемся на Bo3",
|
|
StartsAt: start,
|
|
RegistrationDeadline: start.Add(-2 * time.Hour),
|
|
}
|
|
|
|
if err := announcer.AnnounceEventCreated(context.Background(), event); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if received.Content != "@everyone" {
|
|
t.Fatalf("unexpected content: %q", received.Content)
|
|
}
|
|
if len(received.AllowedMentions.Parse) != 1 || received.AllowedMentions.Parse[0] != "everyone" {
|
|
t.Fatalf("unexpected allowed mentions: %+v", received.AllowedMentions)
|
|
}
|
|
if len(received.Embeds) != 1 {
|
|
t.Fatalf("expected one embed, got %d", len(received.Embeds))
|
|
}
|
|
eventURL := "https://mix.example.com/events/event-456"
|
|
if received.Embeds[0].Title != "Новый микс: Воскресный микс" ||
|
|
received.Embeds[0].Description != event.Description ||
|
|
received.Embeds[0].URL != eventURL ||
|
|
len(received.Embeds[0].Fields) != 2 {
|
|
t.Fatalf("unexpected embed: %+v", received.Embeds[0])
|
|
}
|
|
if len(received.Components) != 1 || len(received.Components[0].Components) != 1 {
|
|
t.Fatalf("unexpected components: %+v", received.Components)
|
|
}
|
|
linkButton := received.Components[0].Components[0]
|
|
if linkButton.Style != 5 || linkButton.Label != "Зарегистрироваться" || linkButton.URL != eventURL {
|
|
t.Fatalf("unexpected registration button: %+v", linkButton)
|
|
}
|
|
}
|
|
|
|
func TestAnnounceEventCreatedReturnsDiscordError(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, _ *http.Request) {
|
|
http.Error(response, `{"message":"Missing Permissions"}`, http.StatusForbidden)
|
|
}))
|
|
defer server.Close()
|
|
announcer, err := New(Config{
|
|
BotToken: "secret-token",
|
|
ChannelID: "channel-123",
|
|
PublicURL: "https://mix.example.com",
|
|
APIBaseURL: server.URL,
|
|
HTTPClient: server.Client(),
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := announcer.AnnounceEventCreated(context.Background(), domain.Event{ID: "event-456"}); err == nil {
|
|
t.Fatal("expected Discord error")
|
|
}
|
|
}
|