diff --git a/db/query/events.sql b/db/query/events.sql index 1a61445..82c7ed8 100644 --- a/db/query/events.sql +++ b/db/query/events.sql @@ -54,7 +54,7 @@ SET sport_id = EXCLUDED.sport_id, is_live = EXCLUDED.is_live, source = EXCLUDED.source, fetched_at = now(); --- name: InsertEventSettings :exec +-- name: SaveEventSettings :exec INSERT INTO company_event_settings ( company_id, event_id, @@ -243,19 +243,7 @@ WHERE id = $1; UPDATE events SET is_monitored = $1 WHERE id = $2; --- name: UpdateEventSettings :exec -UPDATE company_event_settings -SET is_active = COALESCE(sqlc.narg('is_active'), is_active), - is_featured = COALESCE( - sqlc.narg('is_featured'), - is_featured - ), - winning_upper_limit = COALESCE( - sqlc.narg('winning_upper_limit'), - winning_upper_limit - ) -WHERE event_id = $1 - AND company_id = $2; + -- name: DeleteEvent :exec DELETE FROM events WHERE id = $1; \ No newline at end of file diff --git a/db/query/leagues.sql b/db/query/leagues.sql index fbbc562..1063480 100644 --- a/db/query/leagues.sql +++ b/db/query/leagues.sql @@ -36,6 +36,10 @@ WHERE ( sport_id = sqlc.narg('sport_id') OR sqlc.narg('sport_id') IS NULL ) + AND ( + name ILIKE '%' || sqlc.narg('query') || '%' + OR sqlc.narg('query') IS NULL + ) ORDER BY name ASC LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); -- name: GetAllLeaguesWithSettings :many @@ -58,6 +62,11 @@ WHERE (company_id = $1) is_featured = sqlc.narg('is_featured') OR sqlc.narg('is_featured') IS NULL ) + AND ( + name ILIKE '%' || sqlc.narg('query') || '%' + OR league_name ILIKE '%' || sqlc.narg('query') || '%' + OR sqlc.narg('query') IS NULL + ) ORDER BY is_featured DESC, name ASC LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); diff --git a/db/query/odds.sql b/db/query/odds.sql index 8c231b1..0a4916e 100644 --- a/db/query/odds.sql +++ b/db/query/odds.sql @@ -26,7 +26,7 @@ SET market_type = EXCLUDED.market_type, raw_odds = EXCLUDED.raw_odds, fetched_at = EXCLUDED.fetched_at, expires_at = EXCLUDED.expires_at; --- name: InsertOddSettings :exec +-- name: SaveOddSettings :exec INSERT INTO company_odd_settings ( company_id, odds_market_id, @@ -46,6 +46,10 @@ SELECT * FROM odds_market_with_settings WHERE company_id = $1 LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); +-- name: GetOddByID :one +SELECT * +FROM odds_market_with_event +WHERE id = $1; -- name: GetOddsByMarketID :one SELECT * FROM odds_market_with_event @@ -57,6 +61,11 @@ FROM odds_market_with_settings WHERE market_id = $1 AND event_id = $2 AND company_id = $3; +-- name: GetOddsWithSettingsByID :one +SELECT * +FROM odds_market_with_settings +WHERE id = $1 + AND company_id = $2; -- name: GetOddsByEventID :many SELECT * FROM odds_market_with_event diff --git a/gen/db/events.sql.go b/gen/db/events.sql.go index 313b240..0932419 100644 --- a/gen/db/events.sql.go +++ b/gen/db/events.sql.go @@ -654,40 +654,6 @@ func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error return err } -const InsertEventSettings = `-- name: InsertEventSettings :exec -INSERT INTO company_event_settings ( - company_id, - event_id, - is_active, - is_featured, - winning_upper_limit - ) -VALUES ($1, $2, $3, $4, $5) ON CONFLICT(company_id, event_id) DO -UPDATE -SET is_active = EXCLUDED.is_active, - is_featured = EXCLUDED.is_featured, - winning_upper_limit = EXCLUDED.winning_upper_limit -` - -type InsertEventSettingsParams struct { - CompanyID int64 `json:"company_id"` - EventID string `json:"event_id"` - IsActive pgtype.Bool `json:"is_active"` - IsFeatured pgtype.Bool `json:"is_featured"` - WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"` -} - -func (q *Queries) InsertEventSettings(ctx context.Context, arg InsertEventSettingsParams) error { - _, err := q.db.Exec(ctx, InsertEventSettings, - arg.CompanyID, - arg.EventID, - arg.IsActive, - arg.IsFeatured, - arg.WinningUpperLimit, - ) - return err -} - const IsEventMonitored = `-- name: IsEventMonitored :one SELECT is_monitored FROM events @@ -727,6 +693,40 @@ func (q *Queries) ListLiveEvents(ctx context.Context) ([]string, error) { return items, nil } +const SaveEventSettings = `-- name: SaveEventSettings :exec +INSERT INTO company_event_settings ( + company_id, + event_id, + is_active, + is_featured, + winning_upper_limit + ) +VALUES ($1, $2, $3, $4, $5) ON CONFLICT(company_id, event_id) DO +UPDATE +SET is_active = EXCLUDED.is_active, + is_featured = EXCLUDED.is_featured, + winning_upper_limit = EXCLUDED.winning_upper_limit +` + +type SaveEventSettingsParams struct { + CompanyID int64 `json:"company_id"` + EventID string `json:"event_id"` + IsActive pgtype.Bool `json:"is_active"` + IsFeatured pgtype.Bool `json:"is_featured"` + WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"` +} + +func (q *Queries) SaveEventSettings(ctx context.Context, arg SaveEventSettingsParams) error { + _, err := q.db.Exec(ctx, SaveEventSettings, + arg.CompanyID, + arg.EventID, + arg.IsActive, + arg.IsFeatured, + arg.WinningUpperLimit, + ) + return err +} + const UpdateEventMonitored = `-- name: UpdateEventMonitored :exec UPDATE events SET is_monitored = $1 @@ -743,40 +743,6 @@ func (q *Queries) UpdateEventMonitored(ctx context.Context, arg UpdateEventMonit return err } -const UpdateEventSettings = `-- name: UpdateEventSettings :exec -UPDATE company_event_settings -SET is_active = COALESCE($3, is_active), - is_featured = COALESCE( - $4, - is_featured - ), - winning_upper_limit = COALESCE( - $5, - winning_upper_limit - ) -WHERE event_id = $1 - AND company_id = $2 -` - -type UpdateEventSettingsParams struct { - EventID string `json:"event_id"` - CompanyID int64 `json:"company_id"` - IsActive pgtype.Bool `json:"is_active"` - IsFeatured pgtype.Bool `json:"is_featured"` - WinningUpperLimit pgtype.Int4 `json:"winning_upper_limit"` -} - -func (q *Queries) UpdateEventSettings(ctx context.Context, arg UpdateEventSettingsParams) error { - _, err := q.db.Exec(ctx, UpdateEventSettings, - arg.EventID, - arg.CompanyID, - arg.IsActive, - arg.IsFeatured, - arg.WinningUpperLimit, - ) - 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 5d49d4d..ff9ea19 100644 --- a/gen/db/leagues.sql.go +++ b/gen/db/leagues.sql.go @@ -44,13 +44,18 @@ WHERE ( sport_id = $2 OR $2 IS NULL ) + AND ( + name ILIKE '%' || $3 || '%' + OR $3 IS NULL + ) ORDER BY name ASC -LIMIT $4 OFFSET $3 +LIMIT $5 OFFSET $4 ` type GetAllLeaguesParams struct { CountryCode pgtype.Text `json:"country_code"` SportID pgtype.Int4 `json:"sport_id"` + Query pgtype.Text `json:"query"` Offset pgtype.Int4 `json:"offset"` Limit pgtype.Int4 `json:"limit"` } @@ -59,6 +64,7 @@ func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([ rows, err := q.db.Query(ctx, GetAllLeagues, arg.CountryCode, arg.SportID, + arg.Query, arg.Offset, arg.Limit, ) @@ -109,9 +115,14 @@ WHERE (company_id = $1) is_featured = $5 OR $5 IS NULL ) + AND ( + name ILIKE '%' || $6 || '%' + OR league_name ILIKE '%' || $6 || '%' + OR $6 IS NULL + ) ORDER BY is_featured DESC, name ASC -LIMIT $7 OFFSET $6 +LIMIT $8 OFFSET $7 ` type GetAllLeaguesWithSettingsParams struct { @@ -120,6 +131,7 @@ type GetAllLeaguesWithSettingsParams struct { SportID pgtype.Int4 `json:"sport_id"` IsActive pgtype.Bool `json:"is_active"` IsFeatured pgtype.Bool `json:"is_featured"` + Query pgtype.Text `json:"query"` Offset pgtype.Int4 `json:"offset"` Limit pgtype.Int4 `json:"limit"` } @@ -131,6 +143,7 @@ func (q *Queries) GetAllLeaguesWithSettings(ctx context.Context, arg GetAllLeagu arg.SportID, arg.IsActive, arg.IsFeatured, + arg.Query, arg.Offset, arg.Limit, ) diff --git a/gen/db/odds.sql.go b/gen/db/odds.sql.go index 33fcde8..a0bb5a9 100644 --- a/gen/db/odds.sql.go +++ b/gen/db/odds.sql.go @@ -114,6 +114,34 @@ func (q *Queries) GetAllOddsWithSettings(ctx context.Context, arg GetAllOddsWith return items, nil } +const GetOddByID = `-- name: GetOddByID :one +SELECT id, event_id, market_type, market_name, market_category, market_id, raw_odds, default_is_active, fetched_at, expires_at, is_monitored, is_live, status, source +FROM odds_market_with_event +WHERE id = $1 +` + +func (q *Queries) GetOddByID(ctx context.Context, id int64) (OddsMarketWithEvent, error) { + row := q.db.QueryRow(ctx, GetOddByID, id) + var i OddsMarketWithEvent + err := row.Scan( + &i.ID, + &i.EventID, + &i.MarketType, + &i.MarketName, + &i.MarketCategory, + &i.MarketID, + &i.RawOdds, + &i.DefaultIsActive, + &i.FetchedAt, + &i.ExpiresAt, + &i.IsMonitored, + &i.IsLive, + &i.Status, + &i.Source, + ) + return i, err +} + const GetOddsByEventID = `-- name: GetOddsByEventID :many SELECT id, event_id, market_type, market_name, market_category, market_id, raw_odds, default_is_active, fetched_at, expires_at, is_monitored, is_live, status, source FROM odds_market_with_event @@ -272,6 +300,39 @@ func (q *Queries) GetOddsWithSettingsByEventID(ctx context.Context, arg GetOddsW return items, nil } +const GetOddsWithSettingsByID = `-- name: GetOddsWithSettingsByID :one +SELECT id, event_id, market_type, market_name, market_category, market_id, default_is_active, fetched_at, expires_at, company_id, is_active, raw_odds, updated_at +FROM odds_market_with_settings +WHERE id = $1 + AND company_id = $2 +` + +type GetOddsWithSettingsByIDParams struct { + ID int64 `json:"id"` + CompanyID int64 `json:"company_id"` +} + +func (q *Queries) GetOddsWithSettingsByID(ctx context.Context, arg GetOddsWithSettingsByIDParams) (OddsMarketWithSetting, error) { + row := q.db.QueryRow(ctx, GetOddsWithSettingsByID, arg.ID, arg.CompanyID) + var i OddsMarketWithSetting + err := row.Scan( + &i.ID, + &i.EventID, + &i.MarketType, + &i.MarketName, + &i.MarketCategory, + &i.MarketID, + &i.DefaultIsActive, + &i.FetchedAt, + &i.ExpiresAt, + &i.CompanyID, + &i.IsActive, + &i.RawOdds, + &i.UpdatedAt, + ) + return i, err +} + const GetOddsWithSettingsByMarketID = `-- name: GetOddsWithSettingsByMarketID :one SELECT id, event_id, market_type, market_name, market_category, market_id, default_is_active, fetched_at, expires_at, company_id, is_active, raw_odds, updated_at FROM odds_market_with_settings @@ -307,36 +368,6 @@ func (q *Queries) GetOddsWithSettingsByMarketID(ctx context.Context, arg GetOdds return i, err } -const InsertOddSettings = `-- name: InsertOddSettings :exec -INSERT INTO company_odd_settings ( - company_id, - odds_market_id, - is_active, - custom_raw_odds - ) -VALUES ($1, $2, $3, $4) ON CONFLICT (company_id, odds_market_id) DO -UPDATE -SET is_active = EXCLUDED.is_active, - custom_raw_odds = EXCLUDED.custom_raw_odds -` - -type InsertOddSettingsParams struct { - CompanyID int64 `json:"company_id"` - OddsMarketID int64 `json:"odds_market_id"` - IsActive pgtype.Bool `json:"is_active"` - CustomRawOdds []byte `json:"custom_raw_odds"` -} - -func (q *Queries) InsertOddSettings(ctx context.Context, arg InsertOddSettingsParams) error { - _, err := q.db.Exec(ctx, InsertOddSettings, - arg.CompanyID, - arg.OddsMarketID, - arg.IsActive, - arg.CustomRawOdds, - ) - return err -} - const InsertOddsMarket = `-- name: InsertOddsMarket :exec INSERT INTO odds_market ( event_id, @@ -391,3 +422,33 @@ func (q *Queries) InsertOddsMarket(ctx context.Context, arg InsertOddsMarketPara ) return err } + +const SaveOddSettings = `-- name: SaveOddSettings :exec +INSERT INTO company_odd_settings ( + company_id, + odds_market_id, + is_active, + custom_raw_odds + ) +VALUES ($1, $2, $3, $4) ON CONFLICT (company_id, odds_market_id) DO +UPDATE +SET is_active = EXCLUDED.is_active, + custom_raw_odds = EXCLUDED.custom_raw_odds +` + +type SaveOddSettingsParams struct { + CompanyID int64 `json:"company_id"` + OddsMarketID int64 `json:"odds_market_id"` + IsActive pgtype.Bool `json:"is_active"` + CustomRawOdds []byte `json:"custom_raw_odds"` +} + +func (q *Queries) SaveOddSettings(ctx context.Context, arg SaveOddSettingsParams) error { + _, err := q.db.Exec(ctx, SaveOddSettings, + arg.CompanyID, + arg.OddsMarketID, + arg.IsActive, + arg.CustomRawOdds, + ) + return err +} diff --git a/internal/domain/event.go b/internal/domain/event.go index 0906918..6bae5a1 100644 --- a/internal/domain/event.go +++ b/internal/domain/event.go @@ -98,42 +98,45 @@ type BaseEventRes struct { DefaultIsFeatured bool `json:"default_is_featured"` DefaultIsActive bool `json:"default_is_active"` DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"` - Score string `json:"score,omitempty"` - MatchMinute int `json:"match_minute,omitempty"` - TimerStatus string `json:"timer_status,omitempty"` - AddedTime int `json:"added_time,omitempty"` - MatchPeriod int `json:"match_period,omitempty"` + Score string `json:"score"` + MatchMinute int `json:"match_minute"` + TimerStatus string `json:"timer_status"` + AddedTime int `json:"added_time"` + MatchPeriod int `json:"match_period"` IsLive bool `json:"is_live"` FetchedAt time.Time `json:"fetched_at"` } type EventWithSettings struct { - ID string - SportID int32 - MatchName string - HomeTeam string - AwayTeam string - HomeTeamID int64 - AwayTeamID int64 - HomeTeamImage string - AwayTeamImage string - LeagueID int64 - LeagueName string - LeagueCC ValidString - StartTime time.Time - Source EventSource - Status EventStatus - IsFeatured bool - IsMonitored bool - IsActive bool - WinningUpperLimit int32 - Score ValidString - MatchMinute ValidInt - TimerStatus ValidString - AddedTime ValidInt - MatchPeriod ValidInt - IsLive bool - UpdatedAt time.Time - FetchedAt time.Time + ID string + SportID int32 + MatchName string + HomeTeam string + AwayTeam string + HomeTeamID int64 + AwayTeamID int64 + HomeTeamImage string + AwayTeamImage string + LeagueID int64 + LeagueName string + LeagueCC ValidString + StartTime time.Time + Source EventSource + Status EventStatus + IsMonitored bool + IsFeatured bool + IsActive bool + WinningUpperLimit int32 + DefaultIsFeatured bool + DefaultIsActive bool + DefaultWinningUpperLimit int32 + Score ValidString + MatchMinute ValidInt + TimerStatus ValidString + AddedTime ValidInt + MatchPeriod ValidInt + IsLive bool + UpdatedAt time.Time + FetchedAt time.Time } type CreateEvent struct { @@ -155,33 +158,36 @@ type CreateEvent struct { } type EventWithSettingsRes struct { - ID string `json:"id"` - SportID int32 `json:"sport_id"` - MatchName string `json:"match_name"` - HomeTeam string `json:"home_team"` - AwayTeam string `json:"away_team"` - HomeTeamID int64 `json:"home_team_id"` - AwayTeamID int64 `json:"away_team_id"` - HomeTeamImage string `json:"home_team_image"` - AwayTeamImage string `json:"away_team_image"` - LeagueID int64 `json:"league_id"` - LeagueName string `json:"league_name"` - LeagueCC string `json:"league_cc"` - StartTime time.Time `json:"start_time"` - Source EventSource `json:"source"` - Status EventStatus `json:"status"` - IsFeatured bool `json:"is_featured"` - IsMonitored bool `json:"is_monitored"` - IsActive bool `json:"is_active"` - WinningUpperLimit int32 `json:"winning_upper_limit"` - Score string `json:"score,omitempty"` - MatchMinute int `json:"match_minute,omitempty"` - TimerStatus string `json:"timer_status,omitempty"` - AddedTime int `json:"added_time,omitempty"` - MatchPeriod int `json:"match_period,omitempty"` - IsLive bool `json:"is_live"` - UpdatedAt time.Time `json:"updated_at"` - FetchedAt time.Time `json:"fetched_at"` + ID string `json:"id"` + SportID int32 `json:"sport_id"` + MatchName string `json:"match_name"` + HomeTeam string `json:"home_team"` + AwayTeam string `json:"away_team"` + HomeTeamID int64 `json:"home_team_id"` + AwayTeamID int64 `json:"away_team_id"` + HomeTeamImage string `json:"home_team_image"` + AwayTeamImage string `json:"away_team_image"` + LeagueID int64 `json:"league_id"` + LeagueName string `json:"league_name"` + LeagueCC string `json:"league_cc"` + StartTime time.Time `json:"start_time"` + Source EventSource `json:"source"` + Status EventStatus `json:"status"` + IsMonitored bool `json:"is_monitored"` + IsFeatured bool `json:"is_featured"` + IsActive bool `json:"is_active"` + WinningUpperLimit int32 `json:"winning_upper_limit"` + DefaultIsFeatured bool `json:"default_is_featured"` + DefaultIsActive bool `json:"default_is_active"` + DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"` + Score string `json:"score,omitempty"` + MatchMinute int `json:"match_minute,omitempty"` + TimerStatus string `json:"timer_status,omitempty"` + AddedTime int `json:"added_time,omitempty"` + MatchPeriod int `json:"match_period,omitempty"` + IsLive bool `json:"is_live"` + UpdatedAt time.Time `json:"updated_at"` + FetchedAt time.Time `json:"fetched_at"` } type EventSettings struct { @@ -291,8 +297,8 @@ func ConvertCreateEvent(e CreateEvent) dbgen.InsertEventParams { } } -func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.InsertEventSettingsParams { - return dbgen.InsertEventSettingsParams{ +func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.SaveEventSettingsParams { + return dbgen.SaveEventSettingsParams{ CompanyID: eventSettings.CompanyID, EventID: eventSettings.EventID, IsActive: eventSettings.IsActive.ToPG(), @@ -318,13 +324,15 @@ func ConvertDBEventWithSetting(event dbgen.EventWithSetting) EventWithSettings { Value: event.LeagueCc.String, Valid: event.LeagueCc.Valid, }, - StartTime: event.StartTime.Time.UTC(), - Source: EventSource(event.Source), - Status: EventStatus(event.Status), - IsFeatured: event.IsFeatured, - IsMonitored: event.IsMonitored, - IsActive: event.IsActive, - WinningUpperLimit: event.WinningUpperLimit, + StartTime: event.StartTime.Time.UTC(), + Source: EventSource(event.Source), + Status: EventStatus(event.Status), + IsFeatured: event.IsFeatured, + IsMonitored: event.IsMonitored, + IsActive: event.IsActive, + DefaultIsFeatured: event.DefaultIsFeatured, + DefaultIsActive: event.DefaultIsActive, + DefaultWinningUpperLimit: event.DefaultWinningUpperLimit, Score: ValidString{ Value: event.Score.String, Valid: event.Score.Valid, @@ -359,8 +367,8 @@ func ConvertDBEventWithSettings(events []dbgen.EventWithSetting) []EventWithSett return result } -func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.UpdateEventSettingsParams { - return dbgen.UpdateEventSettingsParams{ +func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.SaveEventSettingsParams { + return dbgen.SaveEventSettingsParams{ EventID: event.EventID, CompanyID: event.CompanyID, IsActive: event.IsActive.ToPG(), @@ -409,32 +417,35 @@ func ConvertEventResList(events []BaseEvent) []BaseEventRes { func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes { return EventWithSettingsRes{ - ID: event.ID, - SportID: event.SportID, - MatchName: event.MatchName, - HomeTeam: event.HomeTeam, - AwayTeam: event.AwayTeam, - HomeTeamID: event.HomeTeamID, - AwayTeamID: event.AwayTeamID, - HomeTeamImage: event.HomeTeamImage, - AwayTeamImage: event.AwayTeamImage, - LeagueID: event.LeagueID, - LeagueName: event.LeagueName, - LeagueCC: event.LeagueCC.Value, - StartTime: event.StartTime.UTC(), - Source: EventSource(event.Source), - Status: EventStatus(event.Status), - IsFeatured: event.IsFeatured, - IsMonitored: event.IsMonitored, - IsActive: event.IsActive, - WinningUpperLimit: event.WinningUpperLimit, - Score: event.Score.Value, - MatchMinute: event.MatchMinute.Value, - TimerStatus: event.TimerStatus.Value, - AddedTime: event.AddedTime.Value, - MatchPeriod: event.MatchPeriod.Value, - IsLive: event.IsLive, - FetchedAt: event.FetchedAt.UTC(), + ID: event.ID, + SportID: event.SportID, + MatchName: event.MatchName, + HomeTeam: event.HomeTeam, + AwayTeam: event.AwayTeam, + HomeTeamID: event.HomeTeamID, + AwayTeamID: event.AwayTeamID, + HomeTeamImage: event.HomeTeamImage, + AwayTeamImage: event.AwayTeamImage, + LeagueID: event.LeagueID, + LeagueName: event.LeagueName, + LeagueCC: event.LeagueCC.Value, + StartTime: event.StartTime.UTC(), + Source: EventSource(event.Source), + Status: EventStatus(event.Status), + IsFeatured: event.IsFeatured, + IsMonitored: event.IsMonitored, + IsActive: event.IsActive, + DefaultIsFeatured: event.DefaultIsFeatured, + DefaultIsActive: event.DefaultIsActive, + DefaultWinningUpperLimit: event.DefaultWinningUpperLimit, + WinningUpperLimit: event.WinningUpperLimit, + Score: event.Score.Value, + MatchMinute: event.MatchMinute.Value, + TimerStatus: event.TimerStatus.Value, + AddedTime: event.AddedTime.Value, + MatchPeriod: event.MatchPeriod.Value, + IsLive: event.IsLive, + FetchedAt: event.FetchedAt.UTC(), } } diff --git a/internal/domain/league.go b/internal/domain/league.go index a44ae70..88862b3 100644 --- a/internal/domain/league.go +++ b/internal/domain/league.go @@ -8,24 +8,30 @@ import ( // The ID and the Bet365 IDs we have here are both gotten from the betapi type LeagueWithSettings struct { - ID int64 - Name string - CompanyID int64 - CountryCode ValidString - Bet365ID ValidInt32 - SportID int32 - IsActive bool - IsFeatured bool - UpdatedAt time.Time + ID int64 + Name string + CompanyID int64 + CountryCode ValidString + Bet365ID ValidInt32 + SportID int32 + IsActive bool + IsFeatured bool + DefaultIsActive bool + DefaultIsFeatured bool + UpdatedAt time.Time } type LeagueWithSettingsRes struct { - ID int64 `json:"id" example:"1"` - Name string `json:"name" example:"BPL"` - CountryCode string `json:"cc" example:"uk"` - Bet365ID int32 `json:"bet365_id" example:"1121"` - IsActive bool `json:"is_active" example:"false"` - SportID int32 `json:"sport_id" example:"1"` - IsFeatured bool `json:"is_featured" example:"false"` + ID int64 `json:"id" example:"1"` + Name string `json:"name" example:"BPL"` + CompanyID int64 `json:"company_id" example:"1"` + CountryCode string `json:"cc" example:"uk"` + Bet365ID int32 `json:"bet365_id" example:"1121"` + IsActive bool `json:"is_active" example:"false"` + SportID int32 `json:"sport_id" example:"1"` + IsFeatured bool `json:"is_featured" example:"false"` + DefaultIsActive bool `json:"default_is_active" example:"false"` + DefaultIsFeatured bool `json:"default_is_featured" example:"false"` + UpdatedAt time.Time `json:"updated_at"` } type BaseLeague struct { ID int64 @@ -82,6 +88,7 @@ type UpdateLeague struct { } type LeagueFilter struct { + Query ValidString CountryCode ValidString SportID ValidInt32 IsActive ValidBool @@ -154,6 +161,9 @@ func ConvertDBLeagueWithSetting(lws dbgen.LeagueWithSetting) LeagueWithSettings SportID: lws.SportID, IsFeatured: lws.IsFeatured, UpdatedAt: lws.UpdatedAt.Time, + + DefaultIsActive: lws.DefaultIsActive, + DefaultIsFeatured: lws.DefaultIsFeatured, } } @@ -174,3 +184,50 @@ func ConvertUpdateLeague(updateLeague UpdateLeague) dbgen.UpdateLeagueParams { SportID: updateLeague.SportID.ToPG(), } } + +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, + DefaultIsActive: lws.DefaultIsActive, + DefaultIsFeatured: lws.DefaultIsFeatured, + } +} + +func ConvertLeagueWithSettingResList(leagues []LeagueWithSettings) []LeagueWithSettingsRes { + result := make([]LeagueWithSettingsRes, len(leagues)) + + for i, lws := range leagues { + result[i] = ConvertLeagueWithSettingRes(lws) + } + + return result +} + +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, + DefaultIsFeatured: league.DefaultIsFeatured, + } +} + +func ConvertBaseLeagueResList(leagues []BaseLeague) []BaseLeagueRes { + result := make([]BaseLeagueRes, len(leagues)) + for i, league := range leagues { + result[i] = ConvertBaseLeagueRes(league) + } + + return result +} diff --git a/internal/domain/odds.go b/internal/domain/odds.go index fa30718..cb67b82 100644 --- a/internal/domain/odds.go +++ b/internal/domain/odds.go @@ -61,6 +61,17 @@ type CreateOddMarketSettings struct { CustomRawOdds []map[string]interface{} } +type CustomOdd struct { + OddID int64 `json:"odd_id"` + OddValue float32 `json:"odd_value"` +} + +type CreateOddMarketSettingsReq struct { + OddMarketID int64 `json:"odd_market_id"` + IsActive *bool `json:"is_active,omitempty"` + CustomOdd []CustomOdd `json:"custom_odd,omitempty"` +} + // type RawOddsByMarketID struct { // ID int64 `json:"id"` // MarketName string `json:"market_name"` @@ -136,12 +147,12 @@ func ConvertCreateOddMarket(oddMarket CreateOddMarket) (dbgen.InsertOddsMarketPa }, nil } -func ConvertCreateOddMarketSetting(oms CreateOddMarketSettings) (dbgen.InsertOddSettingsParams, error) { +func ConvertCreateOddMarketSetting(oms CreateOddMarketSettings) (dbgen.SaveOddSettingsParams, error) { rawOddsBytes, err := json.Marshal(oms.CustomRawOdds) if err != nil { - return dbgen.InsertOddSettingsParams{}, err + return dbgen.SaveOddSettingsParams{}, err } - return dbgen.InsertOddSettingsParams{ + return dbgen.SaveOddSettingsParams{ CompanyID: oms.CompanyID, OddsMarketID: oms.OddMarketID, IsActive: oms.IsActive.ToPG(), diff --git a/internal/domain/setting_list.go b/internal/domain/setting_list.go index 5f4a20e..5f90621 100644 --- a/internal/domain/setting_list.go +++ b/internal/domain/setting_list.go @@ -35,6 +35,18 @@ type SettingListRes struct { CashbackAmountCap float32 `json:"cashback_amount_cap"` } +func ConvertSettingListRes(settings SettingList) SettingListRes { + return SettingListRes{ + SMSProvider: settings.SMSProvider, + MaxNumberOfOutcomes: settings.MaxNumberOfOutcomes, + BetAmountLimit: settings.BetAmountLimit.Float32(), + DailyTicketPerIP: settings.DailyTicketPerIP, + TotalWinningLimit: settings.TotalWinningLimit.Float32(), + AmountForBetReferral: settings.AmountForBetReferral.Float32(), + CashbackAmountCap: settings.CashbackAmountCap.Float32(), + } +} + type SaveSettingListReq struct { SMSProvider *string `json:"sms_provider,omitempty"` MaxNumberOfOutcomes *int64 `json:"max_number_of_outcomes,omitempty"` @@ -157,57 +169,105 @@ func (vsl *ValidSettingList) GetAllValid() map[string]*bool { return settingValid } -func setValidSetting[T any](settings map[string]*T, searchKey string, setVal T) error { - for key, setting := range settings { +// func setValidSetting[T any](settings map[string]*T, searchKey string, searchVal string, setVal func(string) (T, error)) error { +// for key, setting := range settings { + +// if key == searchKey { +// s, err := setVal(searchVal) +// if err != nil { +// return err +// } +// *setting = s +// } +// return nil +// } +// return ErrSettingNotFound +// } +func (vsl *ValidSettingList) SetInt64Setting(searchKey string, searchVal string) error { + for key, setting := range vsl.GetInt64SettingsMap() { if key == searchKey { - *setting = setVal + value, err := strconv.ParseInt(searchVal, 10, 64) + if err != nil { + return err + } + *setting = ValidInt64{Value: value, Valid: true} + return nil } - return nil } return ErrSettingNotFound } -func (vsl *ValidSettingList) SetInt64Setting(searchKey string, searchVal string) error { - value, err := strconv.ParseInt(searchVal, 10, 64) - if err != nil { - return err - } - return setValidSetting(vsl.GetInt64SettingsMap(), searchKey, ValidInt64{Value: value, Valid: true}) -} func (vsl *ValidSettingList) SetCurrencySetting(searchKey string, searchVal string) error { - value, err := strconv.ParseInt(searchVal, 10, 64) - if err != nil { - return err + for key, setting := range vsl.GetCurrencySettingsMap() { + if key == searchKey { + value, err := strconv.ParseInt(searchVal, 10, 64) + if err != nil { + return err + } + *setting = ValidCurrency{Value: Currency(value), Valid: true} + return nil + } } - return setValidSetting(vsl.GetCurrencySettingsMap(), searchKey, ValidCurrency{Value: Currency(value), Valid: true}) + + return ErrSettingNotFound } func (vsl *ValidSettingList) SetStringSetting(searchKey string, searchVal string) error { - return setValidSetting(vsl.GetStringSettingsMap(), searchKey, ValidString{Value: searchVal, Valid: true}) + for key, setting := range vsl.GetStringSettingsMap() { + if key == searchKey { + *setting = ValidString{Value: searchVal, Valid: true} + return nil + } + } + + return ErrSettingNotFound } func (vsl *ValidSettingList) SetBoolSetting(searchKey string, searchVal string) error { - value, err := strconv.ParseBool(searchVal) - if err != nil { - return err + for key, setting := range vsl.GetBoolSettingsMap() { + + if key == searchKey { + value, err := strconv.ParseBool(searchVal) + if err != nil { + return err + } + + *setting = ValidBool{Value: value, Valid: true} + return nil + } + } - return setValidSetting(vsl.GetBoolSettingsMap(), searchKey, ValidBool{Value: value, Valid: true}) + + return ErrSettingNotFound } func (vsl *ValidSettingList) SetFloat32Setting(searchKey string, searchVal string) error { - value, err := strconv.ParseFloat(searchVal, 32) - if err != nil { - return err + for key, setting := range vsl.GetFloat32SettingsMap() { + if key == searchKey { + value, err := strconv.ParseFloat(searchVal, 32) + if err != nil { + return err + } + *setting = ValidFloat32{Value: float32(value), Valid: true} + return nil + } } - return setValidSetting(vsl.GetFloat32SettingsMap(), searchKey, ValidFloat32{Value: float32(value), Valid: true}) + + return ErrSettingNotFound } func (vsl *ValidSettingList) SetTimeSetting(searchKey string, searchVal string) error { - value, err := time.Parse(time.RFC3339, searchVal) - if err != nil { - return err + for key, setting := range vsl.GetTimeSettingsMap() { + if key == searchKey { + value, err := time.Parse(time.RFC3339, searchVal) + if err != nil { + return err + } + *setting = ValidTime{Value: value, Valid: true} + return nil + } } - return setValidSetting(vsl.GetTimeSettingsMap(), searchKey, ValidTime{Value: value, Valid: true}) + return ErrSettingNotFound } func (vsl *ValidSettingList) SetSetting(searchKey string, searchVal string) error { @@ -223,9 +283,10 @@ func (vsl *ValidSettingList) SetSetting(searchKey string, searchVal string) erro for _, setter := range setters { if err := setter(searchKey, searchVal); err != nil { if err == ErrSettingNotFound { + // fmt.Printf("setting is not found %v \n", searchKey) continue // not this setter, try the next } - return fmt.Errorf("error while processing setting %q: %w", searchKey, err) + return fmt.Errorf("error while processing setting %q: %w \n", searchKey, err) } return nil // successfully set } @@ -306,6 +367,7 @@ func validateSettings[T any]( var errs []string for key, s := range settings { if !customValidator(s) { + errs = append(errs, fmt.Sprintf("%v is invalid", key)) } } @@ -378,6 +440,7 @@ func (vsl *ValidSettingList) ValidateAllSettings() error { for _, validator := range validators { if err := validator(); err != nil { + errs = append(errs, err.Error()) } } @@ -410,12 +473,12 @@ func ConvertDBGlobalSettingList(settings []dbgen.GlobalSetting) (SettingList, er if err == ErrSettingNotFound { MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key)) } + MongoDBLogger.Error("unknown error while fetching settings", zap.Error(err)) } } if err := dbSettingList.ValidateAllSettings(); err != nil { - fmt.Printf("setting validation error: %v \n", err) - MongoDBLogger.Warn("setting validation error", zap.Error(err)) + MongoDBLogger.Warn("setting validation error", zap.Error(err), zap.Any("db_setting_list", dbSettingList)) return SettingList{}, err } @@ -436,7 +499,6 @@ func ConvertDBOverrideSettingList(settings []dbgen.GetOverrideSettingsRow) (Sett } if err := dbSettingList.ValidateAllSettings(); err != nil { - fmt.Printf("setting validation error: %v \n", err) MongoDBLogger.Warn("setting validation error", zap.Error(err)) return SettingList{}, err } diff --git a/internal/repository/event.go b/internal/repository/event.go index d0798d7..dc593bc 100644 --- a/internal/repository/event.go +++ b/internal/repository/event.go @@ -16,9 +16,6 @@ func (s *Store) SaveEvent(ctx context.Context, e domain.CreateEvent) error { return s.queries.InsertEvent(ctx, domain.ConvertCreateEvent(e)) } -func (s *Store) InsertEventSettings(ctx context.Context, eventSetting domain.CreateEventSettings) error { - return s.queries.InsertEventSettings(ctx, domain.ConvertCreateEventSettings(eventSetting)) -} func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) { return s.queries.ListLiveEvents(ctx) @@ -121,7 +118,7 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Bas } func (s *Store) GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error) { event, err := s.queries.GetEventWithSettingByID(ctx, dbgen.GetEventWithSettingByIDParams{ - ID: ID, + ID: ID, CompanyID: companyID, }) if err != nil { @@ -176,7 +173,7 @@ func (s *Store) UpdateEventMonitored(ctx context.Context, eventID string, IsMoni } func (s *Store) UpdateEventSettings(ctx context.Context, event domain.CreateEventSettings) error { - return s.queries.UpdateEventSettings(ctx, domain.ConvertUpdateEventSettings(event)) + return s.queries.SaveEventSettings(ctx, domain.ConvertUpdateEventSettings(event)); } func (s *Store) DeleteEvent(ctx context.Context, eventID string) error { diff --git a/internal/repository/league.go b/internal/repository/league.go index f003fd9..52b8aef 100644 --- a/internal/repository/league.go +++ b/internal/repository/league.go @@ -18,6 +18,7 @@ func (s *Store) SaveLeagueSettings(ctx context.Context, leagueSettings domain.Cr func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) { l, err := s.queries.GetAllLeagues(ctx, dbgen.GetAllLeaguesParams{ + Query: filter.Query.ToPG(), CountryCode: filter.CountryCode.ToPG(), SportID: filter.SportID.ToPG(), Limit: pgtype.Int4{ @@ -38,6 +39,7 @@ func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ( func (s *Store) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error) { l, err := s.queries.GetAllLeaguesWithSettings(ctx, dbgen.GetAllLeaguesWithSettingsParams{ + Query: filter.Query.ToPG(), CompanyID: companyID, CountryCode: filter.CountryCode.ToPG(), SportID: filter.SportID.ToPG(), diff --git a/internal/repository/odds.go b/internal/repository/odds.go index cb684ce..976c007 100644 --- a/internal/repository/odds.go +++ b/internal/repository/odds.go @@ -97,6 +97,21 @@ func (s *Store) GetAllOddsWithSettings(ctx context.Context, companyID int64, fil return domainOdds, nil } + +func (s *Store) GetOddByID(ctx context.Context, id int64) (domain.OddMarket, error) { + odd, err := s.queries.GetOddByID(ctx, id) + if err != nil { + return domain.OddMarket{}, err + } + + convertedOdd, err := domain.ConvertDBOddMarket(odd) + + if err != nil { + return domain.OddMarket{}, err + } + return convertedOdd, nil +} + func (s *Store) GetOddsByMarketID(ctx context.Context, marketID string, eventID string) (domain.OddMarket, error) { odds, err := s.queries.GetOddsByMarketID(ctx, dbgen.GetOddsByMarketIDParams{ @@ -134,6 +149,25 @@ func (s *Store) GetOddsWithSettingsByMarketID(ctx context.Context, marketID stri return convertedOdd, nil } +func (s *Store) GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID int64) (domain.OddMarketWithSettings, error) { + + odds, err := s.queries.GetOddsWithSettingsByID(ctx, dbgen.GetOddsWithSettingsByIDParams{ + ID: ID, + CompanyID: companyID, + }) + + if err != nil { + return domain.OddMarketWithSettings{}, err + } + + convertedOdd, err := domain.ConvertDBOddMarketWithSetting(odds) + + if err != nil { + return domain.OddMarketWithSettings{}, err + } + return convertedOdd, nil +} + func (s *Store) GetOddsByEventID(ctx context.Context, upcomingID string, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) { odds, err := s.queries.GetOddsByEventID(ctx, dbgen.GetOddsByEventIDParams{ EventID: upcomingID, @@ -185,3 +219,13 @@ func (s *Store) GetOddsWithSettingsByEventID(ctx context.Context, upcomingID str func (s *Store) DeleteOddsForEvent(ctx context.Context, eventID string) error { return s.queries.DeleteOddsForEvent(ctx, eventID) } + +func (s *Store) SaveOddsSetting(ctx context.Context, odd domain.CreateOddMarketSettings) error { + + res, err := domain.ConvertCreateOddMarketSetting(odd) + + if err != nil { + return nil + } + return s.queries.SaveOddSettings(ctx, res) +} diff --git a/internal/services/odds/port.go b/internal/services/odds/port.go index d1026aa..3ec57b9 100644 --- a/internal/services/odds/port.go +++ b/internal/services/odds/port.go @@ -17,6 +17,11 @@ 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) + // Settings + SaveOddsSetting(ctx context.Context, odd domain.CreateOddMarketSettings) error // Odd History InsertOddHistory(ctx context.Context, odd domain.CreateOddHistory) (domain.OddHistory, error) diff --git a/internal/services/odds/service.go b/internal/services/odds/service.go index 33e8db8..dff3fdd 100644 --- a/internal/services/odds/service.go +++ b/internal/services/odds/service.go @@ -705,6 +705,46 @@ func (s *ServiceImpl) GetAllOddsWithSettings(ctx context.Context, companyID int6 return s.store.GetAllOddsWithSettings(ctx, companyID, filter) } +func (s *ServiceImpl) GetOddByID(ctx context.Context, id int64) (domain.OddMarket, error) { + return s.store.GetOddByID(ctx, id) +} + +func (s *ServiceImpl) SaveOddsSetting(ctx context.Context, odd domain.CreateOddMarketSettings) error { + return s.store.SaveOddsSetting(ctx, odd) +} + +func (s *ServiceImpl) SaveOddsSettingReq(ctx context.Context, companyID int64, req domain.CreateOddMarketSettingsReq) error { + + odd, err := s.GetOddsWithSettingsByID(ctx, req.OddMarketID, companyID) + if err != nil { + return err + } + + newOdds, err := convertRawMessage(odd.RawOdds) + if err != nil { + return err + } + + if len(req.CustomOdd) != 0 { + for _, customOdd := range req.CustomOdd { + for _, newOdd := range newOdds { + oldRawOddID := getInt(newOdd["id"]) + + if oldRawOddID == int(customOdd.OddID) { + newOdd["odds"] = customOdd.OddValue + } + } + } + } + + return s.SaveOddsSetting(ctx, domain.CreateOddMarketSettings{ + CompanyID: companyID, + OddMarketID: req.OddMarketID, + IsActive: domain.ConvertBoolPtr(req.IsActive), + CustomRawOdds: newOdds, + }) +} + func (s *ServiceImpl) GetOddsByMarketID(ctx context.Context, marketID string, eventID string) (domain.OddMarket, error) { rows, err := s.store.GetOddsByMarketID(ctx, marketID, eventID) if err != nil { @@ -722,6 +762,10 @@ func (s *ServiceImpl) GetOddsWithSettingsByMarketID(ctx context.Context, marketI return rows, nil } +func (s *ServiceImpl) GetOddsWithSettingsByID(ctx context.Context, ID int64, companyID int64) (domain.OddMarketWithSettings, error) { + return s.store.GetOddsWithSettingsByID(ctx, ID, companyID) +} + func (s *ServiceImpl) GetOddsByEventID(ctx context.Context, upcomingID string, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) { return s.store.GetOddsByEventID(ctx, upcomingID, filter) } diff --git a/internal/web_server/handlers/event_handler.go b/internal/web_server/handlers/event_handler.go index e0914a3..6c3c286 100644 --- a/internal/web_server/handlers/event_handler.go +++ b/internal/web_server/handlers/event_handler.go @@ -511,7 +511,7 @@ type UpdateEventSettingsReq struct { // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse -// @Router /api/v1/{tenant_slug}/events/{id}/settings [put] +// @Router /api/v1/tenant/{tenant_slug}/events/{id}/settings [put] func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error { companyID := c.Locals("company_id").(domain.ValidInt64) if !companyID.Valid { @@ -523,7 +523,7 @@ func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error { var req UpdateEventSettingsReq if err := c.BodyParser(&req); err != nil { - h.BadRequestLogger().Info("Failed to parse user id", + h.BadRequestLogger().Info("Failed to parse event id", zap.String("eventID", eventID), zap.Error(err), ) @@ -543,7 +543,7 @@ func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error { for field, msg := range valErrs { errMsg += fmt.Sprintf("%s: %s; ", field, msg) } - h.BadRequestLogger().Error("Failed to update event featured", + h.BadRequestLogger().Error("Failed to update event settings", append(logFields, zap.String("errMsg", errMsg))..., ) return fiber.NewError(fiber.StatusBadRequest, errMsg) @@ -557,7 +557,63 @@ func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error { }) if err != nil { - h.InternalServerErrorLogger().Error("Failed to update event featured", append(logFields, zap.Error(err))...) + 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) + +} + +type SetEventIsMonitoredReq struct { + IsMonitored bool `json:"is_monitored"` +} + + +// SetEventIsMonitored godoc +// @Summary update the event is_monitored +// @Description Update the event is_monitored +// @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/events/{id}/is_monitored [patch] +func (h *Handler) SetEventIsMonitored(c *fiber.Ctx) error { + eventID := c.Params("id") + + var req SetEventIsMonitoredReq + + if err := c.BodyParser(&req); err != nil { + h.BadRequestLogger().Info("Failed to parse bet id", + zap.String("eventID", eventID), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + logFields := []zap.Field{ + zap.String("eventID", eventID), + zap.Any("is_featured", req.IsMonitored), + } + 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 featured", + append(logFields, zap.String("errMsg", errMsg))..., + ) + return fiber.NewError(fiber.StatusBadRequest, errMsg) + } + + err := h.eventSvc.UpdateEventMonitored(c.Context(), eventID, req.IsMonitored) + + if err != nil { + h.InternalServerErrorLogger().Error("Failed to update event is_monitored", append(logFields, zap.Error(err))...) return fiber.NewError(fiber.StatusInternalServerError, err.Error()) } diff --git a/internal/web_server/handlers/leagues.go b/internal/web_server/handlers/leagues.go index 48274fd..4363e27 100644 --- a/internal/web_server/handlers/leagues.go +++ b/internal/web_server/handlers/leagues.go @@ -33,6 +33,12 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { Valid: true, } + searchQuery := c.Query("query") + searchString := domain.ValidString{ + Value: searchQuery, + Valid: searchQuery != "", + } + countryCodeQuery := c.Query("cc") countryCode := domain.ValidString{ Value: countryCodeQuery, @@ -73,6 +79,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { zap.Bool("is_active_valid", isActive.Valid), zap.String("cc_query", countryCodeQuery), zap.String("cc", countryCode.Value), + zap.String("query", searchQuery), zap.Bool("cc_valid", countryCode.Valid), zap.String("sport_id_query", sportIDQuery), zap.Int32("sport_id", sportID.Value), @@ -85,6 +92,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { SportID: sportID, Limit: limit, Offset: offset, + Query: searchString, }) if err != nil { @@ -93,7 +101,10 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error { ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to get leagues:"+err.Error()) } - return response.WriteJSON(c, fiber.StatusOK, "All leagues retrieved", leagues, nil) + + res := domain.ConvertBaseLeagueResList(leagues) + + return response.WriteJSON(c, fiber.StatusOK, "All leagues retrieved", res, nil) } // GetAllLeaguesForTenant godoc @@ -125,6 +136,11 @@ func (h *Handler) GetAllLeaguesForTenant(c *fiber.Ctx) error { Valid: true, } + searchQuery := c.Query("query") + searchString := domain.ValidString{ + Value: searchQuery, + Valid: searchQuery != "", + } countryCodeQuery := c.Query("cc") countryCode := domain.ValidString{ Value: countryCodeQuery, @@ -179,6 +195,7 @@ func (h *Handler) GetAllLeaguesForTenant(c *fiber.Ctx) error { SportID: sportID, Limit: limit, Offset: offset, + Query: searchString, }) if err != nil { @@ -186,7 +203,10 @@ func (h *Handler) GetAllLeaguesForTenant(c *fiber.Ctx) error { h.InternalServerErrorLogger().Error("Failed to get all leagues", append(queryLogFields, zap.Error(err))...) return fiber.NewError(fiber.StatusInternalServerError, "Failed to get leagues:"+err.Error()) } - return response.WriteJSON(c, fiber.StatusOK, "All leagues retrieved", leagues, nil) + + res := domain.ConvertLeagueWithSettingResList(leagues) + + return response.WriteJSON(c, fiber.StatusOK, "All leagues retrieved", res, nil) } type SetLeagueActiveReq struct { diff --git a/internal/web_server/handlers/odd_handler.go b/internal/web_server/handlers/odd_handler.go index bf89c84..9f23dff 100644 --- a/internal/web_server/handlers/odd_handler.go +++ b/internal/web_server/handlers/odd_handler.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "strconv" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" @@ -300,3 +301,49 @@ func (h *Handler) GetTenantOddsByUpcomingID(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusOK, "Odds retrieved successfully", odds, nil) } + +func (h *Handler) SaveOddsSetting(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 + + if err := c.BodyParser(&req); err != nil { + h.BadRequestLogger().Info("Failed to parse event id", + zap.Int64("CompanyID", companyID.Value), + zap.Error(err), + ) + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + logFields := []zap.Field{ + zap.Int64("companyID", companyID.Value), + zap.Any("is_active", req.IsActive), + zap.Any("custom_odd", req.CustomOdd), + } + + 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.prematchSvc.SaveOddsSettingReq(c.Context(), companyID.Value, req) + + 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) + +} diff --git a/internal/web_server/handlers/settings_handler.go b/internal/web_server/handlers/settings_handler.go index bc30195..13e9890 100644 --- a/internal/web_server/handlers/settings_handler.go +++ b/internal/web_server/handlers/settings_handler.go @@ -17,12 +17,15 @@ func (h *Handler) GetGlobalSettingList(c *fiber.Ctx) error { h.mongoLoggerSvc.Error("Failed to fetch settings", zap.Int("status_code", fiber.StatusInternalServerError), zap.Error(err), + zap.Time("timestamp", time.Now()), ) return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.Error()) } - return response.WriteJSON(c, fiber.StatusOK, "All Settings retrieved successfully", settingsList, nil) + res := domain.ConvertSettingListRes(settingsList) + + return response.WriteJSON(c, fiber.StatusOK, "All Settings retrieved successfully", res, nil) } func (h *Handler) GetGlobalSettingByKey(c *fiber.Ctx) error { @@ -100,7 +103,9 @@ func (h *Handler) UpdateGlobalSettingList(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.Error()) } - return response.WriteJSON(c, fiber.StatusOK, "setting updated", settingsList, nil) + res := domain.ConvertSettingListRes(settingsList) + + return response.WriteJSON(c, fiber.StatusOK, "setting updated", res, nil) } func (h *Handler) SaveCompanySettingList(c *fiber.Ctx) error { @@ -178,7 +183,9 @@ func (h *Handler) GetCompanySettingList(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.Error()) } - return response.WriteJSON(c, fiber.StatusOK, "All Settings retrieved successfully", settingsList, nil) + res := domain.ConvertSettingListRes(settingsList) + + return response.WriteJSON(c, fiber.StatusOK, "All Settings retrieved successfully", res, nil) } // /api/v1/{tenant_slug}/settings/{key} diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 8ca5173..c1fc9fe 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -58,7 +58,7 @@ func (a *App) initAppRoutes() { a.fiber.Get("/", func(c *fiber.Ctx) error { return c.JSON(fiber.Map{ "message": "Welcome to the FortuneBet API", - "version": "1.0dev12", + "version": "1.0.dev13", }) }) @@ -236,10 +236,12 @@ func (a *App) initAppRoutes() { 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) groupV1.Get("/events", a.authMiddleware, h.GetAllUpcomingEvents) groupV1.Get("/events/:id", a.authMiddleware, h.GetUpcomingEventByID) groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved) + groupV1.Patch("/events/:id/is_monitored", a.authMiddleware, a.SuperAdminOnly, h.SetEventIsMonitored) tenant.Get("/events", h.GetTenantUpcomingEvents) tenant.Get("/events/:id", h.GetTenantEventByID)