diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index a30f872..c2e98cb 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -75,8 +75,6 @@ CREATE TABLE IF NOT EXISTS wallets ( updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(user_id, type) ); - - CREATE TABLE refresh_tokens ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, @@ -342,7 +340,7 @@ CREATE TABLE company_event_settings ( event_id BIGINT NOT NULL, is_active BOOLEAN, is_featured BOOLEAN, - winning_upper_limit INT, + winning_upper_limit BIGINT, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE (company_id, event_id) ); diff --git a/db/query/bet.sql b/db/query/bet.sql index 811dd1f..c0682a4 100644 --- a/db/query/bet.sql +++ b/db/query/bet.sql @@ -133,6 +133,38 @@ SELECT * FROM bet_with_outcomes WHERE status = 2 AND processed = false; +-- name: GetBetOutcomeViewByEventID :many +SELECT bet_outcomes.*, + users.first_name, + users.last_name, + bets.amount, + bets.total_odds +FROM bet_outcomes + JOIN bets ON bets.id = bet_outcomes.bet_id + JOIN users ON bets.user_id = users.id +WHERE bet_outcomes.event_id = $1 + AND ( + bets.company_id = sqlc.narg('company_id') + OR sqlc.narg('company_id') IS NULL + ) + AND ( + bet_outcomes.status = sqlc.narg('filter_status') + OR sqlc.narg('filter_status') IS NULL + ) +LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); +-- name: TotalBetOutcomeViewByEventID :one +SELECT count(*) +FROM bet_outcomes + JOIN bets ON bets.id = bet_outcomes.bet_id +WHERE bet_outcomes.event_id = $1 + AND ( + bets.company_id = sqlc.narg('company_id') + OR sqlc.narg('company_id') IS NULL + ) + AND ( + bet_outcomes.status = sqlc.narg('filter_status') + OR sqlc.narg('filter_status') IS NULL + ); -- name: GetBetOutcomeByEventID :many SELECT * FROM bet_outcomes @@ -180,6 +212,11 @@ UPDATE bet_outcomes SEt status = $1 WHERE event_id = $2 RETURNING *; +-- name: UpdateBetOutcomeStatusForOddID :many +UPDATE bet_outcomes +SEt status = $1 +WHERE odd_id = $2 +RETURNING *; -- name: UpdateStatus :exec UPDATE bets SET status = $1, diff --git a/db/query/company.sql b/db/query/company.sql index 00128f5..516775f 100644 --- a/db/query/company.sql +++ b/db/query/company.sql @@ -30,8 +30,8 @@ WHERE ( SELECT * FROM companies_details WHERE id = $1; --- name: GetCompanyIDUsingSlug :one -SELECT id +-- name: GetCompanyUsingSlug :one +SELECT * FROM companies WHERE slug = $1; -- name: SearchCompanyByName :many diff --git a/db/query/events.sql b/db/query/events.sql index ff7b03f..84b10b8 100644 --- a/db/query/events.sql +++ b/db/query/events.sql @@ -56,7 +56,7 @@ SET sport_id = EXCLUDED.sport_id, source = EXCLUDED.source, default_winning_upper_limit = EXCLUDED.default_winning_upper_limit, fetched_at = now(); --- name: SaveEventSettings :exec +-- name: SaveTenantEventSettings :exec INSERT INTO company_event_settings ( company_id, event_id, @@ -300,7 +300,9 @@ FROM events e WHERE e.id = $1 LIMIT 1; -- name: GetSportAndLeagueIDs :one -SELECT sport_id, league_id FROM events +SELECT sport_id, + league_id +FROM events WHERE id = $1; -- name: UpdateMatchResult :exec UPDATE events @@ -313,8 +315,22 @@ FROM events WHERE id = $1; -- name: UpdateEventMonitored :exec UPDATE events -SET is_monitored = $1 +SET is_monitored = $1, + updated_at = CURRENT_TIMESTAMP WHERE id = $2; +-- name: UpdateGlobalEventSettings :exec +UPDATE events +SET default_is_active = COALESCE(sqlc.narg(default_is_active), default_is_active), + default_is_featured = COALESCE( + sqlc.narg(default_is_featured), + default_is_featured + ), + default_winning_upper_limit = COALESCE( + sqlc.narg(default_winning_upper_limit), + default_winning_upper_limit + ), + updated_at = CURRENT_TIMESTAMP +WHERE id = $1; -- name: DeleteEvent :exec DELETE FROM events -WHERE id = $1; +WHERE id = $1; \ No newline at end of file diff --git a/db/query/leagues.sql b/db/query/leagues.sql index 476c3e8..b45460f 100644 --- a/db/query/leagues.sql +++ b/db/query/leagues.sql @@ -14,7 +14,7 @@ SET name = EXCLUDED.name, country_code = EXCLUDED.country_code, bet365_id = EXCLUDED.bet365_id, sport_id = EXCLUDED.sport_id; --- name: InsertLeagueSettings :exec +-- name: SaveLeagueSettings :exec INSERT INTO company_league_settings ( company_id, league_id, @@ -118,7 +118,7 @@ SET name = COALESCE(sqlc.narg('name'), name), bet365_id = COALESCE(sqlc.narg('bet365_id'), bet365_id), sport_id = COALESCE(sqlc.narg('sport_id'), sport_id) WHERE id = $1; --- name: UpdateLeagueSettings :exec +-- name: UpdateCompanyLeagueSettings :exec UPDATE company_league_settings SET is_active = COALESCE(sqlc.narg('is_active'), is_active), is_featured = COALESCE( @@ -126,4 +126,9 @@ SET is_active = COALESCE(sqlc.narg('is_active'), is_active), is_featured ) WHERE league_id = $1 - AND company_id = $2; \ No newline at end of file + AND company_id = $2; +-- name: UpdateGlobalLeagueSettings :exec +UPDATE leagues +SET default_is_active = COALESCE(sqlc.narg('is_active'), default_is_active), + default_is_featured = COALESCE(sqlc.narg('is_featured'), default_is_featured) +WHERE id = $1; \ No newline at end of file diff --git a/db/query/odds.sql b/db/query/odds.sql index dc467c6..8950868 100644 --- a/db/query/odds.sql +++ b/db/query/odds.sql @@ -143,4 +143,15 @@ WHERE event_id = $1 LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); -- name: DeleteOddsForEvent :exec DELETE FROM odds_market -Where event_id = $1; \ No newline at end of file +Where event_id = $1; +-- name: DeleteAllCompanyOddsSetting :exec +DELETE FROM company_odd_settings +WHERE company_id = $1; +-- name: DeleteCompanyOddsSettingByOddMarketID :exec +DELETE FROM company_odd_settings +WHERE company_id = $1 + AND odds_market_id = $2; +-- name: UpdateGlobalOddsSetting :exec +UPDATE odds_market +SET default_is_active = COALESCE(sqlc.narg(default_is_active), default_is_active) +WHERE id = $1; \ No newline at end of file diff --git a/db/scripts/003_fix_autoincrement_desync.sql b/db/scripts/003_fix_autoincrement_desync.sql new file mode 100644 index 0000000..835e10e --- /dev/null +++ b/db/scripts/003_fix_autoincrement_desync.sql @@ -0,0 +1,31 @@ +-- For each table with an id sequence +SELECT setval( + pg_get_serial_sequence('users', 'id'), + COALESCE(MAX(id), 1) + ) +FROM users; +SELECT setval( + pg_get_serial_sequence('wallets', 'id'), + COALESCE(MAX(id), 1) + ) +FROM wallets; +SELECT setval( + pg_get_serial_sequence('customer_wallets', 'id'), + COALESCE(MAX(id), 1) + ) +FROM customer_wallets; +SELECT setval( + pg_get_serial_sequence('companies', 'id'), + COALESCE(MAX(id), 1) + ) +FROM companies; +SELECT setval( + pg_get_serial_sequence('branches', 'id'), + COALESCE(MAX(id), 1) + ) +FROM branches; +SELECT setval( + pg_get_serial_sequence('supported_operations', 'id'), + COALESCE(MAX(id), 1) + ) +FROM supported_operations; \ No newline at end of file diff --git a/gen/db/bet.sql.go b/gen/db/bet.sql.go index 9813c89..8e6254c 100644 --- a/gen/db/bet.sql.go +++ b/gen/db/bet.sql.go @@ -448,6 +448,103 @@ func (q *Queries) GetBetOutcomeCountByOddID(ctx context.Context, oddID int64) (i return count, err } +const GetBetOutcomeViewByEventID = `-- name: GetBetOutcomeViewByEventID :many +SELECT bet_outcomes.id, bet_outcomes.bet_id, bet_outcomes.sport_id, bet_outcomes.event_id, bet_outcomes.odd_id, bet_outcomes.home_team_name, bet_outcomes.away_team_name, bet_outcomes.market_id, bet_outcomes.market_name, bet_outcomes.odd, bet_outcomes.odd_name, bet_outcomes.odd_header, bet_outcomes.odd_handicap, bet_outcomes.status, bet_outcomes.expires, + users.first_name, + users.last_name, + bets.amount, + bets.total_odds +FROM bet_outcomes + JOIN bets ON bets.id = bet_outcomes.bet_id + JOIN users ON bets.user_id = users.id +WHERE bet_outcomes.event_id = $1 + AND ( + bets.company_id = $2 + OR $2 IS NULL + ) + AND ( + bet_outcomes.status = $3 + OR $3 IS NULL + ) +LIMIT $5 OFFSET $4 +` + +type GetBetOutcomeViewByEventIDParams struct { + EventID int64 `json:"event_id"` + CompanyID pgtype.Int8 `json:"company_id"` + FilterStatus pgtype.Int4 `json:"filter_status"` + Offset pgtype.Int4 `json:"offset"` + Limit pgtype.Int4 `json:"limit"` +} + +type GetBetOutcomeViewByEventIDRow struct { + ID int64 `json:"id"` + BetID int64 `json:"bet_id"` + SportID int64 `json:"sport_id"` + EventID int64 `json:"event_id"` + OddID int64 `json:"odd_id"` + HomeTeamName string `json:"home_team_name"` + AwayTeamName string `json:"away_team_name"` + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + Odd float32 `json:"odd"` + OddName string `json:"odd_name"` + OddHeader string `json:"odd_header"` + OddHandicap string `json:"odd_handicap"` + Status int32 `json:"status"` + Expires pgtype.Timestamp `json:"expires"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Amount int64 `json:"amount"` + TotalOdds float32 `json:"total_odds"` +} + +func (q *Queries) GetBetOutcomeViewByEventID(ctx context.Context, arg GetBetOutcomeViewByEventIDParams) ([]GetBetOutcomeViewByEventIDRow, error) { + rows, err := q.db.Query(ctx, GetBetOutcomeViewByEventID, + arg.EventID, + arg.CompanyID, + arg.FilterStatus, + arg.Offset, + arg.Limit, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetBetOutcomeViewByEventIDRow + for rows.Next() { + var i GetBetOutcomeViewByEventIDRow + if err := rows.Scan( + &i.ID, + &i.BetID, + &i.SportID, + &i.EventID, + &i.OddID, + &i.HomeTeamName, + &i.AwayTeamName, + &i.MarketID, + &i.MarketName, + &i.Odd, + &i.OddName, + &i.OddHeader, + &i.OddHandicap, + &i.Status, + &i.Expires, + &i.FirstName, + &i.LastName, + &i.Amount, + &i.TotalOdds, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const GetBetsForCashback = `-- name: GetBetsForCashback :many SELECT id, company_id, amount, total_odds, status, user_id, is_shop_bet, cashed_out, outcomes_hash, fast_code, processed, created_at, updated_at, full_name, phone_number, outcomes FROM bet_with_outcomes @@ -557,6 +654,34 @@ func (q *Queries) GetTotalBets(ctx context.Context, arg GetTotalBetsParams) (int return count, err } +const TotalBetOutcomeViewByEventID = `-- name: TotalBetOutcomeViewByEventID :one +SELECT count(*) +FROM bet_outcomes + JOIN bets ON bets.id = bet_outcomes.bet_id +WHERE bet_outcomes.event_id = $1 + AND ( + bets.company_id = $2 + OR $2 IS NULL + ) + AND ( + bet_outcomes.status = $3 + OR $3 IS NULL + ) +` + +type TotalBetOutcomeViewByEventIDParams struct { + EventID int64 `json:"event_id"` + CompanyID pgtype.Int8 `json:"company_id"` + FilterStatus pgtype.Int4 `json:"filter_status"` +} + +func (q *Queries) TotalBetOutcomeViewByEventID(ctx context.Context, arg TotalBetOutcomeViewByEventIDParams) (int64, error) { + row := q.db.QueryRow(ctx, TotalBetOutcomeViewByEventID, arg.EventID, arg.CompanyID, arg.FilterStatus) + var count int64 + err := row.Scan(&count) + return count, err +} + const UpdateBetOutcomeStatus = `-- name: UpdateBetOutcomeStatus :one UPDATE bet_outcomes SET status = $1 @@ -675,6 +800,54 @@ func (q *Queries) UpdateBetOutcomeStatusForEvent(ctx context.Context, arg Update return items, nil } +const UpdateBetOutcomeStatusForOddID = `-- name: UpdateBetOutcomeStatusForOddID :many +UPDATE bet_outcomes +SEt status = $1 +WHERE odd_id = $2 +RETURNING id, bet_id, sport_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, odd_header, odd_handicap, status, expires +` + +type UpdateBetOutcomeStatusForOddIDParams struct { + Status int32 `json:"status"` + OddID int64 `json:"odd_id"` +} + +func (q *Queries) UpdateBetOutcomeStatusForOddID(ctx context.Context, arg UpdateBetOutcomeStatusForOddIDParams) ([]BetOutcome, error) { + rows, err := q.db.Query(ctx, UpdateBetOutcomeStatusForOddID, arg.Status, arg.OddID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []BetOutcome + for rows.Next() { + var i BetOutcome + if err := rows.Scan( + &i.ID, + &i.BetID, + &i.SportID, + &i.EventID, + &i.OddID, + &i.HomeTeamName, + &i.AwayTeamName, + &i.MarketID, + &i.MarketName, + &i.Odd, + &i.OddName, + &i.OddHeader, + &i.OddHandicap, + &i.Status, + &i.Expires, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const UpdateBetWithCashback = `-- name: UpdateBetWithCashback :exec UPDATE bets SET processed = $1 diff --git a/gen/db/company.sql.go b/gen/db/company.sql.go index 506eaca..ba728e7 100644 --- a/gen/db/company.sql.go +++ b/gen/db/company.sql.go @@ -153,17 +153,27 @@ func (q *Queries) GetCompanyByID(ctx context.Context, id int64) (CompaniesDetail return i, err } -const GetCompanyIDUsingSlug = `-- name: GetCompanyIDUsingSlug :one -SELECT id +const GetCompanyUsingSlug = `-- name: GetCompanyUsingSlug :one +SELECT id, name, slug, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at FROM companies WHERE slug = $1 ` -func (q *Queries) GetCompanyIDUsingSlug(ctx context.Context, slug string) (int64, error) { - row := q.db.QueryRow(ctx, GetCompanyIDUsingSlug, slug) - var id int64 - err := row.Scan(&id) - return id, err +func (q *Queries) GetCompanyUsingSlug(ctx context.Context, slug string) (Company, error) { + row := q.db.QueryRow(ctx, GetCompanyUsingSlug, slug) + var i Company + err := row.Scan( + &i.ID, + &i.Name, + &i.Slug, + &i.AdminID, + &i.WalletID, + &i.DeductedPercentage, + &i.IsActive, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err } const SearchCompanyByName = `-- name: SearchCompanyByName :many diff --git a/gen/db/events.sql.go b/gen/db/events.sql.go index fc793b1..a8345fb 100644 --- a/gen/db/events.sql.go +++ b/gen/db/events.sql.go @@ -282,7 +282,7 @@ type GetEventWithSettingByIDRow struct { CompanyID pgtype.Int8 `json:"company_id"` IsActive bool `json:"is_active"` IsFeatured bool `json:"is_featured"` - WinningUpperLimit int32 `json:"winning_upper_limit"` + WinningUpperLimit int64 `json:"winning_upper_limit"` UpdatedAt pgtype.Timestamp `json:"updated_at"` LeagueCc pgtype.Text `json:"league_cc"` } @@ -440,7 +440,7 @@ type GetEventsWithSettingsRow struct { CompanyID pgtype.Int8 `json:"company_id"` IsActive bool `json:"is_active"` IsFeatured bool `json:"is_featured"` - WinningUpperLimit int32 `json:"winning_upper_limit"` + WinningUpperLimit int64 `json:"winning_upper_limit"` UpdatedAt pgtype.Timestamp `json:"updated_at"` LeagueCc pgtype.Text `json:"league_cc"` } @@ -514,7 +514,9 @@ func (q *Queries) GetEventsWithSettings(ctx context.Context, arg GetEventsWithSe } const GetSportAndLeagueIDs = `-- name: GetSportAndLeagueIDs :one -SELECT sport_id, league_id FROM events +SELECT sport_id, + league_id +FROM events WHERE id = $1 ` @@ -831,7 +833,7 @@ func (q *Queries) ListLiveEvents(ctx context.Context) ([]int64, error) { return items, nil } -const SaveEventSettings = `-- name: SaveEventSettings :exec +const SaveTenantEventSettings = `-- name: SaveTenantEventSettings :exec INSERT INTO company_event_settings ( company_id, event_id, @@ -846,16 +848,16 @@ SET is_active = EXCLUDED.is_active, winning_upper_limit = EXCLUDED.winning_upper_limit ` -type SaveEventSettingsParams struct { +type SaveTenantEventSettingsParams struct { CompanyID int64 `json:"company_id"` EventID int64 `json:"event_id"` IsActive pgtype.Bool `json:"is_active"` IsFeatured pgtype.Bool `json:"is_featured"` - WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"` + WinningUpperLimit pgtype.Int8 `json:"winning_upper_limit"` } -func (q *Queries) SaveEventSettings(ctx context.Context, arg SaveEventSettingsParams) error { - _, err := q.db.Exec(ctx, SaveEventSettings, +func (q *Queries) SaveTenantEventSettings(ctx context.Context, arg SaveTenantEventSettingsParams) error { + _, err := q.db.Exec(ctx, SaveTenantEventSettings, arg.CompanyID, arg.EventID, arg.IsActive, @@ -867,7 +869,8 @@ func (q *Queries) SaveEventSettings(ctx context.Context, arg SaveEventSettingsPa const UpdateEventMonitored = `-- name: UpdateEventMonitored :exec UPDATE events -SET is_monitored = $1 +SET is_monitored = $1, + updated_at = CURRENT_TIMESTAMP WHERE id = $2 ` @@ -881,6 +884,38 @@ func (q *Queries) UpdateEventMonitored(ctx context.Context, arg UpdateEventMonit return err } +const UpdateGlobalEventSettings = `-- name: UpdateGlobalEventSettings :exec +UPDATE events +SET default_is_active = COALESCE($2, default_is_active), + default_is_featured = COALESCE( + $3, + default_is_featured + ), + default_winning_upper_limit = COALESCE( + $4, + default_winning_upper_limit + ), + updated_at = CURRENT_TIMESTAMP +WHERE id = $1 +` + +type UpdateGlobalEventSettingsParams struct { + ID int64 `json:"id"` + DefaultIsActive pgtype.Bool `json:"default_is_active"` + DefaultIsFeatured pgtype.Bool `json:"default_is_featured"` + DefaultWinningUpperLimit pgtype.Int8 `json:"default_winning_upper_limit"` +} + +func (q *Queries) UpdateGlobalEventSettings(ctx context.Context, arg UpdateGlobalEventSettingsParams) error { + _, err := q.db.Exec(ctx, UpdateGlobalEventSettings, + arg.ID, + arg.DefaultIsActive, + arg.DefaultIsFeatured, + arg.DefaultWinningUpperLimit, + ) + return err +} + const UpdateMatchResult = `-- name: UpdateMatchResult :exec UPDATE events SET score = $1, diff --git a/gen/db/leagues.sql.go b/gen/db/leagues.sql.go index 1d2800b..912e257 100644 --- a/gen/db/leagues.sql.go +++ b/gen/db/leagues.sql.go @@ -292,7 +292,7 @@ func (q *Queries) InsertLeague(ctx context.Context, arg InsertLeagueParams) erro return err } -const InsertLeagueSettings = `-- name: InsertLeagueSettings :exec +const SaveLeagueSettings = `-- name: SaveLeagueSettings :exec INSERT INTO company_league_settings ( company_id, league_id, @@ -305,15 +305,15 @@ SET is_active = EXCLUDED.is_active, is_featured = EXCLUDED.is_featured ` -type InsertLeagueSettingsParams struct { +type SaveLeagueSettingsParams struct { CompanyID int64 `json:"company_id"` LeagueID int64 `json:"league_id"` IsActive pgtype.Bool `json:"is_active"` IsFeatured pgtype.Bool `json:"is_featured"` } -func (q *Queries) InsertLeagueSettings(ctx context.Context, arg InsertLeagueSettingsParams) error { - _, err := q.db.Exec(ctx, InsertLeagueSettings, +func (q *Queries) SaveLeagueSettings(ctx context.Context, arg SaveLeagueSettingsParams) error { + _, err := q.db.Exec(ctx, SaveLeagueSettings, arg.CompanyID, arg.LeagueID, arg.IsActive, @@ -322,6 +322,52 @@ func (q *Queries) InsertLeagueSettings(ctx context.Context, arg InsertLeagueSett return err } +const UpdateCompanyLeagueSettings = `-- name: UpdateCompanyLeagueSettings :exec +UPDATE company_league_settings +SET is_active = COALESCE($3, is_active), + is_featured = COALESCE( + $4, + is_featured + ) +WHERE league_id = $1 + AND company_id = $2 +` + +type UpdateCompanyLeagueSettingsParams struct { + LeagueID int64 `json:"league_id"` + CompanyID int64 `json:"company_id"` + IsActive pgtype.Bool `json:"is_active"` + IsFeatured pgtype.Bool `json:"is_featured"` +} + +func (q *Queries) UpdateCompanyLeagueSettings(ctx context.Context, arg UpdateCompanyLeagueSettingsParams) error { + _, err := q.db.Exec(ctx, UpdateCompanyLeagueSettings, + arg.LeagueID, + arg.CompanyID, + arg.IsActive, + arg.IsFeatured, + ) + return err +} + +const UpdateGlobalLeagueSettings = `-- name: UpdateGlobalLeagueSettings :exec +UPDATE leagues +SET default_is_active = COALESCE($2, default_is_active), + default_is_featured = COALESCE($3, default_is_featured) +WHERE id = $1 +` + +type UpdateGlobalLeagueSettingsParams struct { + ID int64 `json:"id"` + IsActive pgtype.Bool `json:"is_active"` + IsFeatured pgtype.Bool `json:"is_featured"` +} + +func (q *Queries) UpdateGlobalLeagueSettings(ctx context.Context, arg UpdateGlobalLeagueSettingsParams) error { + _, err := q.db.Exec(ctx, UpdateGlobalLeagueSettings, arg.ID, arg.IsActive, arg.IsFeatured) + return err +} + const UpdateLeague = `-- name: UpdateLeague :exec UPDATE leagues SET name = COALESCE($2, name), @@ -349,31 +395,3 @@ func (q *Queries) UpdateLeague(ctx context.Context, arg UpdateLeagueParams) erro ) return err } - -const UpdateLeagueSettings = `-- name: UpdateLeagueSettings :exec -UPDATE company_league_settings -SET is_active = COALESCE($3, is_active), - is_featured = COALESCE( - $4, - is_featured - ) -WHERE league_id = $1 - AND company_id = $2 -` - -type UpdateLeagueSettingsParams struct { - LeagueID int64 `json:"league_id"` - CompanyID int64 `json:"company_id"` - IsActive pgtype.Bool `json:"is_active"` - IsFeatured pgtype.Bool `json:"is_featured"` -} - -func (q *Queries) UpdateLeagueSettings(ctx context.Context, arg UpdateLeagueSettingsParams) error { - _, err := q.db.Exec(ctx, UpdateLeagueSettings, - arg.LeagueID, - arg.CompanyID, - arg.IsActive, - arg.IsFeatured, - ) - return err -} diff --git a/gen/db/models.go b/gen/db/models.go index cff8694..339efb8 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -177,7 +177,7 @@ type CompanyEventSetting struct { EventID int64 `json:"event_id"` IsActive pgtype.Bool `json:"is_active"` IsFeatured pgtype.Bool `json:"is_featured"` - WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"` + WinningUpperLimit pgtype.Int8 `json:"winning_upper_limit"` UpdatedAt pgtype.Timestamp `json:"updated_at"` } @@ -405,7 +405,7 @@ type EventWithSetting struct { CompanyID pgtype.Int8 `json:"company_id"` IsActive bool `json:"is_active"` IsFeatured bool `json:"is_featured"` - WinningUpperLimit int32 `json:"winning_upper_limit"` + WinningUpperLimit int64 `json:"winning_upper_limit"` UpdatedAt pgtype.Timestamp `json:"updated_at"` LeagueCc pgtype.Text `json:"league_cc"` } diff --git a/gen/db/odds.sql.go b/gen/db/odds.sql.go index ac9974c..e7c687e 100644 --- a/gen/db/odds.sql.go +++ b/gen/db/odds.sql.go @@ -11,6 +11,32 @@ import ( "github.com/jackc/pgx/v5/pgtype" ) +const DeleteAllCompanyOddsSetting = `-- name: DeleteAllCompanyOddsSetting :exec +DELETE FROM company_odd_settings +WHERE company_id = $1 +` + +func (q *Queries) DeleteAllCompanyOddsSetting(ctx context.Context, companyID int64) error { + _, err := q.db.Exec(ctx, DeleteAllCompanyOddsSetting, companyID) + return err +} + +const DeleteCompanyOddsSettingByOddMarketID = `-- name: DeleteCompanyOddsSettingByOddMarketID :exec +DELETE FROM company_odd_settings +WHERE company_id = $1 + AND odds_market_id = $2 +` + +type DeleteCompanyOddsSettingByOddMarketIDParams struct { + CompanyID int64 `json:"company_id"` + OddsMarketID int64 `json:"odds_market_id"` +} + +func (q *Queries) DeleteCompanyOddsSettingByOddMarketID(ctx context.Context, arg DeleteCompanyOddsSettingByOddMarketIDParams) error { + _, err := q.db.Exec(ctx, DeleteCompanyOddsSettingByOddMarketID, arg.CompanyID, arg.OddsMarketID) + return err +} + const DeleteOddsForEvent = `-- name: DeleteOddsForEvent :exec DELETE FROM odds_market Where event_id = $1 @@ -568,3 +594,19 @@ func (q *Queries) SaveOddSettings(ctx context.Context, arg SaveOddSettingsParams ) return err } + +const UpdateGlobalOddsSetting = `-- name: UpdateGlobalOddsSetting :exec +UPDATE odds_market +SET default_is_active = COALESCE($2, default_is_active) +WHERE id = $1 +` + +type UpdateGlobalOddsSettingParams struct { + ID int64 `json:"id"` + DefaultIsActive pgtype.Bool `json:"default_is_active"` +} + +func (q *Queries) UpdateGlobalOddsSetting(ctx context.Context, arg UpdateGlobalOddsSettingParams) error { + _, err := q.db.Exec(ctx, UpdateGlobalOddsSetting, arg.ID, arg.DefaultIsActive) + return err +} diff --git a/internal/domain/bet.go b/internal/domain/bet.go index e4939ba..dcb78f0 100644 --- a/internal/domain/bet.go +++ b/internal/domain/bet.go @@ -163,6 +163,35 @@ type BetRes struct { FastCode string `json:"fast_code"` } +type BetOutcomeViewRes struct { + ID int64 `json:"id"` + BetID int64 `json:"bet_id"` + SportID int64 `json:"sport_id"` + EventID int64 `json:"event_id"` + OddID int64 `json:"odd_id"` + HomeTeamName string `json:"home_team_name"` + AwayTeamName string `json:"away_team_name"` + MarketID int64 `json:"market_id"` + MarketName string `json:"market_name"` + Odd float32 `json:"odd"` + OddName string `json:"odd_name"` + OddHeader string `json:"odd_header"` + OddHandicap string `json:"odd_handicap"` + Status OutcomeStatus `json:"status"` + Expires time.Time `json:"expires"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + Amount int64 `json:"amount"` + TotalOdds float32 `json:"total_odds"` +} + +type BetOutcomeViewFilter struct { + OutcomeStatus ValidOutcomeStatus + CompanyID ValidInt64 + Limit ValidInt32 + Offset ValidInt32 +} + func ConvertCreateBetRes(bet Bet, createdNumber int64) CreateBetRes { return CreateBetRes{ ID: bet.ID, @@ -228,6 +257,29 @@ func ConvertDBBetOutcomes(outcome dbgen.BetOutcome) BetOutcome { Expires: outcome.Expires.Time, } } +func ConvertDBBetOutcomesView(outcome dbgen.GetBetOutcomeViewByEventIDRow) BetOutcomeViewRes { + return BetOutcomeViewRes{ + ID: outcome.ID, + BetID: outcome.BetID, + SportID: outcome.SportID, + EventID: outcome.EventID, + OddID: outcome.OddID, + HomeTeamName: outcome.HomeTeamName, + AwayTeamName: outcome.AwayTeamName, + MarketID: outcome.MarketID, + MarketName: outcome.MarketName, + Odd: outcome.Odd, + OddName: outcome.OddName, + OddHeader: outcome.OddHeader, + OddHandicap: outcome.OddHandicap, + Status: OutcomeStatus(outcome.Status), + Expires: outcome.Expires.Time, + FirstName: outcome.FirstName, + LastName: outcome.LastName, + Amount: outcome.Amount, + TotalOdds: outcome.TotalOdds, + } +} func ConvertDBBetWithOutcomes(bet dbgen.BetWithOutcome) GetBet { var outcomes []BetOutcome = make([]BetOutcome, 0, len(bet.Outcomes)) diff --git a/internal/domain/event.go b/internal/domain/event.go index d898150..de5ac3a 100644 --- a/internal/domain/event.go +++ b/internal/domain/event.go @@ -1,6 +1,7 @@ package domain import ( + "fmt" "time" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" @@ -50,6 +51,58 @@ const ( EVENT_SOURCE_ENET EventSource = "enetpulse" ) +// --- EventStatus Validation --- +func (s EventStatus) IsValid() bool { + switch s { + case STATUS_PENDING, + STATUS_IN_PLAY, + STATUS_TO_BE_FIXED, + STATUS_ENDED, + STATUS_POSTPONED, + STATUS_CANCELLED, + STATUS_WALKOVER, + STATUS_INTERRUPTED, + STATUS_ABANDONED, + STATUS_RETIRED, + STATUS_SUSPENDED, + STATUS_DECIDED_BY_FA, + STATUS_REMOVED: + return true + default: + return false + } +} + +func ParseEventStatus(val string) (EventStatus, error) { + s := EventStatus(val) + if !s.IsValid() { + return "", fmt.Errorf("invalid EventStatus: %q", val) + } + return s, nil +} + +// --- EventSource Validation --- +func (s EventSource) IsValid() bool { + switch s { + case EVENT_SOURCE_BET365, + EVENT_SOURCE_BWIN, + EVENT_SOURCE_BETFAIR, + EVENT_SOURCE_1XBET, + EVENT_SOURCE_ENET: + return true + default: + return false + } +} + +func ParseEventSource(val string) (EventSource, error) { + s := EventSource(val) + if !s.IsValid() { + return "", fmt.Errorf("invalid EventSource: %q", val) + } + return s, nil +} + type BaseEvent struct { ID int64 SourceEventID string @@ -128,7 +181,7 @@ type EventWithSettings struct { IsMonitored bool IsFeatured bool IsActive bool - WinningUpperLimit int32 + WinningUpperLimit int64 DefaultIsFeatured bool DefaultIsActive bool DefaultWinningUpperLimit int64 @@ -181,7 +234,7 @@ type EventWithSettingsRes struct { IsMonitored bool `json:"is_monitored"` IsFeatured bool `json:"is_featured"` IsActive bool `json:"is_active"` - WinningUpperLimit int32 `json:"winning_upper_limit"` + WinningUpperLimit int64 `json:"winning_upper_limit"` DefaultIsFeatured bool `json:"default_is_featured"` DefaultIsActive bool `json:"default_is_active"` DefaultWinningUpperLimit int64 `json:"default_winning_upper_limit"` @@ -204,12 +257,18 @@ type EventSettings struct { UpdatedAt time.Time } -type CreateEventSettings struct { +type UpdateTenantEventSettings struct { CompanyID int64 EventID int64 IsActive ValidBool IsFeatured ValidBool - WinningUpperLimit ValidInt + WinningUpperLimit ValidInt64 +} +type UpdateGlobalEventSettings struct { + EventID int64 + IsActive ValidBool + IsFeatured ValidBool + WinningUpperLimit ValidInt64 } type ValidEventStatus struct { @@ -331,8 +390,8 @@ func ConvertCreateEvent(e CreateEvent) dbgen.InsertEventParams { } } -func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.SaveEventSettingsParams { - return dbgen.SaveEventSettingsParams{ +func ConvertCreateEventSettings(eventSettings UpdateTenantEventSettings) dbgen.SaveTenantEventSettingsParams { + return dbgen.SaveTenantEventSettingsParams{ CompanyID: eventSettings.CompanyID, EventID: eventSettings.EventID, IsActive: eventSettings.IsActive.ToPG(), @@ -343,17 +402,19 @@ func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.SaveEve func ConvertDBEventWithSetting(event dbgen.EventWithSetting) EventWithSettings { return EventWithSettings{ - ID: event.ID, - SportID: event.SportID, - MatchName: event.MatchName, - HomeTeam: event.HomeTeam, - AwayTeam: event.AwayTeam, - HomeTeamID: event.HomeTeamID, - AwayTeamID: event.AwayTeamID, - HomeTeamImage: event.HomeKitImage, - AwayTeamImage: event.AwayKitImage, - LeagueID: event.LeagueID, - LeagueName: event.LeagueName, + ID: event.ID, + SourceEventID: event.SourceEventID, + WinningUpperLimit: event.WinningUpperLimit, + SportID: event.SportID, + MatchName: event.MatchName, + HomeTeam: event.HomeTeam, + AwayTeam: event.AwayTeam, + HomeTeamID: event.HomeTeamID, + AwayTeamID: event.AwayTeamID, + HomeTeamImage: event.HomeKitImage, + AwayTeamImage: event.AwayKitImage, + LeagueID: event.LeagueID, + LeagueName: event.LeagueName, LeagueCC: ValidString{ Value: event.LeagueCc.String, Valid: event.LeagueCc.Valid, @@ -401,8 +462,8 @@ func ConvertDBEventWithSettings(events []dbgen.EventWithSetting) []EventWithSett return result } -func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.SaveEventSettingsParams { - return dbgen.SaveEventSettingsParams{ +func ConvertUpdateTenantEventSettings(event UpdateTenantEventSettings) dbgen.SaveTenantEventSettingsParams { + return dbgen.SaveTenantEventSettingsParams{ EventID: event.EventID, CompanyID: event.CompanyID, IsActive: event.IsActive.ToPG(), @@ -410,10 +471,19 @@ func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.SaveEventSettin WinningUpperLimit: event.WinningUpperLimit.ToPG(), } } +func ConvertUpdateGlobalEventSettings(event UpdateGlobalEventSettings) dbgen.UpdateGlobalEventSettingsParams { + return dbgen.UpdateGlobalEventSettingsParams{ + ID: event.EventID, + DefaultIsActive: event.IsActive.ToPG(), + DefaultIsFeatured: event.IsFeatured.ToPG(), + DefaultWinningUpperLimit: event.WinningUpperLimit.ToPG(), + } +} func ConvertEventRes(event BaseEvent) BaseEventRes { return BaseEventRes{ ID: event.ID, + SourceEventID: event.SourceEventID, SportID: event.SportID, MatchName: event.MatchName, HomeTeam: event.HomeTeam, @@ -452,6 +522,7 @@ func ConvertEventResList(events []BaseEvent) []BaseEventRes { func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes { return EventWithSettingsRes{ ID: event.ID, + SourceEventID: event.SourceEventID, SportID: event.SportID, MatchName: event.MatchName, HomeTeam: event.HomeTeam, @@ -480,6 +551,7 @@ func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes { MatchPeriod: event.MatchPeriod.Value, IsLive: event.IsLive, FetchedAt: event.FetchedAt.UTC(), + UpdatedAt: event.UpdatedAt, } } diff --git a/internal/domain/league.go b/internal/domain/league.go index 6743b6e..c2de5d1 100644 --- a/internal/domain/league.go +++ b/internal/domain/league.go @@ -87,6 +87,17 @@ type UpdateLeague struct { SportID ValidInt32 `json:"sport_id" example:"1"` } +type UpdateLeagueSettingsReq struct { + IsFeatured *bool `json:"is_featured" example:"true"` + IsActive *bool `json:"is_active" example:"true"` +} + +type UpdateGlobalLeagueSettings struct { + ID int64 + DefaultIsActive ValidBool + DefaultIsFeatured ValidBool +} + type LeagueFilter struct { Query ValidString CountryCode ValidString @@ -109,8 +120,8 @@ func ConvertCreateLeague(league CreateLeague) dbgen.InsertLeagueParams { } } -func ConvertCreateLeagueSettings(leagueSetting CreateLeagueSettings) dbgen.InsertLeagueSettingsParams { - return dbgen.InsertLeagueSettingsParams{ +func ConvertCreateLeagueSettings(leagueSetting CreateLeagueSettings) dbgen.SaveLeagueSettingsParams { + return dbgen.SaveLeagueSettingsParams{ CompanyID: leagueSetting.CompanyID, LeagueID: leagueSetting.LeagueID, IsActive: leagueSetting.IsActive.ToPG(), @@ -149,7 +160,7 @@ func ConvertDBLeagueWithSetting(lws dbgen.GetAllLeaguesWithSettingsRow) LeagueWi ID: lws.ID, Name: lws.Name, CompanyID: lws.CompanyID.Int64, - CountryCode: ValidString{ + CountryCode: ValidString{ Value: lws.CountryCode.String, Valid: lws.CountryCode.Valid, }, @@ -187,15 +198,15 @@ func ConvertUpdateLeague(updateLeague UpdateLeague) dbgen.UpdateLeagueParams { func ConvertLeagueWithSettingRes(lws LeagueWithSettings) LeagueWithSettingsRes { return LeagueWithSettingsRes{ - ID: lws.ID, - Name: lws.Name, - CompanyID: lws.CompanyID, - CountryCode: lws.CountryCode.Value, - Bet365ID: lws.Bet365ID.Value, - IsActive: lws.IsActive, - SportID: lws.SportID, - IsFeatured: lws.IsFeatured, - UpdatedAt: lws.UpdatedAt, + ID: lws.ID, + Name: lws.Name, + CompanyID: lws.CompanyID, + CountryCode: lws.CountryCode.Value, + Bet365ID: lws.Bet365ID.Value, + IsActive: lws.IsActive, + SportID: lws.SportID, + IsFeatured: lws.IsFeatured, + UpdatedAt: lws.UpdatedAt, DefaultIsActive: lws.DefaultIsActive, DefaultIsFeatured: lws.DefaultIsFeatured, } @@ -213,12 +224,12 @@ func ConvertLeagueWithSettingResList(leagues []LeagueWithSettings) []LeagueWithS func ConvertBaseLeagueRes(league BaseLeague) BaseLeagueRes { return BaseLeagueRes{ - ID: league.ID, - Name: league.Name, - CountryCode: league.CountryCode.Value, - Bet365ID: league.Bet365ID.Value, - SportID: league.SportID, - DefaultIsActive: league.DefaultIsActive, + ID: league.ID, + Name: league.Name, + CountryCode: league.CountryCode.Value, + Bet365ID: league.Bet365ID.Value, + SportID: league.SportID, + DefaultIsActive: league.DefaultIsActive, DefaultIsFeatured: league.DefaultIsFeatured, } } @@ -231,3 +242,11 @@ func ConvertBaseLeagueResList(leagues []BaseLeague) []BaseLeagueRes { return result } + +func ConvertUpdateGlobalLeagueSetting(league UpdateGlobalLeagueSettings) dbgen.UpdateGlobalLeagueSettingsParams { + return dbgen.UpdateGlobalLeagueSettingsParams{ + ID: league.ID, + IsActive: league.DefaultIsActive.ToPG(), + IsFeatured: league.DefaultIsFeatured.ToPG(), + } +} diff --git a/internal/domain/odds.go b/internal/domain/odds.go index 2c94c78..27ac23c 100644 --- a/internal/domain/odds.go +++ b/internal/domain/odds.go @@ -61,6 +61,11 @@ type CreateOddMarketSettings struct { CustomRawOdds []map[string]interface{} } +type UpdateGlobalOddMarketSettings struct { + OddMarketID int64 + IsActive ValidBool +} + type CustomOdd struct { OddID int64 `json:"odd_id"` OddValue float32 `json:"odd_value"` @@ -72,6 +77,11 @@ type CreateOddMarketSettingsReq struct { CustomOdd []CustomOdd `json:"custom_odd,omitempty"` } +type UpdateGlobalOddMarketSettingsReq struct { + OddMarketID int64 `json:"odd_market_id"` + IsActive *bool `json:"is_active,omitempty"` +} + type RawOddsByMarketID struct { ID int64 `json:"id"` MarketName string `json:"market_name"` @@ -86,6 +96,8 @@ type OddMarketFilter struct { Offset ValidInt32 } type OddMarketWithEventFilter struct { + Status ValidString + IsLive ValidBool Limit ValidInt32 Offset ValidInt32 } diff --git a/internal/domain/result.go b/internal/domain/result.go index 698e01e..70993fc 100644 --- a/internal/domain/result.go +++ b/internal/domain/result.go @@ -1,6 +1,7 @@ package domain import ( + "fmt" "time" "github.com/jackc/pgx/v5/pgtype" @@ -48,6 +49,28 @@ const ( OUTCOME_STATUS_ERROR OutcomeStatus = 5 //Half Win and Half Given Back ) +func (o OutcomeStatus) IsValid() bool { + switch o { + case OUTCOME_STATUS_PENDING, + OUTCOME_STATUS_WIN, + OUTCOME_STATUS_LOSS, + OUTCOME_STATUS_VOID, + OUTCOME_STATUS_HALF, + OUTCOME_STATUS_ERROR: + return true + default: + return false + } +} + +func ParseOutcomeStatus(val int) (OutcomeStatus, error) { + o := OutcomeStatus(val) + if !o.IsValid() { + return 0, fmt.Errorf("invalid OutcomeStatus: %d", val) + } + return o, nil +} + func (o *OutcomeStatus) String() string { switch *o { case OUTCOME_STATUS_PENDING: @@ -72,7 +95,6 @@ type ValidOutcomeStatus struct { Valid bool } - func (v ValidOutcomeStatus) ToPG() pgtype.Int4 { return pgtype.Int4{ Int32: int32(v.Value), @@ -80,7 +102,6 @@ func (v ValidOutcomeStatus) ToPG() pgtype.Int4 { } } - type TimeStatus int32 const ( diff --git a/internal/repository/bet.go b/internal/repository/bet.go index bb2a7d7..9a6ad8f 100644 --- a/internal/repository/bet.go +++ b/internal/repository/bet.go @@ -123,7 +123,7 @@ func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]doma Query: filter.Query.ToPG(), CreatedBefore: filter.CreatedBefore.ToPG(), CreatedAfter: filter.CreatedAfter.ToPG(), - }); + }) var result []domain.GetBet = make([]domain.GetBet, 0, len(bets)) for _, bet := range bets { @@ -275,6 +275,36 @@ func (s *Store) SettleWinningBet(ctx context.Context, betID int64, userID int64, return nil } +func (s *Store) GetBetOutcomeViewByEventID(ctx context.Context, eventID int64, filter domain.BetOutcomeViewFilter) ([]domain.BetOutcomeViewRes, int64, error) { + + outcomes, err := s.queries.GetBetOutcomeViewByEventID(ctx, dbgen.GetBetOutcomeViewByEventIDParams{ + EventID: eventID, + FilterStatus: filter.OutcomeStatus.ToPG(), + CompanyID: filter.CompanyID.ToPG(), + Offset: filter.Offset.ToPG(), + Limit: filter.Limit.ToPG(), + }) + + if err != nil { + domain.MongoDBLogger.Error("failed to get bet outcomes by event ID", + zap.Int64("event_id", eventID), + zap.Error(err), + ) + return nil, 0, err + } + + total, err := s.queries.TotalBetOutcomeViewByEventID(ctx, dbgen.TotalBetOutcomeViewByEventIDParams{ + EventID: eventID, + FilterStatus: filter.OutcomeStatus.ToPG(), + CompanyID: filter.CompanyID.ToPG(), + }) + + var result []domain.BetOutcomeViewRes = make([]domain.BetOutcomeViewRes, 0, len(outcomes)) + for _, outcome := range outcomes { + result = append(result, domain.ConvertDBBetOutcomesView(outcome)) + } + return result, total, nil +} func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) { outcomes, err := s.queries.GetBetOutcomeByEventID(ctx, dbgen.GetBetOutcomeByEventIDParams{ @@ -377,6 +407,27 @@ func (s *Store) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int6 } return result, nil } +func (s *Store) UpdateBetOutcomeStatusForOddId(ctx context.Context, oddID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) { + outcomes, err := s.queries.UpdateBetOutcomeStatusForOddID(ctx, dbgen.UpdateBetOutcomeStatusForOddIDParams{ + OddID: oddID, + Status: int32(status), + }) + + if err != nil { + domain.MongoDBLogger.Error("failed to update bet outcome status for oddID", + zap.Int64("oddId", oddID), + zap.Int32("status", int32(status)), + zap.Error(err), + ) + return nil, err + } + + var result []domain.BetOutcome = make([]domain.BetOutcome, 0, len(outcomes)) + for _, outcome := range outcomes { + result = append(result, domain.ConvertDBBetOutcomes(outcome)) + } + return result, nil +} func (s *Store) UpdateBetWithCashback(ctx context.Context, betID int64, cashbackStatus bool) error { err := s.queries.UpdateBetWithCashback(ctx, dbgen.UpdateBetWithCashbackParams{ diff --git a/internal/repository/company.go b/internal/repository/company.go index 08f5251..1e290c9 100644 --- a/internal/repository/company.go +++ b/internal/repository/company.go @@ -17,7 +17,7 @@ func (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany) i := 1 for { - _, err := s.queries.GetCompanyIDUsingSlug(ctx, uniqueSlug) + _, err := s.queries.GetCompanyUsingSlug(ctx, uniqueSlug) if err != nil { if errors.Is(err, pgx.ErrNoRows) { // slug is unique @@ -78,13 +78,13 @@ func (s *Store) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany return domain.ConvertDBCompanyDetails(dbCompany), nil } -func (s *Store) GetCompanyIDBySlug(ctx context.Context, slug string) (int64, error) { - dbCompanyID, err := s.queries.GetCompanyIDUsingSlug(ctx, slug) +func (s *Store) GetCompanyBySlug(ctx context.Context, slug string) (domain.Company, error) { + dbCompany, err := s.queries.GetCompanyUsingSlug(ctx, slug) if err != nil { - return 0, err + return domain.Company{}, err } - return dbCompanyID, nil + return domain.ConvertDBCompany(dbCompany), nil } func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) { diff --git a/internal/repository/event.go b/internal/repository/event.go index b1e5c56..236de50 100644 --- a/internal/repository/event.go +++ b/internal/repository/event.go @@ -3,7 +3,6 @@ package repository import ( "context" "fmt" - "math" dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" @@ -55,8 +54,7 @@ func (s *Store) GetAllEvents(ctx context.Context, filter domain.EventFilter) ([] return nil, 0, err } - numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value)) - return domain.ConvertDBEvents(events), int64(numberOfPages), nil + return domain.ConvertDBEvents(events), totalCount, nil } func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) { @@ -99,8 +97,6 @@ func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filt return nil, 0, err } - numberOfPages := math.Ceil(float64(totalCount) / float64(filter.Limit.Value)) - result := make([]domain.EventWithSettings, len(events)) for i, event := range events { @@ -155,7 +151,7 @@ func (s *Store) GetEventsWithSettings(ctx context.Context, companyID int64, filt } } - return result, int64(numberOfPages), nil + return result, totalCount, nil } func (s *Store) GetEventByID(ctx context.Context, ID int64) (domain.BaseEvent, error) { event, err := s.queries.GetEventByID(ctx, ID) @@ -281,10 +277,13 @@ func (s *Store) UpdateEventMonitored(ctx context.Context, eventID int64, IsMonit }) } -func (s *Store) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error { - return s.queries.SaveEventSettings(ctx, domain.ConvertUpdateEventSettings(event)) +func (s *Store) UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error { + return s.queries.SaveTenantEventSettings(ctx, domain.ConvertUpdateTenantEventSettings(event)) } +func (s *Store) UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error { + return s.queries.UpdateGlobalEventSettings(ctx, domain.ConvertUpdateGlobalEventSettings(event)) +} func (s *Store) DeleteEvent(ctx context.Context, eventID int64) error { err := s.queries.DeleteEvent(ctx, eventID) if err != nil { diff --git a/internal/repository/league.go b/internal/repository/league.go index ae0a4d5..ab01c14 100644 --- a/internal/repository/league.go +++ b/internal/repository/league.go @@ -13,7 +13,7 @@ func (s *Store) SaveLeague(ctx context.Context, league domain.CreateLeague) erro } func (s *Store) SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error { - return s.queries.InsertLeagueSettings(ctx, domain.ConvertCreateLeagueSettings(leagueSettings)) + return s.queries.SaveLeagueSettings(ctx, domain.ConvertCreateLeagueSettings(leagueSettings)) } func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) { @@ -85,3 +85,7 @@ func (s *Store) CheckLeagueSupport(ctx context.Context, leagueID int64, companyI func (s *Store) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error { return s.queries.UpdateLeague(ctx, domain.ConvertUpdateLeague(league)) } + +func (s *Store) UpdateGlobalLeagueSettings(ctx context.Context, league domain.UpdateGlobalLeagueSettings) error { + return s.queries.UpdateGlobalLeagueSettings(ctx, domain.ConvertUpdateGlobalLeagueSetting(league)) +} diff --git a/internal/repository/odds.go b/internal/repository/odds.go index 51e1c6a..009e301 100644 --- a/internal/repository/odds.go +++ b/internal/repository/odds.go @@ -239,17 +239,11 @@ func (s *Store) GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID func (s *Store) GetOddsByEventID(ctx context.Context, eventID int64, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) { odds, err := s.queries.GetOddsByEventID(ctx, dbgen.GetOddsByEventIDParams{ EventID: eventID, + Status: filter.Status.ToPG(), + IsLive: filter.IsLive.ToPG(), Limit: filter.Limit.ToPG(), Offset: filter.Offset.ToPG(), - IsLive: pgtype.Bool{ - Bool: false, - Valid: true, - }, - Status: pgtype.Text{ - String: string(domain.STATUS_PENDING), - Valid: true, - }, - Source: pgtype.Text{}, + Source: pgtype.Text{}, }) if err != nil { return nil, err @@ -322,3 +316,21 @@ func (s *Store) SaveOddsSetting(ctx context.Context, odd domain.CreateOddMarketS } return s.queries.SaveOddSettings(ctx, res) } + +func (s *Store) UpdateGlobalOddsSetting(ctx context.Context, odd domain.UpdateGlobalOddMarketSettings) error { + return s.queries.UpdateGlobalOddsSetting(ctx, dbgen.UpdateGlobalOddsSettingParams{ + ID: odd.OddMarketID, + DefaultIsActive: odd.IsActive.ToPG(), + }) +} + +func (s *Store) DeleteAllCompanyOddsSetting(ctx context.Context, companyID int64) error { + return s.queries.DeleteAllCompanyOddsSetting(ctx, companyID) +} + +func (s *Store) DeleteCompanyOddsSettingByOddMarketID(ctx context.Context, companyID int64, oddMarketID int64) error { + return s.queries.DeleteCompanyOddsSettingByOddMarketID(ctx, dbgen.DeleteCompanyOddsSettingByOddMarketIDParams{ + CompanyID: companyID, + OddsMarketID: oddMarketID, + }) +} diff --git a/internal/services/bet/notification.go b/internal/services/bet/notification.go index e9dd185..f891b94 100644 --- a/internal/services/bet/notification.go +++ b/internal/services/bet/notification.go @@ -247,7 +247,7 @@ func (s *Service) SendAdminErrorNotification(ctx context.Context, betID int64, s } func (s *Service) SendAdminLargeBetNotification(ctx context.Context, betID int64, totalWinnings float32, extra string, companyID int64) error { - headline := fmt.Sprintf("SYSTEM WARNING: High Risk Bet", betID, totalWinnings) + headline := "SYSTEM WARNING: High Risk Bet" message := fmt.Sprintf("Bet #%d has been created with %v payout", betID, totalWinnings) super_admin_users, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{ diff --git a/internal/services/bet/port.go b/internal/services/bet/port.go index dc582b4..1b52474 100644 --- a/internal/services/bet/port.go +++ b/internal/services/bet/port.go @@ -15,6 +15,7 @@ type BetStore interface { GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, int64, error) GetBetByUserID(ctx context.Context, UserID int64) ([]domain.GetBet, error) GetBetByFastCode(ctx context.Context, fastcode string) (domain.GetBet, error) + GetBetOutcomeViewByEventID(ctx context.Context, eventID int64, filter domain.BetOutcomeViewFilter) ([]domain.BetOutcomeViewRes, int64, error) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) GetBetOutcomeByBetID(ctx context.Context, betID int64) ([]domain.BetOutcome, error) GetBetOutcomeCountByOddID(ctx context.Context, oddID int64) (int64, error) @@ -25,7 +26,7 @@ type BetStore interface { UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) UpdateBetOutcomeStatusByBetID(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) - + UpdateBetOutcomeStatusForOddId(ctx context.Context, oddID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) GetBetSummary(ctx context.Context, filter domain.ReportFilter) ( totalStakes domain.Currency, totalBets int64, diff --git a/internal/services/bet/service.go b/internal/services/bet/service.go index 009f6fd..2379c3b 100644 --- a/internal/services/bet/service.go +++ b/internal/services/bet/service.go @@ -848,6 +848,9 @@ func (s *Service) GetBetOutcomeByBetID(ctx context.Context, UserID int64) ([]dom return s.betStore.GetBetOutcomeByBetID(ctx, UserID) } +func (s *Service) GetBetOutcomeViewByEventID(ctx context.Context, eventID int64, filter domain.BetOutcomeViewFilter) ([]domain.BetOutcomeViewRes, int64, error) { + return s.betStore.GetBetOutcomeViewByEventID(ctx, eventID, filter) +} func (s *Service) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) { return s.betStore.GetBetOutcomeByEventID(ctx, eventID, is_filtered) } @@ -1076,6 +1079,19 @@ func (s *Service) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID in return outcomes, nil } +func (s *Service) UpdateBetOutcomeStatusForOddId(ctx context.Context, oddID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) { + outcomes, err := s.betStore.UpdateBetOutcomeStatusForOddId(ctx, oddID, status) + if err != nil { + s.mongoLogger.Error("failed to update bet outcome status", + zap.Int64("oddID", oddID), + zap.Error(err), + ) + return nil, err + } + + return outcomes, nil +} + func (s *Service) SetBetToRemoved(ctx context.Context, id int64) error { _, err := s.betStore.UpdateBetOutcomeStatusByBetID(ctx, id, domain.OUTCOME_STATUS_VOID) if err != nil { diff --git a/internal/services/company/port.go b/internal/services/company/port.go index 10bfa70..d3540f2 100644 --- a/internal/services/company/port.go +++ b/internal/services/company/port.go @@ -11,7 +11,7 @@ type CompanyStore interface { GetAllCompanies(ctx context.Context, filter domain.CompanyFilter) ([]domain.GetCompany, error) SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error) - GetCompanyIDBySlug(ctx context.Context, slug string) (int64, error) + GetCompanyBySlug(ctx context.Context, slug string) (domain.Company, error) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) DeleteCompany(ctx context.Context, id int64) error diff --git a/internal/services/company/service.go b/internal/services/company/service.go index a396a10..1f69a22 100644 --- a/internal/services/company/service.go +++ b/internal/services/company/service.go @@ -26,8 +26,8 @@ func (s *Service) GetAllCompanies(ctx context.Context, filter domain.CompanyFilt func (s *Service) GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error) { return s.companyStore.GetCompanyByID(ctx, id) } -func (s *Service) GetCompanyIDBySlug(ctx context.Context, slug string) (int64, error){ - return s.companyStore.GetCompanyIDBySlug(ctx, slug) +func (s *Service) GetCompanyBySlug(ctx context.Context, slug string) (domain.Company, error) { + return s.companyStore.GetCompanyBySlug(ctx, slug) } func (s *Service) SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error) { diff --git a/internal/services/event/port.go b/internal/services/event/port.go index 546699e..8653ce6 100644 --- a/internal/services/event/port.go +++ b/internal/services/event/port.go @@ -18,6 +18,7 @@ type Service interface { UpdateEventMonitored(ctx context.Context, eventID int64, IsMonitored bool) error GetEventsWithSettings(ctx context.Context, companyID int64, filter domain.EventFilter) ([]domain.EventWithSettings, int64, error) GetEventWithSettingByID(ctx context.Context, ID int64, companyID int64) (domain.EventWithSettings, error) - UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error + UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error + UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error GetSportAndLeagueIDs(ctx context.Context, eventID int64) ([]int64, error) } diff --git a/internal/services/event/service.go b/internal/services/event/service.go index 5bc27e6..b083641 100644 --- a/internal/services/event/service.go +++ b/internal/services/event/service.go @@ -491,8 +491,11 @@ func (s *service) GetEventWithSettingByID(ctx context.Context, ID int64, company return s.store.GetEventWithSettingByID(ctx, ID, companyID) } -func (s *service) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error { - return s.store.UpdateEventSettings(ctx, event) +func (s *service) UpdateTenantEventSettings(ctx context.Context, event domain.UpdateTenantEventSettings) error { + return s.store.UpdateTenantEventSettings(ctx, event) +} +func (s *service) UpdateGlobalEventSettings(ctx context.Context, event domain.UpdateGlobalEventSettings) error { + return s.store.UpdateGlobalEventSettings(ctx, event) } func (s *service) GetSportAndLeagueIDs(ctx context.Context, eventID int64) ([]int64, error) { diff --git a/internal/services/league/port.go b/internal/services/league/port.go index 54dc626..277f602 100644 --- a/internal/services/league/port.go +++ b/internal/services/league/port.go @@ -10,7 +10,8 @@ type Service interface { SaveLeague(ctx context.Context, league domain.CreateLeague) error SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) - GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, int64, error) + GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, int64, error) CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error + UpdateGlobalLeagueSettings(ctx context.Context, league domain.UpdateGlobalLeagueSettings) error } diff --git a/internal/services/league/service.go b/internal/services/league/service.go index 9a3e1a3..b07bc99 100644 --- a/internal/services/league/service.go +++ b/internal/services/league/service.go @@ -40,3 +40,7 @@ func (s *service) CheckLeagueSupport(ctx context.Context, leagueID int64, compan func (s *service) UpdateLeague(ctx context.Context, league domain.UpdateLeague) error { return s.store.UpdateLeague(ctx, league) } + +func (s *service) UpdateGlobalLeagueSettings(ctx context.Context, league domain.UpdateGlobalLeagueSettings) error { + return s.store.UpdateGlobalLeagueSettings(ctx, league) +} \ No newline at end of file diff --git a/internal/services/odds/port.go b/internal/services/odds/port.go index 3ec57b9..b67b91e 100644 --- a/internal/services/odds/port.go +++ b/internal/services/odds/port.go @@ -17,31 +17,17 @@ type Service interface { GetALLPrematchOdds(ctx context.Context) ([]domain.OddMarket, error) // GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.OddMarket, error) DeleteOddsForEvent(ctx context.Context, eventID string) error - GetOddByID(ctx context.Context, id int64) (domain.OddMarket, error) - GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID int64) (domain.OddMarketWithSettings, error) + GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID int64) (domain.OddMarketWithSettings, error) + // Settings SaveOddsSetting(ctx context.Context, odd domain.CreateOddMarketSettings) error + UpdateGlobalOddsSetting(ctx context.Context, odd domain.UpdateGlobalOddMarketSettings) error + DeleteAllCompanyOddsSetting(ctx context.Context, companyID int64) error + DeleteCompanyOddsSettingByOddMarketID(ctx context.Context, companyID int64, oddMarketID int64) error // Odd History InsertOddHistory(ctx context.Context, odd domain.CreateOddHistory) (domain.OddHistory, error) GetAllOddHistory(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error) GetInitialOddPerDay(ctx context.Context, filter domain.OddHistoryFilter) ([]domain.OddHistory, error) - - // Disabling Odds - InsertDisabledOdd(ctx context.Context, odd domain.CreateDisabledOdd) (domain.DisabledOdd, error) - GetAllDisabledOdds(ctx context.Context) ([]domain.DisabledOdd, error) - GetDisabledOddByRawOddID(ctx context.Context, rawOddID int64) (domain.DisabledOdd, error) - GetDisabledOddByID(ctx context.Context, id int64) (domain.DisabledOdd, error) - DeleteDisabledOddsByID(ctx context.Context, id int64) error - DeleteDisabledOddsByRawOddID(ctx context.Context, id int64) error - - // Custom Odds - // InsertCustomOdds(ctx context.Context, odd domain.CreateCustomOdd) (domain.CustomOdd, error) - // GetAllCustomOdds(ctx context.Context, filter domain.CustomOddFilter) ([]domain.CustomOdd, error) - // GetCustomOddByID(ctx context.Context, id int64) (domain.CustomOdd, error) - // GetCustomOddByOddID(ctx context.Context, oddId int64, companyID int64) (domain.CustomOdd, error) - // DeleteCustomOddByID(ctx context.Context, id int64) error - // DeleteCustomOddsByOddID(ctx context.Context, oddId int64, companyID int64) error - // DeleteCustomOddByEventID(ctx context.Context, eventID string) error } diff --git a/internal/services/odds/service.go b/internal/services/odds/service.go index 0a9f401..dcc1004 100644 --- a/internal/services/odds/service.go +++ b/internal/services/odds/service.go @@ -676,6 +676,10 @@ func (s *ServiceImpl) SaveOddsSetting(ctx context.Context, odd domain.CreateOddM return s.store.SaveOddsSetting(ctx, odd) } +func (s *ServiceImpl) UpdateGlobalOddsSetting(ctx context.Context, odd domain.UpdateGlobalOddMarketSettings) error { + return s.store.UpdateGlobalOddsSetting(ctx, odd); +} + func (s *ServiceImpl) SaveOddsSettingReq(ctx context.Context, companyID int64, req domain.CreateOddMarketSettingsReq) error { odd, err := s.GetOddsWithSettingsByID(ctx, req.OddMarketID, companyID) @@ -741,6 +745,14 @@ func (s *ServiceImpl) DeleteOddsForEvent(ctx context.Context, eventID int64) err return s.store.DeleteOddsForEvent(ctx, eventID) } +func (s *ServiceImpl) DeleteAllCompanyOddsSetting(ctx context.Context, companyID int64) error { + return s.store.DeleteAllCompanyOddsSetting(ctx, companyID) +} + +func (s *ServiceImpl) DeleteCompanyOddsSettingByOddMarketID(ctx context.Context, companyID int64, oddMarketID int64) error{ + return s.store.DeleteCompanyOddsSettingByOddMarketID(ctx, companyID, oddMarketID) +} + // func getString(v interface{}) string { // if str, ok := v.(string); ok { // return str diff --git a/internal/web_server/cron.go b/internal/web_server/cron.go index f1caaac..09aab85 100644 --- a/internal/web_server/cron.go +++ b/internal/web_server/cron.go @@ -27,71 +27,71 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S spec string task func() }{ - { - spec: "0 0 * * * *", // Every 1 hour - task: func() { - mongoLogger.Info("Began fetching upcoming events cron task") - if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { - mongoLogger.Error("Failed to fetch upcoming events", - zap.Error(err), - ) - } else { - mongoLogger.Info("Completed fetching upcoming events without errors") - } - }, - }, - { - spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) - task: func() { - mongoLogger.Info("Began fetching non live odds cron task") - if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { - mongoLogger.Error("Failed to fetch non live odds", - zap.Error(err), - ) - } else { - mongoLogger.Info("Completed fetching non live odds without errors") - } - }, - }, - { - spec: "0 */5 * * * *", // Every 5 Minutes - task: func() { - mongoLogger.Info("Began update all expired events status cron task") - if _, err := resultService.CheckAndUpdateExpiredB365Events(context.Background()); err != nil { - mongoLogger.Error("Failed to update expired events status", - zap.Error(err), - ) - } else { - mongoLogger.Info("Completed expired events without errors") - } - }, - }, - { - spec: "0 */15 * * * *", // Every 15 Minutes - task: func() { - mongoLogger.Info("Began updating bets based on event results cron task") - if err := resultService.FetchB365ResultAndUpdateBets(context.Background()); err != nil { - mongoLogger.Error("Failed to process result", - zap.Error(err), - ) - } else { - mongoLogger.Info("Completed processing all event result outcomes without errors") - } - }, - }, - { - spec: "0 0 0 * * 1", // Every Monday - task: func() { - mongoLogger.Info("Began Send weekly result notification cron task") - if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-7*24*time.Hour)); err != nil { - mongoLogger.Error("Failed to process result", - zap.Error(err), - ) - } else { - mongoLogger.Info("Completed sending weekly result notification without errors") - } - }, - }, + // { + // spec: "0 0 * * * *", // Every 1 hour + // task: func() { + // mongoLogger.Info("Began fetching upcoming events cron task") + // if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { + // mongoLogger.Error("Failed to fetch upcoming events", + // zap.Error(err), + // ) + // } else { + // mongoLogger.Info("Completed fetching upcoming events without errors") + // } + // }, + // }, + // { + // spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) + // task: func() { + // mongoLogger.Info("Began fetching non live odds cron task") + // if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { + // mongoLogger.Error("Failed to fetch non live odds", + // zap.Error(err), + // ) + // } else { + // mongoLogger.Info("Completed fetching non live odds without errors") + // } + // }, + // }, + // { + // spec: "0 */5 * * * *", // Every 5 Minutes + // task: func() { + // mongoLogger.Info("Began update all expired events status cron task") + // if _, err := resultService.CheckAndUpdateExpiredB365Events(context.Background()); err != nil { + // mongoLogger.Error("Failed to update expired events status", + // zap.Error(err), + // ) + // } else { + // mongoLogger.Info("Completed expired events without errors") + // } + // }, + // }, + // { + // spec: "0 */15 * * * *", // Every 15 Minutes + // task: func() { + // mongoLogger.Info("Began updating bets based on event results cron task") + // if err := resultService.FetchB365ResultAndUpdateBets(context.Background()); err != nil { + // mongoLogger.Error("Failed to process result", + // zap.Error(err), + // ) + // } else { + // mongoLogger.Info("Completed processing all event result outcomes without errors") + // } + // }, + // }, + // { + // spec: "0 0 0 * * 1", // Every Monday + // task: func() { + // mongoLogger.Info("Began Send weekly result notification cron task") + // if err := resultService.CheckAndSendResultNotifications(context.Background(), time.Now().Add(-7*24*time.Hour)); err != nil { + // mongoLogger.Error("Failed to process result", + // zap.Error(err), + // ) + // } else { + // mongoLogger.Info("Completed sending weekly result notification without errors") + // } + // }, + // }, } for _, job := range schedule { diff --git a/internal/web_server/handlers/admin.go b/internal/web_server/handlers/admin.go index 6eb6122..b7bd75e 100644 --- a/internal/web_server/handlers/admin.go +++ b/internal/web_server/handlers/admin.go @@ -451,24 +451,24 @@ func (h *Handler) UpdateAdmin(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusInternalServerError, "Failed to update admin:"+err.Error()) } - if req.CompanyID != nil { - _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{ - ID: *req.CompanyID, - AdminID: domain.ValidInt64{ - Value: AdminID, - Valid: true, - }, - }) - if err != nil { - h.mongoLoggerSvc.Error("UpdateAdmin failed to update company", - zap.Int("status_code", fiber.StatusInternalServerError), - zap.Int64("admin_id", AdminID), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to update company:"+err.Error()) - } - } + // if req.CompanyID != nil { + // _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{ + // ID: *req.CompanyID, + // AdminID: domain.ValidInt64{ + // Value: AdminID, + // Valid: true, + // }, + // }) + // if err != nil { + // h.mongoLoggerSvc.Error("UpdateAdmin failed to update company", + // zap.Int("status_code", fiber.StatusInternalServerError), + // zap.Int64("admin_id", AdminID), + // zap.Error(err), + // zap.Time("timestamp", time.Now()), + // ) + // return fiber.NewError(fiber.StatusInternalServerError, "Failed to update company:"+err.Error()) + // } + // } h.mongoLoggerSvc.Info("UpdateAdmin succeeded", zap.Int("status_code", fiber.StatusOK), diff --git a/internal/web_server/handlers/auth_handler.go b/internal/web_server/handlers/auth_handler.go index a64f285..930d841 100644 --- a/internal/web_server/handlers/auth_handler.go +++ b/internal/web_server/handlers/auth_handler.go @@ -169,7 +169,7 @@ type loginAdminRes struct { func (h *Handler) LoginAdmin(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { - h.BadRequestLogger().Error("invalid company id") + h.BadRequestLogger().Error("invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id") } var req loginAdminReq diff --git a/internal/web_server/handlers/bet_handler.go b/internal/web_server/handlers/bet_handler.go index 7b33f09..7677b2e 100644 --- a/internal/web_server/handlers/bet_handler.go +++ b/internal/web_server/handlers/bet_handler.go @@ -552,6 +552,25 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error { Valid: true, } } + + var companyID domain.ValidInt64 + companyIDQuery := c.Query("company_id") + if companyIDQuery != "" { + companyIDParsed, err := strconv.ParseInt(companyIDQuery, 10, 64) + if err != nil { + h.mongoLoggerSvc.Info("invalid company_id format", + zap.String("company_id", companyIDQuery), + zap.Int("status_code", fiber.StatusBadRequest), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid company_id format") + } + companyID = domain.ValidInt64{ + Value: companyIDParsed, + Valid: true, + } + } bets, total, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{ IsShopBet: isShopBet, Query: searchString, @@ -560,6 +579,7 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error { Status: statusFilter, Limit: limit, Offset: offset, + CompanyID: companyID, }) if err != nil { h.mongoLoggerSvc.Error("Failed to get all bets", diff --git a/internal/web_server/handlers/event_handler.go b/internal/web_server/handlers/event_handler.go index e32d295..27fa0cd 100644 --- a/internal/web_server/handlers/event_handler.go +++ b/internal/web_server/handlers/event_handler.go @@ -135,6 +135,40 @@ func (h *Handler) GetAllEvents(c *fiber.Ctx) error { } } + isActiveQuery := c.Query("is_active") + var isActive domain.ValidBool + if isActiveQuery != "" { + isActiveParsed, err := strconv.ParseBool(isActiveQuery) + if err != nil { + h.BadRequestLogger().Error("Failed to parse isActive", + zap.String("is_active", isActiveQuery), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_active") + } + + isActive = domain.ValidBool{ + Value: isActiveParsed, + Valid: true, + } + } + + statusQuery := c.Query("status") + var eventStatus domain.ValidEventStatus + if statusQuery != "" { + eventStatusParsed, err := domain.ParseEventStatus(statusQuery) + if err != nil { + h.BadRequestLogger().Error("Failed to parse statusQuery", + zap.String("is_featured", isFeaturedQuery), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, "invalid event status string") + } + eventStatus = domain.ValidEventStatus{ + Value: eventStatusParsed, + Valid: true, + } + } events, total, err := h.eventSvc.GetAllEvents( c.Context(), domain.EventFilter{ SportID: sportID, @@ -146,6 +180,8 @@ func (h *Handler) GetAllEvents(c *fiber.Ctx) error { Offset: offset, CountryCode: countryCode, Featured: isFeatured, + Active: isActive, + Status: eventStatus, }) // fmt.Printf("League ID: %v", leagueID) @@ -294,18 +330,18 @@ func (h *Handler) GetTenantUpcomingEvents(c *fiber.Ctx) error { events, total, err := h.eventSvc.GetEventsWithSettings( c.Context(), companyID.Value, domain.EventFilter{ - SportID: sportID, - LeagueID: leagueID, - Query: searchString, + SportID: sportID, + LeagueID: leagueID, + Query: searchString, FirstStartTime: domain.ValidTime{ Value: time.Now(), Valid: true, }, - LastStartTime: lastStartTime, - Limit: limit, - Offset: offset, - CountryCode: countryCode, - Featured: isFeatured, + LastStartTime: lastStartTime, + Limit: limit, + Offset: offset, + CountryCode: countryCode, + Featured: isFeatured, Status: domain.ValidEventStatus{ Value: domain.STATUS_PENDING, Valid: true, @@ -334,6 +370,200 @@ func (h *Handler) GetTenantUpcomingEvents(c *fiber.Ctx) error { } +// @Summary Retrieve all upcoming events with settings +// @Description Retrieve all upcoming events settings from the database +// @Tags prematch +// @Accept json +// @Produce json +// @Param page query int false "Page number" +// @Param page_size query int false "Page size" +// @Param league_id query string false "League ID Filter" +// @Param sport_id query string false "Sport ID Filter" +// @Param cc query string false "Country Code Filter" +// @Param first_start_time query string false "Start Time" +// @Param last_start_time query string false "End Time" +// @Success 200 {array} domain.BaseEvent +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/{tenant_slug}/events [get] +func (h *Handler) GetTenantEvents(c *fiber.Ctx) error { + companyID := c.Locals("company_id").(domain.ValidInt64) + if !companyID.Valid { + h.BadRequestLogger().Error("invalid company id") + return fiber.NewError(fiber.StatusBadRequest, "invalid company id") + } + + page := c.QueryInt("page", 1) + pageSize := c.QueryInt("page_size", 10) + limit := domain.ValidInt32{ + Value: int32(pageSize), + Valid: true, + } + offset := domain.ValidInt32{ + Value: int32(page - 1), + Valid: true, + } + + leagueIDQuery := c.Query("league_id") + var leagueID domain.ValidInt64 + if leagueIDQuery != "" { + leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64) + if err != nil { + h.BadRequestLogger().Error("invalid league id", + zap.String("league_id", leagueIDQuery), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, "invalid league id") + } + leagueID = domain.ValidInt64{ + Value: leagueIDInt, + Valid: true, + } + } + sportIDQuery := c.Query("sport_id") + var sportID domain.ValidInt32 + if sportIDQuery != "" { + sportIDint, err := strconv.Atoi(sportIDQuery) + if err != nil { + h.BadRequestLogger().Info("invalid sport id", + zap.String("sportID", sportIDQuery), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, "invalid sport id") + } + sportID = domain.ValidInt32{ + Value: int32(sportIDint), + Valid: true, + } + } + + searchQuery := c.Query("query") + searchString := domain.ValidString{ + Value: searchQuery, + Valid: searchQuery != "", + } + + firstStartTimeQuery := c.Query("first_start_time") + var firstStartTime domain.ValidTime + if firstStartTimeQuery != "" { + firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery) + if err != nil { + h.BadRequestLogger().Info("invalid start_time format", + zap.String("first_start_time", firstStartTimeQuery), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format") + } + firstStartTime = domain.ValidTime{ + Value: firstStartTimeParsed, + Valid: true, + } + } + + lastStartTimeQuery := c.Query("last_start_time") + var lastStartTime domain.ValidTime + if lastStartTimeQuery != "" { + lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery) + if err != nil { + h.BadRequestLogger().Info("invalid last_start_time format", + zap.String("last_start_time", lastStartTimeQuery), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format") + } + lastStartTime = domain.ValidTime{ + Value: lastStartTimeParsed, + Valid: true, + } + } + + countryCodeQuery := c.Query("cc") + countryCode := domain.ValidString{ + Value: countryCodeQuery, + Valid: countryCodeQuery != "", + } + + isFeaturedQuery := c.Query("is_featured") + var isFeatured domain.ValidBool + if isFeaturedQuery != "" { + isFeaturedParsed, err := strconv.ParseBool(isFeaturedQuery) + if err != nil { + h.BadRequestLogger().Error("Failed to parse isFeatured", + zap.String("is_featured", isFeaturedQuery), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_featured") + } + + isFeatured = domain.ValidBool{ + Value: isFeaturedParsed, + Valid: true, + } + } + + isActiveQuery := c.Query("is_active") + var isActive domain.ValidBool + if isActiveQuery != "" { + isActiveParsed, err := strconv.ParseBool(isActiveQuery) + if err != nil { + h.BadRequestLogger().Error("Failed to parse isActive", + zap.String("is_active", isActiveQuery), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_active") + } + + isActive = domain.ValidBool{ + Value: isActiveParsed, + Valid: true, + } + } + + statusQuery := c.Query("status") + var eventStatus domain.ValidEventStatus + if statusQuery != "" { + eventStatusParsed, err := domain.ParseEventStatus(statusQuery) + if err != nil { + h.BadRequestLogger().Error("Failed to parse statusQuery", + zap.String("is_featured", isFeaturedQuery), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, "invalid event status string") + } + eventStatus = domain.ValidEventStatus{ + Value: eventStatusParsed, + Valid: true, + } + } + + events, total, err := h.eventSvc.GetEventsWithSettings( + c.Context(), companyID.Value, domain.EventFilter{ + SportID: sportID, + LeagueID: leagueID, + Query: searchString, + FirstStartTime: firstStartTime, + LastStartTime: lastStartTime, + Limit: limit, + Offset: offset, + CountryCode: countryCode, + Featured: isFeatured, + Status: eventStatus, + Active: isActive, + }) + + // fmt.Printf("League ID: %v", leagueID) + if err != nil { + h.InternalServerErrorLogger().Error("Failed to retrieve all upcoming events", + zap.Error(err), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + + res := domain.ConvertEventWithSettingResList(events) + + return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", res, nil, page, int(total)) + +} + type TopLeaguesRes struct { Leagues []TopLeague `json:"leagues"` } @@ -483,6 +713,145 @@ func (h *Handler) GetTenantEventByID(c *fiber.Ctx) error { } +// @Summary Retrieve bet outcomes by event id +// @Description Retrieve bet outcomes by event id +// @Tags prematch +// @Accept json +// @Produce json +// @Param id path string true "ID" +// @Success 200 {object} domain.BaseEvent +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/tenant/{tenant_slug}/events/{id}/bets [get] +func (h *Handler) GetTenantBetsByEventID(c *fiber.Ctx) error { + companyID := c.Locals("company_id").(domain.ValidInt64) + if !companyID.Valid { + h.BadRequestLogger().Error("invalid company id") + return fiber.NewError(fiber.StatusBadRequest, "invalid company id") + } + + idStr := c.Params("id") + eventID, err := strconv.ParseInt(idStr, 10, 64) + if err != nil { + h.BadRequestLogger().Info("Failed to parse event id", zap.String("id", idStr)) + return fiber.NewError(fiber.StatusBadRequest, "Missing id") + } + + page := c.QueryInt("page", 1) + pageSize := c.QueryInt("page_size", 10) + limit := domain.ValidInt32{ + Value: int32(pageSize), + Valid: true, + } + offset := domain.ValidInt32{ + Value: int32(page - 1), + Valid: true, + } + + statusQuery := c.Params("status") + var status domain.ValidOutcomeStatus + if statusQuery != "" { + statusIntParse, err := strconv.ParseInt(statusQuery, 10, 32) + if err != nil { + h.BadRequestLogger().Info("Failed to parse status", zap.String("status", statusQuery)) + return fiber.NewError(fiber.StatusBadRequest, "Invalid status query") + } + + statusParsed, err := domain.ParseOutcomeStatus(int(statusIntParse)) + if err != nil { + h.BadRequestLogger().Info("Failed to parse status", zap.String("status", statusQuery)) + return fiber.NewError(fiber.StatusBadRequest, "Invalid status query") + } + + status = domain.ValidOutcomeStatus{ + Value: statusParsed, + Valid: true, + } + } + + res, total, err := h.betSvc.GetBetOutcomeViewByEventID(c.Context(), eventID, domain.BetOutcomeViewFilter{ + OutcomeStatus: status, + CompanyID: companyID, + Limit: limit, + Offset: offset, + }) + + if err != nil { + h.InternalServerErrorLogger().Error("Failed to get upcoming event by id", + zap.Int64("eventID", eventID), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + return response.WritePaginatedJSON(c, fiber.StatusOK, "Bet Outcomes retrieved successfully", res, nil, page, int(total)) +} + +// @Summary Retrieve bet outcomes by event id +// @Description Retrieve bet outcomes by event id +// @Tags prematch +// @Accept json +// @Produce json +// @Param id path string true "ID" +// @Success 200 {object} domain.BaseEvent +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/events/{id}/bets [get] +func (h *Handler) GetBetsByEventID(c *fiber.Ctx) error { + idStr := c.Params("id") + eventID, err := strconv.ParseInt(idStr, 10, 64) + if err != nil { + h.BadRequestLogger().Info("Failed to parse event id", zap.String("id", idStr)) + return fiber.NewError(fiber.StatusBadRequest, "Missing id") + } + + page := c.QueryInt("page", 1) + pageSize := c.QueryInt("page_size", 10) + limit := domain.ValidInt32{ + Value: int32(pageSize), + Valid: true, + } + offset := domain.ValidInt32{ + Value: int32(page - 1), + Valid: true, + } + + statusQuery := c.Params("status") + var status domain.ValidOutcomeStatus + if statusQuery != "" { + statusIntParse, err := strconv.ParseInt(statusQuery, 10, 32) + if err != nil { + h.BadRequestLogger().Info("Failed to parse status", zap.String("status", statusQuery)) + return fiber.NewError(fiber.StatusBadRequest, "Invalid status query") + } + + statusParsed, err := domain.ParseOutcomeStatus(int(statusIntParse)) + if err != nil { + h.BadRequestLogger().Info("Failed to parse status", zap.String("status", statusQuery)) + return fiber.NewError(fiber.StatusBadRequest, "Invalid status query") + } + + status = domain.ValidOutcomeStatus{ + Value: statusParsed, + Valid: true, + } + } + + res, total, err := h.betSvc.GetBetOutcomeViewByEventID(c.Context(), eventID, domain.BetOutcomeViewFilter{ + OutcomeStatus: status, + Limit: limit, + Offset: offset, + }) + + if err != nil { + h.InternalServerErrorLogger().Error("Failed to get upcoming event by id", + zap.Int64("eventID", eventID), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + return response.WritePaginatedJSON(c, fiber.StatusOK, "Bet Outcomes retrieved successfully", res, nil, page, int(total)) +} + type UpdateEventStatusReq struct { } @@ -519,9 +888,9 @@ func (h *Handler) SetEventStatusToRemoved(c *fiber.Ctx) error { } type UpdateEventSettingsReq struct { - Featured *bool `json:"is_featured" example:"true"` - IsActive *bool `json:"is_active" example:"true"` - WinningUpperLimit *int `json:"winning_upper_limit" example:"10000"` + Featured *bool `json:"is_featured" example:"true"` + IsActive *bool `json:"is_active" example:"true"` + WinningUpperLimit *int64 `json:"winning_upper_limit" example:"10000"` } // UpdateEventSettings godoc @@ -534,8 +903,72 @@ type UpdateEventSettingsReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /api/v1/tenant/{tenant_slug}/events/{id}/settings [put] +// @Router /api/v1/events/{id}/settings [put] func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error { + eventIDStr := c.Params("id") + + eventID, err := strconv.ParseInt(eventIDStr, 10, 64) + if err != nil { + h.BadRequestLogger().Error("invalid event id") + return fiber.NewError(fiber.StatusBadRequest, "invalid event id") + } + + var req UpdateEventSettingsReq + + if err := c.BodyParser(&req); err != nil { + h.BadRequestLogger().Info("Failed to parse event id", + zap.Int64("eventID", eventID), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + logFields := []zap.Field{ + zap.Int64("eventID", eventID), + zap.Any("is_featured", req.Featured), + zap.Any("is_active", req.IsActive), + zap.Any("winning_upper_limit", req.WinningUpperLimit), + } + valErrs, ok := h.validator.Validate(c, req) + if !ok { + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.BadRequestLogger().Error("Failed to update event settings", + append(logFields, zap.String("errMsg", errMsg))..., + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) + } + + err = h.eventSvc.UpdateGlobalEventSettings(c.Context(), domain.UpdateGlobalEventSettings{ + EventID: eventID, + IsFeatured: domain.ConvertBoolPtr(req.Featured), + IsActive: domain.ConvertBoolPtr(req.IsActive), + WinningUpperLimit: domain.ConvertInt64Ptr(req.WinningUpperLimit), + }) + + if err != nil { + h.InternalServerErrorLogger().Error("Failed to update event settings", append(logFields, zap.Error(err))...) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + + return response.WriteJSON(c, fiber.StatusOK, "Event updated successfully", nil, nil) + +} + +// UpdateTenantEventSettings godoc +// @Summary update the event settings +// @Description Update the event settings +// @Tags event +// @Accept json +// @Produce json +// @Param id path int true "Event ID" +// @Success 200 {object} response.APIResponse +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/tenant/{tenant_slug}/events/{id}/settings [put] +func (h *Handler) UpdateTenantEventSettings(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { h.BadRequestLogger().Error("invalid company id") @@ -579,12 +1012,12 @@ func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, errMsg) } - err = h.eventSvc.UpdateEventSettings(c.Context(), domain.CreateEventSettings{ + err = h.eventSvc.UpdateTenantEventSettings(c.Context(), domain.UpdateTenantEventSettings{ CompanyID: companyID.Value, EventID: eventID, IsFeatured: domain.ConvertBoolPtr(req.Featured), IsActive: domain.ConvertBoolPtr(req.IsActive), - WinningUpperLimit: domain.ConvertIntPtr(req.WinningUpperLimit), + WinningUpperLimit: domain.ConvertInt64Ptr(req.WinningUpperLimit), }) if err != nil { diff --git a/internal/web_server/handlers/leagues.go b/internal/web_server/handlers/leagues.go index 73abbf8..08c15a9 100644 --- a/internal/web_server/handlers/leagues.go +++ b/internal/web_server/handlers/leagues.go @@ -26,7 +26,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { limit := domain.ValidInt64{ Value: int64(pageSize), - Valid: pageSize == 0, + Valid: pageSize != 0, } offset := domain.ValidInt64{ Value: int64(page - 1), @@ -54,7 +54,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { sportIDQuery := c.Query("sport_id") var sportID domain.ValidInt32 if sportIDQuery != "" { - sportIDint, err := strconv.Atoi(sportIDQuery) + sportIDint, err := strconv.ParseInt(sportIDQuery, 10, 64) if err != nil { h.BadRequestLogger().Info("invalid sport id", zap.String("sport_id", sportIDQuery), @@ -156,7 +156,7 @@ func (h *Handler) GetAllLeaguesForTenant(c *fiber.Ctx) error { sportIDQuery := c.Query("sport_id") var sportID domain.ValidInt32 if sportIDQuery != "" { - sportIDint, err := strconv.Atoi(sportIDQuery) + sportIDint, err := strconv.ParseInt(sportIDQuery, 10, 64) if err != nil { h.BadRequestLogger().Info("invalid sport id", zap.String("sport_id", sportIDQuery), @@ -235,7 +235,7 @@ func (h *Handler) SetLeagueActive(c *fiber.Ctx) error { if leagueIdStr == "" { return fiber.NewError(fiber.StatusBadRequest, "Missing league id") } - leagueId, err := strconv.Atoi(leagueIdStr) + leagueId, err := strconv.ParseInt(leagueIdStr, 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "invalid league id") } @@ -266,7 +266,7 @@ func (h *Handler) SetLeagueActive(c *fiber.Ctx) error { } if err := h.leagueSvc.SaveLeagueSettings(c.Context(), domain.CreateLeagueSettings{ - LeagueID: int64(leagueId), + LeagueID: leagueId, CompanyID: companyID.Value, IsActive: domain.ValidBool{ Value: req.IsActive, @@ -308,7 +308,7 @@ func (h *Handler) SetLeagueFeatured(c *fiber.Ctx) error { if leagueIdStr == "" { return fiber.NewError(fiber.StatusBadRequest, "Missing league id") } - leagueId, err := strconv.Atoi(leagueIdStr) + leagueId, err := strconv.ParseInt(leagueIdStr, 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "invalid league id") } @@ -336,7 +336,7 @@ func (h *Handler) SetLeagueFeatured(c *fiber.Ctx) error { } err = h.leagueSvc.SaveLeagueSettings(c.Context(), domain.CreateLeagueSettings{ - LeagueID: int64(leagueId), + LeagueID: leagueId, CompanyID: companyID.Value, IsFeatured: domain.ValidBool{ Value: req.IsFeatured, @@ -351,3 +351,45 @@ func (h *Handler) SetLeagueFeatured(c *fiber.Ctx) error { h.SuccessResLogger().Info("League Featured has been successfully updated", queryLogFields...) return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil) } + +func (h *Handler) UpdateGlobalLeagueSetting(c *fiber.Ctx) error { + leagueIdStr := c.Params("id") + if leagueIdStr == "" { + return fiber.NewError(fiber.StatusBadRequest, "Missing league id") + } + leagueId, err := strconv.ParseInt(leagueIdStr, 10, 64) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, "invalid league id") + } + + var req domain.UpdateLeagueSettingsReq + + if err := c.BodyParser(&req); err != nil { + h.BadRequestLogger().Info("UpdateLeagueSettingsReq failed to parse request body", zap.String("league_id", leagueIdStr), zap.Error(err)) + return fiber.NewError(fiber.StatusBadRequest, "Failed to parse request body:"+err.Error()) + } + + valErrs, ok := h.validator.Validate(c, req) + if !ok { + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.BadRequestLogger().Info("Failed to validate UpdateLeagueSettingsReq", zap.Error(err)) + return fiber.NewError(fiber.StatusBadRequest, errMsg) + + } + + err = h.leagueSvc.UpdateGlobalLeagueSettings(c.Context(), domain.UpdateGlobalLeagueSettings{ + ID: leagueId, + DefaultIsActive: domain.ConvertBoolPtr(req.IsActive), + DefaultIsFeatured: domain.ConvertBoolPtr(req.IsFeatured), + }) + + if err != nil { + h.InternalServerErrorLogger().Error("Failed to update league", zap.Error(err), zap.String("leagueId", leagueIdStr)) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to update league:"+err.Error()) + } + return response.WriteJSON(c, fiber.StatusOK, "League updated successfully", nil, nil) + +} diff --git a/internal/web_server/handlers/odd_handler.go b/internal/web_server/handlers/odd_handler.go index ec4ec59..8c6457a 100644 --- a/internal/web_server/handlers/odd_handler.go +++ b/internal/web_server/handlers/odd_handler.go @@ -276,7 +276,6 @@ func (h *Handler) GetTenantOddsByUpcomingID(c *fiber.Ctx) error { zap.Int64("company_id", companyID.Value), } - eventIDStr := c.Params("upcoming_id") eventID, err := strconv.ParseInt(eventIDStr, 10, 64) if err != nil { @@ -309,16 +308,16 @@ func (h *Handler) GetTenantOddsByUpcomingID(c *fiber.Ctx) error { } -func (h *Handler) SaveOddsSetting(c *fiber.Ctx) error { +func (h *Handler) SaveTenantOddsSetting(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { h.BadRequestLogger().Error("invalid company id") return fiber.NewError(fiber.StatusBadRequest, "invalid company id") } - var req domain.CreateOddMarketSettingsReq + var req domain.CreateOddMarketSettingsReq if err := c.BodyParser(&req); err != nil { - h.BadRequestLogger().Info("Failed to parse event id", + h.BadRequestLogger().Info("Failed to parse CreateOddMarketSettingsReq", zap.Int64("CompanyID", companyID.Value), zap.Error(err), ) @@ -337,7 +336,7 @@ func (h *Handler) SaveOddsSetting(c *fiber.Ctx) error { for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } - h.BadRequestLogger().Error("Failed to insert odd settings", + h.BadRequestLogger().Error("Failed to validate insert odd settings", append(logFields, zap.String("errMsg", errMsg))..., ) return fiber.NewError(fiber.StatusBadRequest, errMsg) @@ -354,3 +353,133 @@ func (h *Handler) SaveOddsSetting(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusOK, "Odds Settings saved successfully", nil, nil) } + +func (h *Handler) SaveOddSettings(c *fiber.Ctx) error { + var req domain.UpdateGlobalOddMarketSettingsReq + + if err := c.BodyParser(&req); err != nil { + h.BadRequestLogger().Info("Failed to parse CreateOddMarketSettingsReq", + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + logFields := []zap.Field{ + zap.Any("is_active", req.IsActive), + } + + valErrs, ok := h.validator.Validate(c, req) + if !ok { + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.BadRequestLogger().Error("Failed to validate insert odd settings", + append(logFields, zap.String("errMsg", errMsg))..., + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) + } + + err := h.prematchSvc.UpdateGlobalOddsSetting(c.Context(), domain.UpdateGlobalOddMarketSettings{ + OddMarketID: req.OddMarketID, + IsActive: domain.ConvertBoolPtr(req.IsActive), + }) + + if err != nil { + logFields = append(logFields, zap.Error(err)) + h.InternalServerErrorLogger().Error("Failed to save odds settings", append(logFields, zap.Error(err))...) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to save odds settings"+err.Error()) + } + + return response.WriteJSON(c, fiber.StatusOK, "Odds Settings saved successfully", nil, nil) +} + +func (h *Handler) RemoveOddsSettings(c *fiber.Ctx) error { + companyID := c.Locals("company_id").(domain.ValidInt64) + if !companyID.Valid { + h.BadRequestLogger().Error("invalid company id") + return fiber.NewError(fiber.StatusBadRequest, "invalid company id") + } + + idStr := c.Params("id") + oddID, err := strconv.ParseInt(idStr, 10, 64) + if err != nil { + h.BadRequestLogger().Info("Failed to parse odd id", zap.String("id", idStr)) + return fiber.NewError(fiber.StatusBadRequest, "Missing id") + } + + err = h.prematchSvc.DeleteCompanyOddsSettingByOddMarketID(c.Context(), companyID.Value, oddID) + + if err != nil { + h.InternalServerErrorLogger().Error("Failed to retrieve odds", zap.Error(err)) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove odds settings"+err.Error()) + } + + return response.WriteJSON(c, fiber.StatusOK, "Odds settings successfully removed ", nil, nil) +} +func (h *Handler) RemoveAllOddsSettings(c *fiber.Ctx) error { + companyID := c.Locals("company_id").(domain.ValidInt64) + if !companyID.Valid { + h.BadRequestLogger().Error("invalid company id") + return fiber.NewError(fiber.StatusBadRequest, "invalid company id") + } + + err := h.prematchSvc.DeleteAllCompanyOddsSetting(c.Context(), companyID.Value) + + if err != nil { + h.InternalServerErrorLogger().Error("Failed to remove all odd settings", zap.Int64("company_id", companyID.Value), zap.Error(err)) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to remove all odds settings"+err.Error()) + } + + return response.WriteJSON(c, fiber.StatusOK, "Odds settings successfully removed ", nil, nil) +} + +type UpdateAllBetStatusByOddIDReq struct { + Status domain.OutcomeStatus `json:"status"` +} + +func (h *Handler) UpdateAllBetOutcomeStatusByOddID(c *fiber.Ctx) error { + + idStr := c.Params("id") + oddID, err := strconv.ParseInt(idStr, 10, 64) + if err != nil { + h.BadRequestLogger().Info("Failed to parse odd_id", zap.String("id", idStr)) + return fiber.NewError(fiber.StatusBadRequest, "Missing id") + } + + var req UpdateAllBetStatusByOddIDReq + if err := c.BodyParser(&req); err != nil { + h.BadRequestLogger().Info("Failed to parse event id", + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + logFields := []zap.Field{ + zap.Any("status", req.Status), + } + + valErrs, ok := h.validator.Validate(c, req) + if !ok { + var errMsg string + for field, msg := range valErrs { + errMsg += fmt.Sprintf("%s: %s; ", field, msg) + } + h.BadRequestLogger().Error("Failed to insert odd settings", + append(logFields, zap.String("errMsg", errMsg))..., + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) + } + + _, err = h.betSvc.UpdateBetOutcomeStatusForOddId(c.Context(), oddID, req.Status) + + if err != nil { + h.InternalServerErrorLogger().Error("Failed to update bet status by odd id", + zap.Int64("oddID", oddID), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusInternalServerError, err.Error()) + } + + return response.WriteJSON(c, fiber.StatusOK, "Updated All Bet Outcome Status Successfully", nil, nil) +} diff --git a/internal/web_server/handlers/user.go b/internal/web_server/handlers/user.go index a6ff298..fe89de9 100644 --- a/internal/web_server/handlers/user.go +++ b/internal/web_server/handlers/user.go @@ -14,6 +14,74 @@ import ( "go.uber.org/zap" ) +type GetTenantSlugByToken struct { + Slug string `json:"slug"` +} + +// GetTenantSlugByToken godoc +// @Summary Check if phone number or email exist +// @Description Check if phone number or email exist +// @Tags user +// @Accept json +// @Produce json +// @Param checkPhoneEmailExist body CheckPhoneEmailExistReq true "Check phone number or email exist" +// @Success 200 {object} CheckPhoneEmailExistRes +// @Failure 400 {object} response.APIResponse +// @Failure 500 {object} response.APIResponse +// @Router /api/v1/tenant [get] +func (h *Handler) GetTenantSlugByToken(c *fiber.Ctx) error { + userID, ok := c.Locals("user_id").(int64) + if !ok || userID == 0 { + h.mongoLoggerSvc.Error("Invalid user ID in context", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Invalid user identification") + } + + user, err := h.userSvc.GetUserByID(c.Context(), userID) + if err != nil { + h.mongoLoggerSvc.Error("Failed to get user profile", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve user profile:"+err.Error()) + } + + if !user.CompanyID.Valid { + if user.Role == domain.RoleSuperAdmin { + return fiber.NewError(fiber.StatusBadRequest, "Role Super-Admin Doesn't have a company-id") + } + h.mongoLoggerSvc.Error("Unknown Error: User doesn't have a company-id", + zap.Int64("userID", userID), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Unknown Error: User doesn't have a company-id") + } + company, err := h.companySvc.GetCompanyByID(c.Context(), user.CompanyID.Value) + + if err != nil { + h.mongoLoggerSvc.Error("Failed to get company by id", + zap.Int64("company", user.CompanyID.Value), + zap.Int("status_code", fiber.StatusInternalServerError), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve company:"+err.Error()) + } + + res := GetTenantSlugByToken{ + Slug: company.Slug, + } + + return response.WriteJSON(c, fiber.StatusOK, "Tenant Slug retrieved successfully", res, nil) +} + type CheckPhoneEmailExistReq struct { Email string `json:"email" example:"john.doe@example.com"` PhoneNumber string `json:"phone_number" example:"1234567890"` diff --git a/internal/web_server/middleware.go b/internal/web_server/middleware.go index 68d4889..179cf59 100644 --- a/internal/web_server/middleware.go +++ b/internal/web_server/middleware.go @@ -236,7 +236,7 @@ func (a *App) TenantMiddleware(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "tenant is required for this route") } - companyID, err := a.companySvc.GetCompanyIDBySlug(c.Context(), tenantSlug) + company, err := a.companySvc.GetCompanyBySlug(c.Context(), tenantSlug) if err != nil { a.mongoLoggerSvc.Info("failed to resolve tenant", zap.String("tenant_slug", tenantSlug), @@ -245,8 +245,16 @@ func (a *App) TenantMiddleware(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "failed to resolve tenant") } + if !company.IsActive { + a.mongoLoggerSvc.Info("request using deactivated tenant", + zap.String("tenant_slug", tenantSlug), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusForbidden, "this tenant has been deactivated") + } + c.Locals("company_id", domain.ValidInt64{ - Value: companyID, + Value: company.ID, Valid: true, }) return c.Next() diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 6b3dedc..05aede1 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -96,6 +96,10 @@ func (a *App) initAppRoutes() { "message": "Company Tenant Active", }) }) + + // Get S + groupV1.Get("/tenant", a.authMiddleware, h.GetTenantSlugByToken) + //Direct_deposit groupV1.Post("/direct_deposit", a.authMiddleware, h.InitiateDirectDeposit) groupV1.Post("/direct_deposit/verify", a.authMiddleware, h.VerifyDirectDeposit) @@ -219,55 +223,63 @@ func (a *App) initAppRoutes() { // groupV1.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier) // groupV1.Put("/bonus/update", a.authMiddleware, h.UpdateBonusMultiplier) - groupV1.Get("/cashiers", a.authMiddleware, h.GetAllCashiers) - groupV1.Get("/cashiers/:id", a.authMiddleware, h.GetCashierByID) - groupV1.Post("/cashiers", a.authMiddleware, h.CreateCashier) - groupV1.Put("/cashiers/:id", a.authMiddleware, h.UpdateCashier) + groupV1.Get("/cashiers", a.authMiddleware, a.CompanyOnly, h.GetAllCashiers) + groupV1.Get("/cashiers/:id", a.authMiddleware, a.CompanyOnly, h.GetCashierByID) + groupV1.Post("/cashiers", a.authMiddleware, a.CompanyOnly, h.CreateCashier) + groupV1.Put("/cashiers/:id", a.authMiddleware, a.CompanyOnly, h.UpdateCashier) - tenant.Get("/customer", a.authMiddleware, h.GetAllTenantCustomers) - tenant.Get("/customer/:id", a.authMiddleware, h.GetTenantCustomerByID) - tenant.Put("/customer/:id", a.authMiddleware, h.UpdateTenantCustomer) - tenant.Get("/customer/:id/bets", a.authMiddleware, h.GetTenantCustomerBets) + tenant.Get("/customer", a.authMiddleware, a.CompanyOnly, h.GetAllTenantCustomers) + tenant.Get("/customer/:id", a.authMiddleware, a.CompanyOnly, h.GetTenantCustomerByID) + tenant.Put("/customer/:id", a.authMiddleware, a.CompanyOnly, h.UpdateTenantCustomer) + tenant.Get("/customer/:id/bets", a.authMiddleware, a.CompanyOnly, h.GetTenantCustomerBets) groupV1.Get("/customer", a.authMiddleware, a.SuperAdminOnly, h.GetAllCustomers) groupV1.Get("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCustomerByID) groupV1.Put("/customer/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCustomer) groupV1.Get("/customer/:id/bets", a.authMiddleware, h.GetCustomerBets) - groupV1.Get("/admin", a.authMiddleware, h.GetAllAdmins) - groupV1.Get("/admin/:id", a.authMiddleware, h.GetAdminByID) - groupV1.Post("/admin", a.authMiddleware, h.CreateAdmin) - groupV1.Put("/admin/:id", a.authMiddleware, h.UpdateAdmin) + groupV1.Get("/admin", a.authMiddleware, a.SuperAdminOnly, h.GetAllAdmins) + groupV1.Get("/admin/:id", a.authMiddleware, a.SuperAdminOnly, h.GetAdminByID) + groupV1.Post("/admin", a.authMiddleware, a.SuperAdminOnly, h.CreateAdmin) + groupV1.Put("/admin/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateAdmin) - groupV1.Get("/t-approver", a.authMiddleware, h.GetAllTransactionApprovers) - groupV1.Get("/t-approver/:id", a.authMiddleware, h.GetTransactionApproverByID) - groupV1.Post("/t-approver", a.authMiddleware, h.CreateTransactionApprover) - groupV1.Put("/t-approver/:id", a.authMiddleware, h.UpdateTransactionApprover) + groupV1.Get("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllTransactionApprovers) + groupV1.Get("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.GetTransactionApproverByID) + groupV1.Post("/t-approver", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateTransactionApprover) + groupV1.Put("/t-approver/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateTransactionApprover) - groupV1.Get("/managers", a.authMiddleware, h.GetAllManagers) + groupV1.Get("/managers", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllManagers) groupV1.Get("/managers/:id", a.authMiddleware, h.GetManagerByID) - groupV1.Post("/managers", a.authMiddleware, h.CreateManager) - groupV1.Put("/managers/:id", a.authMiddleware, h.UpdateManagers) - groupV1.Get("/manager/:id/branch", a.authMiddleware, h.GetBranchByManagerID) + groupV1.Post("/managers", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateManager) + groupV1.Put("/managers/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.UpdateManagers) + groupV1.Get("/manager/:id/branch", a.authMiddleware, a.OnlyAdminAndAbove, h.GetBranchByManagerID) groupV1.Get("/odds", a.authMiddleware, a.SuperAdminOnly, h.GetAllOdds) groupV1.Get("/odds/upcoming/:upcoming_id", a.authMiddleware, a.SuperAdminOnly, h.GetOddsByUpcomingID) groupV1.Get("/odds/upcoming/:upcoming_id/market/:market_id", a.authMiddleware, a.SuperAdminOnly, h.GetOddsByMarketID) + groupV1.Post("/odds/settings", a.SuperAdminOnly, h.SaveOddSettings) + groupV1.Put("/odds/bet-outcome/:id", a.SuperAdminOnly, h.UpdateAllBetOutcomeStatusByOddID) tenant.Get("/odds", h.GetAllTenantOdds) tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID) tenant.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetTenantOddsByMarketID) - tenant.Post("/odds/settings", a.CompanyOnly, h.SaveOddsSetting) + tenant.Post("/odds/settings", a.CompanyOnly, h.SaveTenantOddsSetting) + tenant.Delete("/odds/settings/:id", a.CompanyOnly, h.RemoveOddsSettings) + tenant.Delete("/odds/settings", a.CompanyOnly, h.RemoveAllOddsSettings) groupV1.Get("/events", a.authMiddleware, h.GetAllEvents) groupV1.Get("/events/:id", a.authMiddleware, h.GetEventByID) groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved) groupV1.Patch("/events/:id/is_monitored", a.authMiddleware, a.SuperAdminOnly, h.SetEventIsMonitored) + groupV1.Put("/events/:id/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList) + groupV1.Get("/events/:id/bets", a.authMiddleware, a.SuperAdminOnly, h.GetBetsByEventID) tenant.Get("/upcoming-events", h.GetTenantUpcomingEvents) - tenant.Get("/events/:id", h.GetTenantEventByID) tenant.Get("/top-leagues", h.GetTopLeagues) - tenant.Put("/events/:id/settings", h.UpdateEventSettings) + tenant.Get("/events", h.GetTenantEvents) + tenant.Get("/events/:id", h.GetTenantEventByID) + tenant.Put("/events/:id/settings", a.authMiddleware, a.CompanyOnly, h.UpdateTenantEventSettings) + tenant.Get("/events/:id/bets", a.authMiddleware, a.CompanyOnly, h.GetTenantBetsByEventID) //EnetPulse groupV1.Get("/odds/pre-match", h.GetPreMatchOdds) @@ -277,38 +289,40 @@ func (a *App) initAppRoutes() { groupV1.Get("/tournament_stages", h.GetAllTournamentStages) // Leagues - tenant.Get("/leagues", h.GetAllLeagues) - tenant.Put("/leagues/:id/set-active", h.SetLeagueActive) - tenant.Put("/leagues/:id/featured", h.SetLeagueFeatured) groupV1.Get("/leagues", a.authMiddleware, a.SuperAdminOnly, h.GetAllLeagues) + groupV1.Put("/leagues/:id/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalLeagueSetting) + + tenant.Get("/leagues", h.GetAllLeagues) + tenant.Put("/leagues/:id/featured", a.authMiddleware, a.CompanyOnly, h.SetLeagueFeatured) + tenant.Put("/leagues/:id/set-active", a.authMiddleware, a.CompanyOnly, h.SetLeagueActive) groupV1.Get("/result/b365/:id", h.GetBet365ResultsByEventID) // Branch - groupV1.Post("/branch", a.authMiddleware, h.CreateBranch) - groupV1.Get("/branch", a.authMiddleware, h.GetAllBranches) - groupV1.Get("/branch/:id", a.authMiddleware, h.GetBranchByID) - groupV1.Post("/branch/:id/return", a.authMiddleware, h.ReturnBranchWallet) - groupV1.Get("/branch/:id/bets", a.authMiddleware, h.GetBetByBranchID) - groupV1.Put("/branch/:id", a.authMiddleware, h.UpdateBranch) - groupV1.Put("/branch/:id/set-active", a.authMiddleware, h.UpdateBranchStatus) - groupV1.Put("/branch/:id/set-inactive", a.authMiddleware, h.UpdateBranchStatus) - groupV1.Delete("/branch/:id", a.authMiddleware, h.DeleteBranch) + groupV1.Post("/branch", a.authMiddleware, a.CompanyOnly, h.CreateBranch) + groupV1.Get("/branch", a.authMiddleware, a.CompanyOnly, h.GetAllBranches) + groupV1.Get("/branch/:id", a.authMiddleware, a.CompanyOnly, h.GetBranchByID) + groupV1.Post("/branch/:id/return", a.authMiddleware, a.CompanyOnly, h.ReturnBranchWallet) + groupV1.Get("/branch/:id/bets", a.authMiddleware, a.CompanyOnly, h.GetBetByBranchID) + groupV1.Put("/branch/:id", a.authMiddleware, a.CompanyOnly, h.UpdateBranch) + groupV1.Put("/branch/:id/set-active", a.authMiddleware, a.CompanyOnly, h.UpdateBranchStatus) + groupV1.Put("/branch/:id/set-inactive", a.authMiddleware, a.CompanyOnly, h.UpdateBranchStatus) + groupV1.Delete("/branch/:id", a.authMiddleware, a.CompanyOnly, h.DeleteBranch) - groupV1.Get("/search/branch", a.authMiddleware, h.SearchBranch) + groupV1.Get("/search/branch", a.authMiddleware, a.CompanyOnly, h.SearchBranch) - groupV1.Get("/branchLocation", a.authMiddleware, h.GetAllBranchLocations) + groupV1.Get("/branchLocation", a.authMiddleware, a.CompanyOnly, h.GetAllBranchLocations) - groupV1.Get("/branch/:id/cashiers", a.authMiddleware, h.GetBranchCashiers) - groupV1.Get("/branchCashier", a.authMiddleware, h.GetBranchForCashier) + groupV1.Get("/branch/:id/cashiers", a.authMiddleware, a.CompanyOnly, h.GetBranchCashiers) + groupV1.Get("/branchCashier", a.authMiddleware, a.CompanyOnly, h.GetBranchForCashier) // Branch Operation groupV1.Get("/supportedOperation", a.authMiddleware, a.SuperAdminOnly, h.GetAllSupportedOperations) groupV1.Post("/supportedOperation", a.authMiddleware, a.SuperAdminOnly, h.CreateSupportedOperation) - groupV1.Post("/operation", a.authMiddleware, h.CreateBranchOperation) - groupV1.Get("/branch/:id/operation", a.authMiddleware, h.GetBranchOperations) + groupV1.Post("/operation", a.authMiddleware, a.CompanyOnly, h.CreateBranchOperation) + groupV1.Get("/branch/:id/operation", a.authMiddleware, a.CompanyOnly, h.GetBranchOperations) - groupV1.Delete("/branch/:id/operation/:opID", a.authMiddleware, h.DeleteBranchOperation) + groupV1.Delete("/branch/:id/operation/:opID", a.authMiddleware, a.CompanyOnly, h.DeleteBranchOperation) // Company groupV1.Post("/company", a.authMiddleware, a.SuperAdminOnly, h.CreateCompany) @@ -316,9 +330,9 @@ func (a *App) initAppRoutes() { groupV1.Get("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.GetCompanyByID) groupV1.Put("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.UpdateCompany) groupV1.Delete("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.DeleteCompany) - groupV1.Get("/company/:id/branch", a.authMiddleware, h.GetBranchByCompanyID) - groupV1.Get("/search/company", a.authMiddleware, h.SearchCompany) - groupV1.Get("/admin-company", a.authMiddleware, h.GetCompanyForAdmin) + groupV1.Get("/company/:id/branch", a.authMiddleware, a.CompanyOnly, h.GetBranchByCompanyID) + groupV1.Get("/search/company", a.authMiddleware, a.CompanyOnly, h.SearchCompany) + groupV1.Get("/admin-company", a.authMiddleware, a.CompanyOnly, h.GetCompanyForAdmin) // Ticket Routes tenant.Post("/ticket", h.CreateTicket) @@ -329,7 +343,7 @@ func (a *App) initAppRoutes() { tenant.Post("/sport/bet", a.authMiddleware, h.CreateBet) tenant.Post("/sport/bet/fastcode", a.authMiddleware, h.CreateBetWithFastCode) tenant.Get("/sport/bet/fastcode/:fast_code", h.GetBetByFastCode) - tenant.Get("/sport/bet", a.authMiddleware, h.GetAllTenantBets) + tenant.Get("/sport/bet", a.authMiddleware, a.CompanyOnly, h.GetAllTenantBets) tenant.Get("/sport/bet/:id", a.authMiddleware, h.GetTenantBetByID) tenant.Patch("/sport/bet/:id", a.authMiddleware, h.UpdateCashOut) tenant.Delete("/sport/bet/:id", a.authMiddleware, h.DeleteTenantBet) @@ -458,9 +472,9 @@ func (a *App) initAppRoutes() { groupV1.Get("/settings/:key", a.authMiddleware, a.SuperAdminOnly, h.GetGlobalSettingByKey) groupV1.Put("/settings", a.authMiddleware, a.SuperAdminOnly, h.UpdateGlobalSettingList) - tenant.Get("/settings", a.authMiddleware, h.GetCompanySettingList) - tenant.Put("/settings", a.authMiddleware, h.SaveCompanySettingList) - tenant.Delete("/settings/:key", a.authMiddleware, h.DeleteCompanySetting) - tenant.Delete("/settings", a.authMiddleware, h.DeleteAllCompanySetting) + tenant.Get("/settings", a.authMiddleware, a.OnlyAdminAndAbove, h.GetCompanySettingList) + tenant.Put("/settings", a.authMiddleware, a.OnlyAdminAndAbove, h.SaveCompanySettingList) + tenant.Delete("/settings/:key", a.authMiddleware, a.OnlyAdminAndAbove, h.DeleteCompanySetting) + tenant.Delete("/settings", a.authMiddleware, a.OnlyAdminAndAbove, h.DeleteAllCompanySetting) }