diff --git a/cmd/main.go b/cmd/main.go index 0969e35..6c01ef1 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -190,7 +190,13 @@ func main() { logger, ) + enePulseSvc := enetpulse.New( + *cfg, + store, + ) + go httpserver.SetupReportandVirtualGameCronJobs(context.Background(), reportSvc, veliVirtualGameService, "C:/Users/User/Desktop") + go httpserver.StartEnetPulseCron(enePulseSvc, domain.MongoDBLogger) go httpserver.ProcessBetCashback(context.TODO(), betSvc) bankRepository := repository.NewBankRepository(store) diff --git a/db/migrations/000005_result_checker.up copy.sql b/db/migrations/000005_result_checker.up copy.sql deleted file mode 100644 index 2cbc8fb..0000000 --- a/db/migrations/000005_result_checker.up copy.sql +++ /dev/null @@ -1,15 +0,0 @@ -CREATE TABLE IF NOT EXISTS results ( - id BIGSERIAL PRIMARY KEY, - bet_outcome_id BIGINT NOT NULL, - event_id BIGINT NOT NULL, - odd_id BIGINT NOT NULL, - market_id BIGINT NOT NULL, - status INT NOT NULL, - score VARCHAR(255), - full_time_score VARCHAR(255), - half_time_score VARCHAR(255), - ss VARCHAR(255), - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (bet_outcome_id) REFERENCES bet_outcomes (id) -); diff --git a/db/migrations/000006_enet_pulse.up.sql b/db/migrations/000006_enet_pulse.up.sql deleted file mode 100644 index 059db33..0000000 --- a/db/migrations/000006_enet_pulse.up.sql +++ /dev/null @@ -1,23 +0,0 @@ -CREATE TABLE IF NOT EXISTS enetpulse_sports ( - id BIGSERIAL PRIMARY KEY, - sport_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id" - name VARCHAR(255) NOT NULL, -- from API "name" - updates_count INT DEFAULT 0, -- from API "n" - last_updated_at TIMESTAMPTZ, -- from API "ut" - status INT DEFAULT 1, -- optional status (active/inactive) - created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMPTZ -); - -CREATE TABLE IF NOT EXISTS enetpulse_tournament_templates ( - id BIGSERIAL PRIMARY KEY, - template_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id" - name VARCHAR(255) NOT NULL, -- from API "name" - sport_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_sports(sport_id) ON DELETE CASCADE, - gender VARCHAR(20) DEFAULT 'unknown', -- from API "gender" {male, female, mixed, unknown} - updates_count INT DEFAULT 0, -- from API "n" - last_updated_at TIMESTAMPTZ, -- from API "ut" - status INT DEFAULT 1, -- optional status (active/inactive) - created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMPTZ -); diff --git a/db/migrations/000006_enet_pulse.down.sql b/db/migrations/000011_enet_pulse.down.sql similarity index 100% rename from db/migrations/000006_enet_pulse.down.sql rename to db/migrations/000011_enet_pulse.down.sql diff --git a/db/migrations/000011_enet_pulse.up.sql b/db/migrations/000011_enet_pulse.up.sql new file mode 100644 index 0000000..7b52a4d --- /dev/null +++ b/db/migrations/000011_enet_pulse.up.sql @@ -0,0 +1,64 @@ +CREATE TABLE IF NOT EXISTS enetpulse_sports ( + id BIGSERIAL PRIMARY KEY, + sport_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id" + name VARCHAR(255) NOT NULL, -- from API "name" + updates_count INT DEFAULT 0, -- from API "n" + last_updated_at TIMESTAMPTZ, -- from API "ut" + status INT DEFAULT 1, -- optional status (active/inactive) + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ +); + +CREATE TABLE IF NOT EXISTS enetpulse_tournament_templates ( + id BIGSERIAL PRIMARY KEY, + template_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id" + name VARCHAR(255) NOT NULL, -- from API "name" + sport_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_sports(sport_id) ON DELETE CASCADE, + gender VARCHAR(20) DEFAULT 'unknown', -- from API "gender" {male, female, mixed, unknown} + updates_count INT DEFAULT 0, -- from API "n" + last_updated_at TIMESTAMPTZ, -- from API "ut" + status INT DEFAULT 1, -- optional status (active/inactive) + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ +); + +CREATE TABLE IF NOT EXISTS enetpulse_tournaments ( + id BIGSERIAL PRIMARY KEY, + tournament_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id" + name VARCHAR(255) NOT NULL, -- from API "name" + + -- Link to the template it belongs to: + tournament_template_fk VARCHAR(50) NOT NULL + REFERENCES enetpulse_tournament_templates(template_id) ON DELETE CASCADE, + + updates_count INT DEFAULT 0, -- from API "n" + last_updated_at TIMESTAMPTZ, -- from API "ut" + status INT DEFAULT 1, -- optional active/inactive flag + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ +); + +-- Create table for tournament stages +CREATE TABLE IF NOT EXISTS enetpulse_tournament_stages ( + id BIGSERIAL PRIMARY KEY, + stage_id VARCHAR(50) NOT NULL UNIQUE, -- from API "id" + name VARCHAR(255) NOT NULL, -- from API "name" + tournament_fk VARCHAR(50) NOT NULL REFERENCES enetpulse_tournaments(tournament_id) ON DELETE CASCADE, + -- from API "tournamentFK" + gender VARCHAR(20) DEFAULT 'unknown', -- from API "gender" {male, female, mixed, unknown} + country_fk VARCHAR(50), -- from API "countryFK" + country_name VARCHAR(255), -- from API "country_name" + start_date TIMESTAMPTZ, -- from API "startdate" + end_date TIMESTAMPTZ, -- from API "enddate" + updates_count INT DEFAULT 0, -- from API "n" + last_updated_at TIMESTAMPTZ, -- from API "ut" + status INT DEFAULT 1, -- optional status (active/inactive) + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ +); + +-- Index to quickly query by tournament_fk +CREATE INDEX IF NOT EXISTS idx_enetpulse_tournament_stages_tournament_fk + ON enetpulse_tournament_stages (tournament_fk); + + diff --git a/db/query/enet_pulse.sql b/db/query/enet_pulse.sql index b9fdfa4..dd1d010 100644 --- a/db/query/enet_pulse.sql +++ b/db/query/enet_pulse.sql @@ -9,6 +9,13 @@ INSERT INTO enetpulse_sports ( ) VALUES ( $1, $2, $3, $4, $5, NOW() ) +ON CONFLICT (sport_id) DO UPDATE +SET + name = EXCLUDED.name, + updates_count = EXCLUDED.updates_count, + last_updated_at = EXCLUDED.last_updated_at, + status = EXCLUDED.status, + updated_at = NOW() RETURNING *; -- name: GetAllEnetpulseSports :many @@ -34,12 +41,18 @@ INSERT INTO enetpulse_tournament_templates ( last_updated_at, status, updated_at -) VALUES ( - $1, $2, $3, $4, $5, $6, $7, NOW() -) +) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW()) +ON CONFLICT (template_id) DO UPDATE +SET + name = EXCLUDED.name, + sport_fk = EXCLUDED.sport_fk, + gender = EXCLUDED.gender, + updates_count = EXCLUDED.updates_count, + last_updated_at = EXCLUDED.last_updated_at, + status = EXCLUDED.status, + updated_at = NOW() RETURNING *; - -- name: GetAllEnetpulseTournamentTemplates :many SELECT id, @@ -55,3 +68,67 @@ SELECT FROM enetpulse_tournament_templates ORDER BY name; +-- name: CreateEnetpulseTournament :one +INSERT INTO enetpulse_tournaments ( + tournament_id, + name, + tournament_template_fk, + updates_count, + last_updated_at, + status +) VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (tournament_id) DO UPDATE +SET + name = EXCLUDED.name, + tournament_template_fk = EXCLUDED.tournament_template_fk, + updates_count = EXCLUDED.updates_count, + last_updated_at = EXCLUDED.last_updated_at, + status = EXCLUDED.status +RETURNING *; + +-- name: GetAllEnetpulseTournaments :many +SELECT * +FROM enetpulse_tournaments +ORDER BY created_at DESC; + +-- name: CreateEnetpulseTournamentStage :one +INSERT INTO enetpulse_tournament_stages ( + stage_id, + name, + tournament_fk, + gender, + country_fk, + country_name, + start_date, + end_date, + updates_count, + last_updated_at, + status +) VALUES ( + $1, -- stage_id + $2, -- name + $3, -- tournament_fk + $4, -- gender + $5, -- country_fk + $6, -- country_name + $7, -- start_date + $8, -- end_date + $9, -- updates_count + $10, -- last_updated_at + $11 -- status +) +RETURNING *; + +-- name: GetAllEnetpulseTournamentStages :many +SELECT * +FROM enetpulse_tournament_stages +ORDER BY created_at DESC; + +-- name: GetTournamentStagesByTournamentFK :many +SELECT * +FROM enetpulse_tournament_stages +WHERE tournament_fk = $1 +ORDER BY created_at DESC; + + + diff --git a/gen/db/enet_pulse.sql.go b/gen/db/enet_pulse.sql.go index e935fac..a2c131b 100644 --- a/gen/db/enet_pulse.sql.go +++ b/gen/db/enet_pulse.sql.go @@ -22,6 +22,13 @@ INSERT INTO enetpulse_sports ( ) VALUES ( $1, $2, $3, $4, $5, NOW() ) +ON CONFLICT (sport_id) DO UPDATE +SET + name = EXCLUDED.name, + updates_count = EXCLUDED.updates_count, + last_updated_at = EXCLUDED.last_updated_at, + status = EXCLUDED.status, + updated_at = NOW() RETURNING id, sport_id, name, updates_count, last_updated_at, status, created_at, updated_at ` @@ -55,6 +62,135 @@ func (q *Queries) CreateEnetpulseSport(ctx context.Context, arg CreateEnetpulseS return i, err } +const CreateEnetpulseTournament = `-- name: CreateEnetpulseTournament :one +INSERT INTO enetpulse_tournaments ( + tournament_id, + name, + tournament_template_fk, + updates_count, + last_updated_at, + status +) VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (tournament_id) DO UPDATE +SET + name = EXCLUDED.name, + tournament_template_fk = EXCLUDED.tournament_template_fk, + updates_count = EXCLUDED.updates_count, + last_updated_at = EXCLUDED.last_updated_at, + status = EXCLUDED.status +RETURNING id, tournament_id, name, tournament_template_fk, updates_count, last_updated_at, status, created_at, updated_at +` + +type CreateEnetpulseTournamentParams struct { + TournamentID string `json:"tournament_id"` + Name string `json:"name"` + TournamentTemplateFk string `json:"tournament_template_fk"` + UpdatesCount pgtype.Int4 `json:"updates_count"` + LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"` + Status pgtype.Int4 `json:"status"` +} + +func (q *Queries) CreateEnetpulseTournament(ctx context.Context, arg CreateEnetpulseTournamentParams) (EnetpulseTournament, error) { + row := q.db.QueryRow(ctx, CreateEnetpulseTournament, + arg.TournamentID, + arg.Name, + arg.TournamentTemplateFk, + arg.UpdatesCount, + arg.LastUpdatedAt, + arg.Status, + ) + var i EnetpulseTournament + err := row.Scan( + &i.ID, + &i.TournamentID, + &i.Name, + &i.TournamentTemplateFk, + &i.UpdatesCount, + &i.LastUpdatedAt, + &i.Status, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const CreateEnetpulseTournamentStage = `-- name: CreateEnetpulseTournamentStage :one +INSERT INTO enetpulse_tournament_stages ( + stage_id, + name, + tournament_fk, + gender, + country_fk, + country_name, + start_date, + end_date, + updates_count, + last_updated_at, + status +) VALUES ( + $1, -- stage_id + $2, -- name + $3, -- tournament_fk + $4, -- gender + $5, -- country_fk + $6, -- country_name + $7, -- start_date + $8, -- end_date + $9, -- updates_count + $10, -- last_updated_at + $11 -- status +) +RETURNING id, stage_id, name, tournament_fk, gender, country_fk, country_name, start_date, end_date, updates_count, last_updated_at, status, created_at, updated_at +` + +type CreateEnetpulseTournamentStageParams struct { + StageID string `json:"stage_id"` + Name string `json:"name"` + TournamentFk string `json:"tournament_fk"` + Gender pgtype.Text `json:"gender"` + CountryFk pgtype.Text `json:"country_fk"` + CountryName pgtype.Text `json:"country_name"` + StartDate pgtype.Timestamptz `json:"start_date"` + EndDate pgtype.Timestamptz `json:"end_date"` + UpdatesCount pgtype.Int4 `json:"updates_count"` + LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"` + Status pgtype.Int4 `json:"status"` +} + +func (q *Queries) CreateEnetpulseTournamentStage(ctx context.Context, arg CreateEnetpulseTournamentStageParams) (EnetpulseTournamentStage, error) { + row := q.db.QueryRow(ctx, CreateEnetpulseTournamentStage, + arg.StageID, + arg.Name, + arg.TournamentFk, + arg.Gender, + arg.CountryFk, + arg.CountryName, + arg.StartDate, + arg.EndDate, + arg.UpdatesCount, + arg.LastUpdatedAt, + arg.Status, + ) + var i EnetpulseTournamentStage + err := row.Scan( + &i.ID, + &i.StageID, + &i.Name, + &i.TournamentFk, + &i.Gender, + &i.CountryFk, + &i.CountryName, + &i.StartDate, + &i.EndDate, + &i.UpdatesCount, + &i.LastUpdatedAt, + &i.Status, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + const CreateEnetpulseTournamentTemplate = `-- name: CreateEnetpulseTournamentTemplate :one INSERT INTO enetpulse_tournament_templates ( template_id, @@ -65,9 +201,16 @@ INSERT INTO enetpulse_tournament_templates ( last_updated_at, status, updated_at -) VALUES ( - $1, $2, $3, $4, $5, $6, $7, NOW() -) +) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW()) +ON CONFLICT (template_id) DO UPDATE +SET + name = EXCLUDED.name, + sport_fk = EXCLUDED.sport_fk, + gender = EXCLUDED.gender, + updates_count = EXCLUDED.updates_count, + last_updated_at = EXCLUDED.last_updated_at, + status = EXCLUDED.status, + updated_at = NOW() RETURNING id, template_id, name, sport_fk, gender, updates_count, last_updated_at, status, created_at, updated_at ` @@ -150,6 +293,47 @@ func (q *Queries) GetAllEnetpulseSports(ctx context.Context) ([]EnetpulseSport, return items, nil } +const GetAllEnetpulseTournamentStages = `-- name: GetAllEnetpulseTournamentStages :many +SELECT id, stage_id, name, tournament_fk, gender, country_fk, country_name, start_date, end_date, updates_count, last_updated_at, status, created_at, updated_at +FROM enetpulse_tournament_stages +ORDER BY created_at DESC +` + +func (q *Queries) GetAllEnetpulseTournamentStages(ctx context.Context) ([]EnetpulseTournamentStage, error) { + rows, err := q.db.Query(ctx, GetAllEnetpulseTournamentStages) + if err != nil { + return nil, err + } + defer rows.Close() + var items []EnetpulseTournamentStage + for rows.Next() { + var i EnetpulseTournamentStage + if err := rows.Scan( + &i.ID, + &i.StageID, + &i.Name, + &i.TournamentFk, + &i.Gender, + &i.CountryFk, + &i.CountryName, + &i.StartDate, + &i.EndDate, + &i.UpdatesCount, + &i.LastUpdatedAt, + &i.Status, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const GetAllEnetpulseTournamentTemplates = `-- name: GetAllEnetpulseTournamentTemplates :many SELECT id, @@ -196,3 +380,81 @@ func (q *Queries) GetAllEnetpulseTournamentTemplates(ctx context.Context) ([]Ene } return items, nil } + +const GetAllEnetpulseTournaments = `-- name: GetAllEnetpulseTournaments :many +SELECT id, tournament_id, name, tournament_template_fk, updates_count, last_updated_at, status, created_at, updated_at +FROM enetpulse_tournaments +ORDER BY created_at DESC +` + +func (q *Queries) GetAllEnetpulseTournaments(ctx context.Context) ([]EnetpulseTournament, error) { + rows, err := q.db.Query(ctx, GetAllEnetpulseTournaments) + if err != nil { + return nil, err + } + defer rows.Close() + var items []EnetpulseTournament + for rows.Next() { + var i EnetpulseTournament + if err := rows.Scan( + &i.ID, + &i.TournamentID, + &i.Name, + &i.TournamentTemplateFk, + &i.UpdatesCount, + &i.LastUpdatedAt, + &i.Status, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetTournamentStagesByTournamentFK = `-- name: GetTournamentStagesByTournamentFK :many +SELECT id, stage_id, name, tournament_fk, gender, country_fk, country_name, start_date, end_date, updates_count, last_updated_at, status, created_at, updated_at +FROM enetpulse_tournament_stages +WHERE tournament_fk = $1 +ORDER BY created_at DESC +` + +func (q *Queries) GetTournamentStagesByTournamentFK(ctx context.Context, tournamentFk string) ([]EnetpulseTournamentStage, error) { + rows, err := q.db.Query(ctx, GetTournamentStagesByTournamentFK, tournamentFk) + if err != nil { + return nil, err + } + defer rows.Close() + var items []EnetpulseTournamentStage + for rows.Next() { + var i EnetpulseTournamentStage + if err := rows.Scan( + &i.ID, + &i.StageID, + &i.Name, + &i.TournamentFk, + &i.Gender, + &i.CountryFk, + &i.CountryName, + &i.StartDate, + &i.EndDate, + &i.UpdatesCount, + &i.LastUpdatedAt, + &i.Status, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/gen/db/models.go b/gen/db/models.go index 0319e8f..6fcf27f 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -255,6 +255,35 @@ type EnetpulseSport struct { UpdatedAt pgtype.Timestamptz `json:"updated_at"` } +type EnetpulseTournament struct { + ID int64 `json:"id"` + TournamentID string `json:"tournament_id"` + Name string `json:"name"` + TournamentTemplateFk string `json:"tournament_template_fk"` + UpdatesCount pgtype.Int4 `json:"updates_count"` + LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"` + Status pgtype.Int4 `json:"status"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + +type EnetpulseTournamentStage struct { + ID int64 `json:"id"` + StageID string `json:"stage_id"` + Name string `json:"name"` + TournamentFk string `json:"tournament_fk"` + Gender pgtype.Text `json:"gender"` + CountryFk pgtype.Text `json:"country_fk"` + CountryName pgtype.Text `json:"country_name"` + StartDate pgtype.Timestamptz `json:"start_date"` + EndDate pgtype.Timestamptz `json:"end_date"` + UpdatesCount pgtype.Int4 `json:"updates_count"` + LastUpdatedAt pgtype.Timestamptz `json:"last_updated_at"` + Status pgtype.Int4 `json:"status"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + type EnetpulseTournamentTemplate struct { ID int64 `json:"id"` TemplateID string `json:"template_id"` diff --git a/internal/domain/enet_pulse.go b/internal/domain/enet_pulse.go index bde9e5f..aae67ea 100644 --- a/internal/domain/enet_pulse.go +++ b/internal/domain/enet_pulse.go @@ -409,3 +409,56 @@ type CreateEnetpulseTournamentTemplate struct { LastUpdatedAt time.Time `json:"lastUpdatedAt"` // from API "ut" Status int `json:"status"` // optional, e.g., active/inactive } + +type CreateEnetpulseTournament struct { + TournamentID string // API "id" + Name string // API "name" + TournamentTemplateFK string // API "tournament_templateFK" (links to template_id) + UpdatesCount int // API "n" + LastUpdatedAt time.Time // API "ut" + Status int // optional, default 1 +} + +type EnetpulseTournament struct { + ID int64 // internal DB PK + TournamentID string + Name string + TournamentTemplateFK string + UpdatesCount int + LastUpdatedAt time.Time + Status int + CreatedAt time.Time + UpdatedAt *time.Time +} + +type EnetpulseTournamentStage struct { + ID int64 `json:"id"` + StageID string `json:"stage_id"` // API id + Name string `json:"name"` // API name + TournamentFK string `json:"tournament_fk"` // Foreign key to tournament + Gender string `json:"gender"` // male/female/mixed/unknown + CountryFK string `json:"country_fk"` // country FK from API + StartDate time.Time `json:"start_date"` // start date/time + EndDate time.Time `json:"end_date"` // end date/time + UpdatesCount int `json:"updates_count"` // n from API + LastUpdatedAt time.Time `json:"last_updated_at"` // ut from API + CountryName string `json:"country_name"` // country name from API + Status int `json:"status"` // active/inactive + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// ✅ Struct for creating new tournament stage rows +type CreateEnetpulseTournamentStage struct { + StageID string `json:"stage_id"` // API id + Name string `json:"name"` // API name + TournamentFK string `json:"tournament_fk"` // DB foreign key to tournaments + Gender string `json:"gender"` // male/female/mixed/unknown + CountryFK string `json:"country_fk"` // country FK from API + StartDate time.Time `json:"start_date"` // start date/time + EndDate time.Time `json:"end_date"` // end date/time + UpdatesCount int `json:"updates_count"` // n from API + LastUpdatedAt time.Time `json:"last_updated_at"` // ut from API + CountryName string `json:"country_name"` // country name from API + Status int `json:"status"` // active/inactive +} diff --git a/internal/repository/enet_pulse.go b/internal/repository/enet_pulse.go index 3b484ad..0ea921e 100644 --- a/internal/repository/enet_pulse.go +++ b/internal/repository/enet_pulse.go @@ -3,6 +3,7 @@ package repository import ( "context" "fmt" + "time" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" @@ -63,6 +64,145 @@ func (s *Store) GetAllEnetpulseTournamentTemplates(ctx context.Context) ([]domai return templates, nil } +// Store.go +func (s *Store) CreateEnetpulseTournament( + ctx context.Context, + tournament domain.CreateEnetpulseTournament, +) (domain.EnetpulseTournament, error) { + // Convert domain model to DB model if needed + dbTournament, err := s.queries.CreateEnetpulseTournament( + ctx, + ConvertCreateEnetpulseTournament(tournament), + ) + if err != nil { + return domain.EnetpulseTournament{}, err + } + return ConvertDBEnetpulseTournament(dbTournament), nil +} + +// store.go +func (s *Store) GetAllEnetpulseTournaments(ctx context.Context) ([]domain.EnetpulseTournament, error) { + dbTournaments, err := s.queries.GetAllEnetpulseTournaments(ctx) + if err != nil { + return nil, err + } + + var tournaments []domain.EnetpulseTournament + for _, dbT := range dbTournaments { + tournaments = append(tournaments, ConvertDBEnetpulseTournament(dbT)) + } + + return tournaments, nil +} + +func (s *Store) CreateEnetpulseTournamentStage( + ctx context.Context, + stage domain.CreateEnetpulseTournamentStage, +) (domain.EnetpulseTournamentStage, error) { + // Convert domain model to DB model if needed + dbStage, err := s.queries.CreateEnetpulseTournamentStage( + ctx, + ConvertCreateEnetpulseTournamentStage(stage), + ) + if err != nil { + return domain.EnetpulseTournamentStage{}, err + } + return ConvertDBEnetpulseTournamentStage(dbStage), nil +} + +// Fetch all tournament stages +func (s *Store) GetAllEnetpulseTournamentStages(ctx context.Context) ([]domain.EnetpulseTournamentStage, error) { + dbStages, err := s.queries.GetAllEnetpulseTournamentStages(ctx) + if err != nil { + return nil, err + } + + var stages []domain.EnetpulseTournamentStage + for _, dbStage := range dbStages { + stages = append(stages, ConvertDBEnetpulseTournamentStage(dbStage)) + } + + return stages, nil +} + +// Optional: Fetch stages by TournamentFK +func (s *Store) GetTournamentStagesByTournamentFK(ctx context.Context, tournamentFK string) ([]domain.EnetpulseTournamentStage, error) { + dbStages, err := s.queries.GetTournamentStagesByTournamentFK(ctx, tournamentFK) + if err != nil { + return nil, err + } + + var stages []domain.EnetpulseTournamentStage + for _, dbStage := range dbStages { + stages = append(stages, ConvertDBEnetpulseTournamentStage(dbStage)) + } + + return stages, nil +} + +// func ConvertCreateEnetpulseTournamentStage(stage domain.CreateEnetpulseTournamentStage) dbgen.EnetpulseTournamentStage { +// return dbgen.EnetpulseTournamentStage{ +// StageID: stage.StageID, +// Name: stage.Name, +// TournamentFK: stage.TournamentFK, +// Gender: stage.Gender, +// CountryFK: stage.CountryFK, +// StartDate: stage.StartDate, +// EndDate: stage.EndDate, +// UpdatesCount: int32(stage.UpdatesCount), +// LastUpdatedAt: stage.LastUpdatedAt, +// CountryName: stage.CountryName, +// Status: int32(stage.Status), +// UpdatedAt: time.Now(), +// } +// } + +func ConvertCreateEnetpulseTournamentStage(stage domain.CreateEnetpulseTournamentStage) dbgen.CreateEnetpulseTournamentStageParams { + return dbgen.CreateEnetpulseTournamentStageParams{ + StageID: stage.StageID, + Name: stage.Name, + TournamentFk: stage.TournamentFK, + Gender: pgtype.Text{String: stage.Gender, Valid: stage.Gender != ""}, + CountryFk: pgtype.Text{String: stage.CountryFK, Valid: stage.CountryFK != ""}, + StartDate: pgtype.Timestamptz{Time: stage.StartDate, Valid: !stage.StartDate.IsZero()}, + EndDate: pgtype.Timestamptz{Time: stage.EndDate, Valid: !stage.EndDate.IsZero()}, + UpdatesCount: pgtype.Int4{Int32: int32(stage.UpdatesCount), Valid: true}, + LastUpdatedAt: pgtype.Timestamptz{Time: stage.LastUpdatedAt, Valid: !stage.LastUpdatedAt.IsZero()}, + CountryName: pgtype.Text{String: stage.CountryName, Valid: stage.CountryFK != ""}, + Status: pgtype.Int4{Int32: int32(stage.Status), Valid: true}, + // Las: pgtype.Timestamptz{Time: time.Now(), Valid: true}, + } +} + +func ConvertDBEnetpulseTournamentStage(db dbgen.EnetpulseTournamentStage) domain.EnetpulseTournamentStage { + return domain.EnetpulseTournamentStage{ + ID: db.ID, + StageID: db.StageID, + Name: db.Name, + TournamentFK: db.TournamentFk, + Gender: db.Gender.String, + CountryFK: db.CountryFk.String, + StartDate: db.StartDate.Time, + EndDate: db.EndDate.Time, + UpdatesCount: func() int { + if db.UpdatesCount.Valid { + return int(db.UpdatesCount.Int32) + } + return 0 + }(), + LastUpdatedAt: db.LastUpdatedAt.Time, + CountryName: db.CountryName.String, + Status: func() int { + if db.Status.Valid { + return int(db.Status.Int32) + } + return 0 + }(), + CreatedAt: db.CreatedAt.Time, + UpdatedAt: db.UpdatedAt.Time, + } +} + func ConvertCreateEnetpulseSport(s domain.CreateEnetpulseSport) dbgen.CreateEnetpulseSportParams { return dbgen.CreateEnetpulseSportParams{ SportID: s.SportID, @@ -139,3 +279,45 @@ func ConvertCreateEnetpulseTournamentTemplate( Status: pgtype.Int4{Int32: int32(t.Status), Valid: true}, } } + +// Convert domain to DB insert struct for sqlc +func ConvertCreateEnetpulseTournament(t domain.CreateEnetpulseTournament) dbgen.CreateEnetpulseTournamentParams { + return dbgen.CreateEnetpulseTournamentParams{ + TournamentID: t.TournamentID, + Name: t.Name, + TournamentTemplateFk: t.TournamentTemplateFK, + UpdatesCount: pgtype.Int4{Int32: int32(t.UpdatesCount), Valid: true}, + LastUpdatedAt: pgtype.Timestamptz{Time: t.LastUpdatedAt, Valid: !t.LastUpdatedAt.IsZero()}, + Status: pgtype.Int4{Int32: int32(t.Status), Valid: true}, + } +} + +// Convert DB row to domain model +func ConvertDBEnetpulseTournament(dbT dbgen.EnetpulseTournament) domain.EnetpulseTournament { + return domain.EnetpulseTournament{ + ID: dbT.ID, + TournamentID: dbT.TournamentID, + Name: dbT.Name, + TournamentTemplateFK: dbT.TournamentTemplateFk, + UpdatesCount: func() int { + if dbT.UpdatesCount.Valid { + return int(dbT.UpdatesCount.Int32) + } + return 0 + }(), + LastUpdatedAt: dbT.LastUpdatedAt.Time, + Status: func() int { + if dbT.Status.Valid { + return int(dbT.Status.Int32) + } + return 0 + }(), + CreatedAt: dbT.CreatedAt.Time, + UpdatedAt: func() *time.Time { + if dbT.UpdatedAt.Valid { + return &dbT.UpdatedAt.Time + } + return nil + }(), + } +} diff --git a/internal/services/enet_pulse/service.go b/internal/services/enet_pulse/service.go index 0e6de9c..0aed297 100644 --- a/internal/services/enet_pulse/service.go +++ b/internal/services/enet_pulse/service.go @@ -111,6 +111,19 @@ func (s *Service) FetchAndStoreSports(ctx context.Context) error { return nil } +func (s *Service) GetAllSports(ctx context.Context) ([]domain.EnetpulseSport, error) { + // 1️⃣ Fetch all sports from the store (database) + sports, err := s.store.GetAllEnetpulseSports(ctx) + if err != nil { + return nil, fmt.Errorf("failed to fetch sports from DB: %w", err) + } + + // 2️⃣ Optionally, you can log the count or perform other transformations + // s.logger.Info("Fetched sports from DB", zap.Int("count", len(sports))) + + return sports, nil +} + func (s *Service) FetchAndStoreTournamentTemplates(ctx context.Context) error { // 1️⃣ Fetch all sports from the database sports, err := s.store.GetAllEnetpulseSports(ctx) @@ -118,15 +131,27 @@ func (s *Service) FetchAndStoreTournamentTemplates(ctx context.Context) error { return fmt.Errorf("failed to fetch sports from DB: %w", err) } + // Template struct + type TournamentTemplate struct { + ID string `json:"id"` + Name string `json:"name"` + SportFK string `json:"sportFK"` + Gender string `json:"gender"` + N string `json:"n"` + UT string `json:"ut"` + } + for _, sport := range sports { - // 2️⃣ Compose URL for each sport using its sportID + // 2️⃣ Compose URL for each sport using its Enetpulse sportFK url := fmt.Sprintf( "http://eapi.enetpulse.com/tournament_template/list/?sportFK=%s&username=%s&token=%s", - sport.SportID, + sport.SportID, // must be Enetpulse sportFK s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token, ) + fmt.Println("Fetching tournament templates:", url) + // 3️⃣ Create HTTP request req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { @@ -146,23 +171,33 @@ func (s *Service) FetchAndStoreTournamentTemplates(ctx context.Context) error { sport.SportID, resp.StatusCode, string(body)) } - // 5️⃣ Decode JSON response - var templatesResp struct { - TournamentTemplates map[string]struct { - ID string `json:"id"` - Name string `json:"name"` - SportFK string `json:"sportFK"` - Gender string `json:"gender"` - N string `json:"n"` // updates count - UT string `json:"ut"` // timestamp - } `json:"tournament_templates"` + // 5️⃣ Decode JSON response flexibly + var raw struct { + TournamentTemplates json.RawMessage `json:"tournament_templates"` } - if err := json.NewDecoder(resp.Body).Decode(&templatesResp); err != nil { - return fmt.Errorf("decoding tournament templates for sport %s: %w", sport.SportID, err) + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("reading tournament templates response for sport %s: %w", sport.SportID, err) + } + if err := json.Unmarshal(bodyBytes, &raw); err != nil { + return fmt.Errorf("unmarshalling raw tournament templates for sport %s: %w", sport.SportID, err) } - // 6️⃣ Iterate and store each tournament template - for _, tmpl := range templatesResp.TournamentTemplates { + // 6️⃣ Parse depending on object or array + templates := map[string]TournamentTemplate{} + if len(raw.TournamentTemplates) > 0 && raw.TournamentTemplates[0] == '{' { + // Object (normal case) + if err := json.Unmarshal(raw.TournamentTemplates, &templates); err != nil { + return fmt.Errorf("decoding tournament templates (object) for sport %s: %w", sport.SportID, err) + } + } else { + // Array or empty → skip safely + fmt.Printf("No tournament templates found for sport %s\n", sport.SportID) + continue + } + + // 7️⃣ Iterate and store each tournament template + for _, tmpl := range templates { updatesCount := 0 if tmpl.N != "" { if n, err := strconv.Atoi(tmpl.N); err == nil { @@ -175,29 +210,248 @@ func (s *Service) FetchAndStoreTournamentTemplates(ctx context.Context) error { lastUpdatedAt = time.Time{} } + // Convert sport.SportID from string to int64 + sportFK, err := strconv.ParseInt(sport.SportID, 10, 64) + if err != nil { + fmt.Printf("failed to convert sport.SportID '%s' to int64: %v\n", sport.SportID, err) + continue + } + createTemplate := domain.CreateEnetpulseTournamentTemplate{ TemplateID: tmpl.ID, Name: tmpl.Name, - SportFK: sport.ID, // use DB sport ID + SportFK: sportFK, // use DB sport ID internally Gender: tmpl.Gender, UpdatesCount: updatesCount, LastUpdatedAt: lastUpdatedAt, Status: 1, // default active } - // Insert into DB if _, err := s.store.CreateEnetpulseTournamentTemplate(ctx, createTemplate); err != nil { - // Log error but continue - // s.logger.Error("failed to store tournament template", zap.String("template_id", tmpl.ID), zap.Error(err)) + fmt.Printf("failed to store tournament template %s: %v\n", tmpl.ID, err) continue } } } - // s.logger.Info("Successfully fetched and stored all tournament templates") + fmt.Println("✅ Successfully fetched and stored all tournament templates") return nil } +func (s *Service) GetAllTournamentTemplates(ctx context.Context) ([]domain.EnetpulseTournamentTemplate, error) { + // 1️⃣ Fetch all tournament templates from the store (database) + templates, err := s.store.GetAllEnetpulseTournamentTemplates(ctx) + if err != nil { + return nil, fmt.Errorf("failed to fetch tournament templates from DB: %w", err) + } + + // 2️⃣ Optionally, you can log the count or perform other transformations + // s.logger.Info("Fetched tournament templates from DB", zap.Int("count", len(templates))) + + return templates, nil +} + +func (s *Service) FetchAndStoreTournaments(ctx context.Context) error { + // 1️⃣ Fetch all tournament templates from the database + templates, err := s.store.GetAllEnetpulseTournamentTemplates(ctx) + if err != nil { + return fmt.Errorf("failed to fetch tournament templates from DB: %w", err) + } + + for _, tmpl := range templates { + // 2️⃣ Compose URL for each tournament template + url := fmt.Sprintf( + "http://eapi.enetpulse.com/tournament/list/?tournament_templateFK=%s&username=%s&token=%s", + tmpl.TemplateID, + s.cfg.EnetPulseConfig.UserName, + s.cfg.EnetPulseConfig.Token, + ) + + // 3️⃣ Create HTTP request + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return fmt.Errorf("creating tournament request for template %s: %w", tmpl.TemplateID, err) + } + + // 4️⃣ Execute request + resp, err := s.httpClient.Do(req) + if err != nil { + return fmt.Errorf("requesting tournaments for template %s: %w", tmpl.TemplateID, err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + return fmt.Errorf("failed to fetch tournaments for template %s (status %d): %s", + tmpl.TemplateID, resp.StatusCode, string(body)) + } + + // 5️⃣ Decode JSON response + var tournamentsResp struct { + Tournaments map[string]struct { + ID string `json:"id"` + Name string `json:"name"` + TournamentTemplateFK string `json:"tournament_templateFK"` + N string `json:"n"` // updates count + UT string `json:"ut"` // timestamp + } `json:"tournaments"` + } + if err := json.NewDecoder(resp.Body).Decode(&tournamentsResp); err != nil { + return fmt.Errorf("decoding tournaments for template %s: %w", tmpl.TemplateID, err) + } + + // 6️⃣ Iterate and store each tournament + for _, t := range tournamentsResp.Tournaments { + updatesCount := 0 + if t.N != "" { + if n, err := strconv.Atoi(t.N); err == nil { + updatesCount = n + } + } + + lastUpdatedAt, err := time.Parse(time.RFC3339, t.UT) + if err != nil { + lastUpdatedAt = time.Time{} + } + + createTournament := domain.CreateEnetpulseTournament{ + TournamentID: t.ID, + Name: t.Name, + TournamentTemplateFK: tmpl.TemplateID, // DB ID of template + UpdatesCount: updatesCount, + LastUpdatedAt: lastUpdatedAt, + Status: 1, // default active + } + + // Insert into DB + if _, err := s.store.CreateEnetpulseTournament(ctx, createTournament); err != nil { + // Log error but continue + // s.logger.Error("failed to store tournament", zap.String("tournament_id", t.ID), zap.Error(err)) + continue + } + } + } + + // s.logger.Info("Successfully fetched and stored all tournaments") + return nil +} + +func (s *Service) GetAllTournaments(ctx context.Context) ([]domain.EnetpulseTournament, error) { + // 1️⃣ Fetch all tournaments from the store (database) + tournaments, err := s.store.GetAllEnetpulseTournaments(ctx) + if err != nil { + return nil, fmt.Errorf("failed to fetch tournaments from DB: %w", err) + } + + // 2️⃣ Optionally log count or do transformations + // s.logger.Info("Fetched tournaments from DB", zap.Int("count", len(tournaments))) + + return tournaments, nil +} + +func (s *Service) FetchAndStoreTournamentStages(ctx context.Context) error { + // 1️⃣ Get all tournaments from DB + tournaments, err := s.store.GetAllEnetpulseTournaments(ctx) + if err != nil { + return fmt.Errorf("failed to fetch tournaments from DB: %w", err) + } + + // 2️⃣ Loop through each tournament + for _, t := range tournaments { + // Compose URL for each tournament + url := fmt.Sprintf( + "http://eapi.enetpulse.com/tournament_stage/list/?language_typeFK=3&tz=Europe/Sofia&tournamentFK=%s&username=%s&token=%s", + t.TournamentID, + s.cfg.EnetPulseConfig.UserName, + s.cfg.EnetPulseConfig.Token, + ) + + // 3️⃣ Create HTTP request + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + // log and skip + // s.logger.Error("creating tournament stages request", zap.String("tournament_id", t.TournamentID), zap.Error(err)) + continue + } + + // 4️⃣ Execute request + resp, err := s.httpClient.Do(req) + if err != nil { + // s.logger.Error("requesting tournament stages", zap.String("tournament_id", t.TournamentID), zap.Error(err)) + continue + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + // s.logger.Error("unexpected status code fetching stages", zap.String("tournament_id", t.TournamentID), zap.Int("status", resp.StatusCode)) + _ = body + continue + } + + // 5️⃣ Decode JSON response (based on EnetPulse response format) + var stagesResp struct { + Stages map[string]struct { + ID string `json:"id"` + Name string `json:"name"` + TournamentFK string `json:"tournamentFK"` + N string `json:"n"` // updates count + UT string `json:"ut"` // timestamp + } `json:"tournament_stages"` + } + if err := json.NewDecoder(resp.Body).Decode(&stagesResp); err != nil { + // s.logger.Error("decoding tournament stages", zap.String("tournament_id", t.TournamentID), zap.Error(err)) + continue + } + + // 6️⃣ Iterate and store each stage + for _, st := range stagesResp.Stages { + updatesCount := 0 + if st.N != "" { + if n, err := strconv.Atoi(st.N); err == nil { + updatesCount = n + } + } + + lastUpdatedAt, err := time.Parse(time.RFC3339, st.UT) + if err != nil { + lastUpdatedAt = time.Time{} + } + + createStage := domain.CreateEnetpulseTournamentStage{ + StageID: st.ID, + Name: st.Name, + TournamentFK: t.TournamentID, // DB ID of the tournament + UpdatesCount: updatesCount, + LastUpdatedAt: lastUpdatedAt, + Status: 1, + } + + // Insert into DB + if _, err := s.store.CreateEnetpulseTournamentStage(ctx, createStage); err != nil { + // s.logger.Error("failed to store tournament stage", zap.String("stage_id", st.ID), zap.Error(err)) + continue + } + } + } + + // s.logger.Info("Successfully fetched and stored all tournament stages for all tournaments") + return nil +} + +func (s *Service) GetAllTournamentStages(ctx context.Context) ([]domain.EnetpulseTournamentStage, error) { + // 1️⃣ Fetch all tournament stages from the store (database) + stages, err := s.store.GetAllEnetpulseTournamentStages(ctx) + if err != nil { + return nil, fmt.Errorf("failed to fetch tournament stages from DB: %w", err) + } + + // 2️⃣ Optionally log count or perform transformations + // s.logger.Info("Fetched tournament stages from DB", zap.Int("count", len(stages))) + + return stages, nil +} + func (s *Service) FetchTournamentTemplates(ctx context.Context) (*domain.TournamentTemplatesResponse, error) { url := fmt.Sprintf( "http://eapi.enetpulse.com/tournamenttemplate/list/?username=%s&token=%s", diff --git a/internal/web_server/cron.go b/internal/web_server/cron.go index eadce96..aa6f753 100644 --- a/internal/web_server/cron.go +++ b/internal/web_server/cron.go @@ -252,7 +252,7 @@ func StartEnetPulseCron(enetPulseSvc *enetpulse.Service, mongoLogger *zap.Logger task func() }{ { - spec: "0 * * * * *", // Every minute + spec: "0 0,10,20,30,40,50 * * * *", // Every 10 minutes task: func() { mongoLogger.Info("Began fetching and storing sports cron task") if err := enetPulseSvc.FetchAndStoreSports(context.Background()); err != nil { @@ -271,6 +271,24 @@ func StartEnetPulseCron(enetPulseSvc *enetpulse.Service, mongoLogger *zap.Logger } else { mongoLogger.Info("Completed fetching and storing tournament templates without errors") } + + mongoLogger.Info("Began fetching and storing tournaments cron task") + if err := enetPulseSvc.FetchAndStoreTournaments(context.Background()); err != nil { + mongoLogger.Error("Failed to fetch and store tournaments", + zap.Error(err), + ) + } else { + mongoLogger.Info("Completed fetching and storing tournaments without errors") + } + + mongoLogger.Info("Began fetching and storing tournament stages cron task") + if err := enetPulseSvc.FetchAndStoreTournamentStages(context.Background()); err != nil { + mongoLogger.Error("Failed to fetch and store tournament stages", + zap.Error(err), + ) + } else { + mongoLogger.Info("Completed fetching and storing tournament stages without errors") + } }, }, } @@ -288,6 +306,6 @@ func StartEnetPulseCron(enetPulseSvc *enetpulse.Service, mongoLogger *zap.Logger } c.Start() - log.Println("EnetPulse cron jobs started for fetching and storing sports and tournament templates") - mongoLogger.Info("EnetPulse cron jobs started for fetching and storing sports and tournament templates") + log.Println("EnetPulse cron jobs started for sports, tournament templates, tournaments, and tournament stages") + mongoLogger.Info("EnetPulse cron jobs started for sports, tournament templates, tournaments, and tournament stages") } diff --git a/internal/web_server/handlers/enet_pulse.go b/internal/web_server/handlers/enet_pulse.go index 56b1408..a54606c 100644 --- a/internal/web_server/handlers/enet_pulse.go +++ b/internal/web_server/handlers/enet_pulse.go @@ -66,6 +66,118 @@ func (h *Handler) GetPreMatchOdds(c *fiber.Ctx) error { }) } +// GetAllSports godoc +// @Summary Get all sports +// @Description Fetches all sports stored in the database +// @Tags EnetPulse - Sports +// @Accept json +// @Produce json +// @Success 200 {object} domain.Response{data=[]domain.EnetpulseSport} +// @Failure 502 {object} domain.ErrorResponse +// @Router /api/v1/enetpulse/sports [get] +func (h *Handler) GetAllSports(c *fiber.Ctx) error { + // Call service + sports, err := h.enetPulseSvc.GetAllSports(c.Context()) + if err != nil { + log.Println("GetAllSports error:", err) + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to fetch sports", + Error: err.Error(), + }) + } + + return c.Status(fiber.StatusOK).JSON(domain.Response{ + Message: "Sports fetched successfully", + Data: sports, + StatusCode: fiber.StatusOK, + Success: true, + }) +} + +// GetAllTournamentTemplates godoc +// @Summary Get all tournament templates +// @Description Fetches all tournament templates stored in the database +// @Tags EnetPulse - Tournament Templates +// @Accept json +// @Produce json +// @Success 200 {object} domain.Response{data=[]domain.EnetpulseTournamentTemplate} +// @Failure 502 {object} domain.ErrorResponse +// @Router /api/v1/enetpulse/tournament-templates [get] +func (h *Handler) GetAllTournamentTemplates(c *fiber.Ctx) error { + // Call service + templates, err := h.enetPulseSvc.GetAllTournamentTemplates(c.Context()) + if err != nil { + log.Println("GetAllTournamentTemplates error:", err) + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to fetch tournament templates", + Error: err.Error(), + }) + } + + return c.Status(fiber.StatusOK).JSON(domain.Response{ + Message: "Tournament templates fetched successfully", + Data: templates, + StatusCode: fiber.StatusOK, + Success: true, + }) +} + +// GetAllTournaments godoc +// @Summary Get all tournaments +// @Description Fetches all tournaments stored in the database +// @Tags EnetPulse - Tournaments +// @Accept json +// @Produce json +// @Success 200 {object} domain.Response{data=[]domain.EnetpulseTournament} +// @Failure 502 {object} domain.ErrorResponse +// @Router /api/v1/enetpulse/tournaments [get] +func (h *Handler) GetAllTournaments(c *fiber.Ctx) error { + // Call service + tournaments, err := h.enetPulseSvc.GetAllTournaments(c.Context()) + if err != nil { + log.Println("GetAllTournaments error:", err) + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to fetch tournaments", + Error: err.Error(), + }) + } + + return c.Status(fiber.StatusOK).JSON(domain.Response{ + Message: "Tournaments fetched successfully", + Data: tournaments, + StatusCode: fiber.StatusOK, + Success: true, + }) +} + +// GetAllTournamentStages godoc +// @Summary Get all tournament stages +// @Description Fetches all tournament stages stored in the database +// @Tags EnetPulse - Tournament Stages +// @Accept json +// @Produce json +// @Success 200 {object} domain.Response{data=[]domain.EnetpulseTournamentStage} +// @Failure 502 {object} domain.ErrorResponse +// @Router /api/v1/enetpulse/tournament-stages [get] +func (h *Handler) GetAllTournamentStages(c *fiber.Ctx) error { + // Call service + stages, err := h.enetPulseSvc.GetAllTournamentStages(c.Context()) + if err != nil { + log.Println("GetAllTournamentStages error:", err) + return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{ + Message: "Failed to fetch tournament stages", + Error: err.Error(), + }) + } + + return c.Status(fiber.StatusOK).JSON(domain.Response{ + Message: "Tournament stages fetched successfully", + Data: stages, + StatusCode: fiber.StatusOK, + Success: true, + }) +} + // Helper: parse comma-separated string into []int func parseIntSlice(input string) []int { if input == "" { diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index b5c1ed0..7e04eee 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -271,6 +271,10 @@ func (a *App) initAppRoutes() { //EnetPulse groupV1.Get("/odds/pre-match", h.GetPreMatchOdds) + groupV1.Get("/sports", h.GetAllSports) + groupV1.Get("/tournament_templates", h.GetAllTournamentTemplates) + groupV1.Get("/tournaments", h.GetAllTournamentTemplates) + groupV1.Get("/tournament_stages", h.GetAllTournamentStages) // Leagues tenant.Get("/leagues", h.GetAllLeagues)