Refactor event and league domain models to include default settings, enhance odds handling, improve API routes, fixed get global settings and Incremented API version to 1.0.dev13.

This commit is contained in:
Samuel Tariku 2025-09-02 04:24:37 +03:00
parent 0b03bfaa42
commit 6ecc6f0428
20 changed files with 688 additions and 277 deletions

View File

@ -54,7 +54,7 @@ SET sport_id = EXCLUDED.sport_id,
is_live = EXCLUDED.is_live, is_live = EXCLUDED.is_live,
source = EXCLUDED.source, source = EXCLUDED.source,
fetched_at = now(); fetched_at = now();
-- name: InsertEventSettings :exec -- name: SaveEventSettings :exec
INSERT INTO company_event_settings ( INSERT INTO company_event_settings (
company_id, company_id,
event_id, event_id,
@ -243,19 +243,7 @@ WHERE id = $1;
UPDATE events UPDATE events
SET is_monitored = $1 SET is_monitored = $1
WHERE id = $2; 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 -- name: DeleteEvent :exec
DELETE FROM events DELETE FROM events
WHERE id = $1; WHERE id = $1;

View File

@ -36,6 +36,10 @@ WHERE (
sport_id = sqlc.narg('sport_id') sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL OR sqlc.narg('sport_id') IS NULL
) )
AND (
name ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
ORDER BY name ASC ORDER BY name ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetAllLeaguesWithSettings :many -- name: GetAllLeaguesWithSettings :many
@ -58,6 +62,11 @@ WHERE (company_id = $1)
is_featured = sqlc.narg('is_featured') is_featured = sqlc.narg('is_featured')
OR sqlc.narg('is_featured') IS NULL 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, ORDER BY is_featured DESC,
name ASC name ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');

View File

@ -26,7 +26,7 @@ SET market_type = EXCLUDED.market_type,
raw_odds = EXCLUDED.raw_odds, raw_odds = EXCLUDED.raw_odds,
fetched_at = EXCLUDED.fetched_at, fetched_at = EXCLUDED.fetched_at,
expires_at = EXCLUDED.expires_at; expires_at = EXCLUDED.expires_at;
-- name: InsertOddSettings :exec -- name: SaveOddSettings :exec
INSERT INTO company_odd_settings ( INSERT INTO company_odd_settings (
company_id, company_id,
odds_market_id, odds_market_id,
@ -46,6 +46,10 @@ SELECT *
FROM odds_market_with_settings FROM odds_market_with_settings
WHERE company_id = $1 WHERE company_id = $1
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetOddByID :one
SELECT *
FROM odds_market_with_event
WHERE id = $1;
-- name: GetOddsByMarketID :one -- name: GetOddsByMarketID :one
SELECT * SELECT *
FROM odds_market_with_event FROM odds_market_with_event
@ -57,6 +61,11 @@ FROM odds_market_with_settings
WHERE market_id = $1 WHERE market_id = $1
AND event_id = $2 AND event_id = $2
AND company_id = $3; AND company_id = $3;
-- name: GetOddsWithSettingsByID :one
SELECT *
FROM odds_market_with_settings
WHERE id = $1
AND company_id = $2;
-- name: GetOddsByEventID :many -- name: GetOddsByEventID :many
SELECT * SELECT *
FROM odds_market_with_event FROM odds_market_with_event

View File

@ -654,40 +654,6 @@ func (q *Queries) InsertEvent(ctx context.Context, arg InsertEventParams) error
return err 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 const IsEventMonitored = `-- name: IsEventMonitored :one
SELECT is_monitored SELECT is_monitored
FROM events FROM events
@ -727,6 +693,40 @@ func (q *Queries) ListLiveEvents(ctx context.Context) ([]string, error) {
return items, nil 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 const UpdateEventMonitored = `-- name: UpdateEventMonitored :exec
UPDATE events UPDATE events
SET is_monitored = $1 SET is_monitored = $1
@ -743,40 +743,6 @@ func (q *Queries) UpdateEventMonitored(ctx context.Context, arg UpdateEventMonit
return err 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 const UpdateMatchResult = `-- name: UpdateMatchResult :exec
UPDATE events UPDATE events
SET score = $1, SET score = $1,

View File

@ -44,13 +44,18 @@ WHERE (
sport_id = $2 sport_id = $2
OR $2 IS NULL OR $2 IS NULL
) )
AND (
name ILIKE '%' || $3 || '%'
OR $3 IS NULL
)
ORDER BY name ASC ORDER BY name ASC
LIMIT $4 OFFSET $3 LIMIT $5 OFFSET $4
` `
type GetAllLeaguesParams struct { type GetAllLeaguesParams struct {
CountryCode pgtype.Text `json:"country_code"` CountryCode pgtype.Text `json:"country_code"`
SportID pgtype.Int4 `json:"sport_id"` SportID pgtype.Int4 `json:"sport_id"`
Query pgtype.Text `json:"query"`
Offset pgtype.Int4 `json:"offset"` Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"` 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, rows, err := q.db.Query(ctx, GetAllLeagues,
arg.CountryCode, arg.CountryCode,
arg.SportID, arg.SportID,
arg.Query,
arg.Offset, arg.Offset,
arg.Limit, arg.Limit,
) )
@ -109,9 +115,14 @@ WHERE (company_id = $1)
is_featured = $5 is_featured = $5
OR $5 IS NULL OR $5 IS NULL
) )
AND (
name ILIKE '%' || $6 || '%'
OR league_name ILIKE '%' || $6 || '%'
OR $6 IS NULL
)
ORDER BY is_featured DESC, ORDER BY is_featured DESC,
name ASC name ASC
LIMIT $7 OFFSET $6 LIMIT $8 OFFSET $7
` `
type GetAllLeaguesWithSettingsParams struct { type GetAllLeaguesWithSettingsParams struct {
@ -120,6 +131,7 @@ type GetAllLeaguesWithSettingsParams struct {
SportID pgtype.Int4 `json:"sport_id"` SportID pgtype.Int4 `json:"sport_id"`
IsActive pgtype.Bool `json:"is_active"` IsActive pgtype.Bool `json:"is_active"`
IsFeatured pgtype.Bool `json:"is_featured"` IsFeatured pgtype.Bool `json:"is_featured"`
Query pgtype.Text `json:"query"`
Offset pgtype.Int4 `json:"offset"` Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"` Limit pgtype.Int4 `json:"limit"`
} }
@ -131,6 +143,7 @@ func (q *Queries) GetAllLeaguesWithSettings(ctx context.Context, arg GetAllLeagu
arg.SportID, arg.SportID,
arg.IsActive, arg.IsActive,
arg.IsFeatured, arg.IsFeatured,
arg.Query,
arg.Offset, arg.Offset,
arg.Limit, arg.Limit,
) )

View File

@ -114,6 +114,34 @@ func (q *Queries) GetAllOddsWithSettings(ctx context.Context, arg GetAllOddsWith
return items, nil 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 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 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 FROM odds_market_with_event
@ -272,6 +300,39 @@ func (q *Queries) GetOddsWithSettingsByEventID(ctx context.Context, arg GetOddsW
return items, nil 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 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 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 FROM odds_market_with_settings
@ -307,36 +368,6 @@ func (q *Queries) GetOddsWithSettingsByMarketID(ctx context.Context, arg GetOdds
return i, err 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 const InsertOddsMarket = `-- name: InsertOddsMarket :exec
INSERT INTO odds_market ( INSERT INTO odds_market (
event_id, event_id,
@ -391,3 +422,33 @@ func (q *Queries) InsertOddsMarket(ctx context.Context, arg InsertOddsMarketPara
) )
return err 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
}

View File

@ -98,42 +98,45 @@ type BaseEventRes struct {
DefaultIsFeatured bool `json:"default_is_featured"` DefaultIsFeatured bool `json:"default_is_featured"`
DefaultIsActive bool `json:"default_is_active"` DefaultIsActive bool `json:"default_is_active"`
DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"` DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"`
Score string `json:"score,omitempty"` Score string `json:"score"`
MatchMinute int `json:"match_minute,omitempty"` MatchMinute int `json:"match_minute"`
TimerStatus string `json:"timer_status,omitempty"` TimerStatus string `json:"timer_status"`
AddedTime int `json:"added_time,omitempty"` AddedTime int `json:"added_time"`
MatchPeriod int `json:"match_period,omitempty"` MatchPeriod int `json:"match_period"`
IsLive bool `json:"is_live"` IsLive bool `json:"is_live"`
FetchedAt time.Time `json:"fetched_at"` FetchedAt time.Time `json:"fetched_at"`
} }
type EventWithSettings struct { type EventWithSettings struct {
ID string ID string
SportID int32 SportID int32
MatchName string MatchName string
HomeTeam string HomeTeam string
AwayTeam string AwayTeam string
HomeTeamID int64 HomeTeamID int64
AwayTeamID int64 AwayTeamID int64
HomeTeamImage string HomeTeamImage string
AwayTeamImage string AwayTeamImage string
LeagueID int64 LeagueID int64
LeagueName string LeagueName string
LeagueCC ValidString LeagueCC ValidString
StartTime time.Time StartTime time.Time
Source EventSource Source EventSource
Status EventStatus Status EventStatus
IsFeatured bool IsMonitored bool
IsMonitored bool IsFeatured bool
IsActive bool IsActive bool
WinningUpperLimit int32 WinningUpperLimit int32
Score ValidString DefaultIsFeatured bool
MatchMinute ValidInt DefaultIsActive bool
TimerStatus ValidString DefaultWinningUpperLimit int32
AddedTime ValidInt Score ValidString
MatchPeriod ValidInt MatchMinute ValidInt
IsLive bool TimerStatus ValidString
UpdatedAt time.Time AddedTime ValidInt
FetchedAt time.Time MatchPeriod ValidInt
IsLive bool
UpdatedAt time.Time
FetchedAt time.Time
} }
type CreateEvent struct { type CreateEvent struct {
@ -155,33 +158,36 @@ type CreateEvent struct {
} }
type EventWithSettingsRes struct { type EventWithSettingsRes struct {
ID string `json:"id"` ID string `json:"id"`
SportID int32 `json:"sport_id"` SportID int32 `json:"sport_id"`
MatchName string `json:"match_name"` MatchName string `json:"match_name"`
HomeTeam string `json:"home_team"` HomeTeam string `json:"home_team"`
AwayTeam string `json:"away_team"` AwayTeam string `json:"away_team"`
HomeTeamID int64 `json:"home_team_id"` HomeTeamID int64 `json:"home_team_id"`
AwayTeamID int64 `json:"away_team_id"` AwayTeamID int64 `json:"away_team_id"`
HomeTeamImage string `json:"home_team_image"` HomeTeamImage string `json:"home_team_image"`
AwayTeamImage string `json:"away_team_image"` AwayTeamImage string `json:"away_team_image"`
LeagueID int64 `json:"league_id"` LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"` LeagueName string `json:"league_name"`
LeagueCC string `json:"league_cc"` LeagueCC string `json:"league_cc"`
StartTime time.Time `json:"start_time"` StartTime time.Time `json:"start_time"`
Source EventSource `json:"source"` Source EventSource `json:"source"`
Status EventStatus `json:"status"` Status EventStatus `json:"status"`
IsFeatured bool `json:"is_featured"` IsMonitored bool `json:"is_monitored"`
IsMonitored bool `json:"is_monitored"` IsFeatured bool `json:"is_featured"`
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
WinningUpperLimit int32 `json:"winning_upper_limit"` WinningUpperLimit int32 `json:"winning_upper_limit"`
Score string `json:"score,omitempty"` DefaultIsFeatured bool `json:"default_is_featured"`
MatchMinute int `json:"match_minute,omitempty"` DefaultIsActive bool `json:"default_is_active"`
TimerStatus string `json:"timer_status,omitempty"` DefaultWinningUpperLimit int32 `json:"default_winning_upper_limit"`
AddedTime int `json:"added_time,omitempty"` Score string `json:"score,omitempty"`
MatchPeriod int `json:"match_period,omitempty"` MatchMinute int `json:"match_minute,omitempty"`
IsLive bool `json:"is_live"` TimerStatus string `json:"timer_status,omitempty"`
UpdatedAt time.Time `json:"updated_at"` AddedTime int `json:"added_time,omitempty"`
FetchedAt time.Time `json:"fetched_at"` 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 { type EventSettings struct {
@ -291,8 +297,8 @@ func ConvertCreateEvent(e CreateEvent) dbgen.InsertEventParams {
} }
} }
func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.InsertEventSettingsParams { func ConvertCreateEventSettings(eventSettings CreateEventSettings) dbgen.SaveEventSettingsParams {
return dbgen.InsertEventSettingsParams{ return dbgen.SaveEventSettingsParams{
CompanyID: eventSettings.CompanyID, CompanyID: eventSettings.CompanyID,
EventID: eventSettings.EventID, EventID: eventSettings.EventID,
IsActive: eventSettings.IsActive.ToPG(), IsActive: eventSettings.IsActive.ToPG(),
@ -318,13 +324,15 @@ func ConvertDBEventWithSetting(event dbgen.EventWithSetting) EventWithSettings {
Value: event.LeagueCc.String, Value: event.LeagueCc.String,
Valid: event.LeagueCc.Valid, Valid: event.LeagueCc.Valid,
}, },
StartTime: event.StartTime.Time.UTC(), StartTime: event.StartTime.Time.UTC(),
Source: EventSource(event.Source), Source: EventSource(event.Source),
Status: EventStatus(event.Status), Status: EventStatus(event.Status),
IsFeatured: event.IsFeatured, IsFeatured: event.IsFeatured,
IsMonitored: event.IsMonitored, IsMonitored: event.IsMonitored,
IsActive: event.IsActive, IsActive: event.IsActive,
WinningUpperLimit: event.WinningUpperLimit, DefaultIsFeatured: event.DefaultIsFeatured,
DefaultIsActive: event.DefaultIsActive,
DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
Score: ValidString{ Score: ValidString{
Value: event.Score.String, Value: event.Score.String,
Valid: event.Score.Valid, Valid: event.Score.Valid,
@ -359,8 +367,8 @@ func ConvertDBEventWithSettings(events []dbgen.EventWithSetting) []EventWithSett
return result return result
} }
func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.UpdateEventSettingsParams { func ConvertUpdateEventSettings(event CreateEventSettings) dbgen.SaveEventSettingsParams {
return dbgen.UpdateEventSettingsParams{ return dbgen.SaveEventSettingsParams{
EventID: event.EventID, EventID: event.EventID,
CompanyID: event.CompanyID, CompanyID: event.CompanyID,
IsActive: event.IsActive.ToPG(), IsActive: event.IsActive.ToPG(),
@ -409,32 +417,35 @@ func ConvertEventResList(events []BaseEvent) []BaseEventRes {
func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes { func ConvertEventWitSettingRes(event EventWithSettings) EventWithSettingsRes {
return EventWithSettingsRes{ return EventWithSettingsRes{
ID: event.ID, ID: event.ID,
SportID: event.SportID, SportID: event.SportID,
MatchName: event.MatchName, MatchName: event.MatchName,
HomeTeam: event.HomeTeam, HomeTeam: event.HomeTeam,
AwayTeam: event.AwayTeam, AwayTeam: event.AwayTeam,
HomeTeamID: event.HomeTeamID, HomeTeamID: event.HomeTeamID,
AwayTeamID: event.AwayTeamID, AwayTeamID: event.AwayTeamID,
HomeTeamImage: event.HomeTeamImage, HomeTeamImage: event.HomeTeamImage,
AwayTeamImage: event.AwayTeamImage, AwayTeamImage: event.AwayTeamImage,
LeagueID: event.LeagueID, LeagueID: event.LeagueID,
LeagueName: event.LeagueName, LeagueName: event.LeagueName,
LeagueCC: event.LeagueCC.Value, LeagueCC: event.LeagueCC.Value,
StartTime: event.StartTime.UTC(), StartTime: event.StartTime.UTC(),
Source: EventSource(event.Source), Source: EventSource(event.Source),
Status: EventStatus(event.Status), Status: EventStatus(event.Status),
IsFeatured: event.IsFeatured, IsFeatured: event.IsFeatured,
IsMonitored: event.IsMonitored, IsMonitored: event.IsMonitored,
IsActive: event.IsActive, IsActive: event.IsActive,
WinningUpperLimit: event.WinningUpperLimit, DefaultIsFeatured: event.DefaultIsFeatured,
Score: event.Score.Value, DefaultIsActive: event.DefaultIsActive,
MatchMinute: event.MatchMinute.Value, DefaultWinningUpperLimit: event.DefaultWinningUpperLimit,
TimerStatus: event.TimerStatus.Value, WinningUpperLimit: event.WinningUpperLimit,
AddedTime: event.AddedTime.Value, Score: event.Score.Value,
MatchPeriod: event.MatchPeriod.Value, MatchMinute: event.MatchMinute.Value,
IsLive: event.IsLive, TimerStatus: event.TimerStatus.Value,
FetchedAt: event.FetchedAt.UTC(), AddedTime: event.AddedTime.Value,
MatchPeriod: event.MatchPeriod.Value,
IsLive: event.IsLive,
FetchedAt: event.FetchedAt.UTC(),
} }
} }

View File

@ -8,24 +8,30 @@ import (
// The ID and the Bet365 IDs we have here are both gotten from the betapi // The ID and the Bet365 IDs we have here are both gotten from the betapi
type LeagueWithSettings struct { type LeagueWithSettings struct {
ID int64 ID int64
Name string Name string
CompanyID int64 CompanyID int64
CountryCode ValidString CountryCode ValidString
Bet365ID ValidInt32 Bet365ID ValidInt32
SportID int32 SportID int32
IsActive bool IsActive bool
IsFeatured bool IsFeatured bool
UpdatedAt time.Time DefaultIsActive bool
DefaultIsFeatured bool
UpdatedAt time.Time
} }
type LeagueWithSettingsRes struct { type LeagueWithSettingsRes struct {
ID int64 `json:"id" example:"1"` ID int64 `json:"id" example:"1"`
Name string `json:"name" example:"BPL"` Name string `json:"name" example:"BPL"`
CountryCode string `json:"cc" example:"uk"` CompanyID int64 `json:"company_id" example:"1"`
Bet365ID int32 `json:"bet365_id" example:"1121"` CountryCode string `json:"cc" example:"uk"`
IsActive bool `json:"is_active" example:"false"` Bet365ID int32 `json:"bet365_id" example:"1121"`
SportID int32 `json:"sport_id" example:"1"` IsActive bool `json:"is_active" example:"false"`
IsFeatured bool `json:"is_featured" 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 { type BaseLeague struct {
ID int64 ID int64
@ -82,6 +88,7 @@ type UpdateLeague struct {
} }
type LeagueFilter struct { type LeagueFilter struct {
Query ValidString
CountryCode ValidString CountryCode ValidString
SportID ValidInt32 SportID ValidInt32
IsActive ValidBool IsActive ValidBool
@ -154,6 +161,9 @@ func ConvertDBLeagueWithSetting(lws dbgen.LeagueWithSetting) LeagueWithSettings
SportID: lws.SportID, SportID: lws.SportID,
IsFeatured: lws.IsFeatured, IsFeatured: lws.IsFeatured,
UpdatedAt: lws.UpdatedAt.Time, UpdatedAt: lws.UpdatedAt.Time,
DefaultIsActive: lws.DefaultIsActive,
DefaultIsFeatured: lws.DefaultIsFeatured,
} }
} }
@ -174,3 +184,50 @@ func ConvertUpdateLeague(updateLeague UpdateLeague) dbgen.UpdateLeagueParams {
SportID: updateLeague.SportID.ToPG(), 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
}

View File

@ -61,6 +61,17 @@ type CreateOddMarketSettings struct {
CustomRawOdds []map[string]interface{} 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 { // type RawOddsByMarketID struct {
// ID int64 `json:"id"` // ID int64 `json:"id"`
// MarketName string `json:"market_name"` // MarketName string `json:"market_name"`
@ -136,12 +147,12 @@ func ConvertCreateOddMarket(oddMarket CreateOddMarket) (dbgen.InsertOddsMarketPa
}, nil }, nil
} }
func ConvertCreateOddMarketSetting(oms CreateOddMarketSettings) (dbgen.InsertOddSettingsParams, error) { func ConvertCreateOddMarketSetting(oms CreateOddMarketSettings) (dbgen.SaveOddSettingsParams, error) {
rawOddsBytes, err := json.Marshal(oms.CustomRawOdds) rawOddsBytes, err := json.Marshal(oms.CustomRawOdds)
if err != nil { if err != nil {
return dbgen.InsertOddSettingsParams{}, err return dbgen.SaveOddSettingsParams{}, err
} }
return dbgen.InsertOddSettingsParams{ return dbgen.SaveOddSettingsParams{
CompanyID: oms.CompanyID, CompanyID: oms.CompanyID,
OddsMarketID: oms.OddMarketID, OddsMarketID: oms.OddMarketID,
IsActive: oms.IsActive.ToPG(), IsActive: oms.IsActive.ToPG(),

View File

@ -35,6 +35,18 @@ type SettingListRes struct {
CashbackAmountCap float32 `json:"cashback_amount_cap"` 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 { type SaveSettingListReq struct {
SMSProvider *string `json:"sms_provider,omitempty"` SMSProvider *string `json:"sms_provider,omitempty"`
MaxNumberOfOutcomes *int64 `json:"max_number_of_outcomes,omitempty"` MaxNumberOfOutcomes *int64 `json:"max_number_of_outcomes,omitempty"`
@ -157,57 +169,105 @@ func (vsl *ValidSettingList) GetAllValid() map[string]*bool {
return settingValid return settingValid
} }
func setValidSetting[T any](settings map[string]*T, searchKey string, setVal T) error { // func setValidSetting[T any](settings map[string]*T, searchKey string, searchVal string, setVal func(string) (T, error)) error {
for key, setting := range settings { // 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 { 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 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 { func (vsl *ValidSettingList) SetCurrencySetting(searchKey string, searchVal string) error {
value, err := strconv.ParseInt(searchVal, 10, 64) for key, setting := range vsl.GetCurrencySettingsMap() {
if err != nil { if key == searchKey {
return err 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 { 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 { func (vsl *ValidSettingList) SetBoolSetting(searchKey string, searchVal string) error {
value, err := strconv.ParseBool(searchVal) for key, setting := range vsl.GetBoolSettingsMap() {
if err != nil {
return err 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 { func (vsl *ValidSettingList) SetFloat32Setting(searchKey string, searchVal string) error {
value, err := strconv.ParseFloat(searchVal, 32) for key, setting := range vsl.GetFloat32SettingsMap() {
if err != nil { if key == searchKey {
return err 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 { func (vsl *ValidSettingList) SetTimeSetting(searchKey string, searchVal string) error {
value, err := time.Parse(time.RFC3339, searchVal) for key, setting := range vsl.GetTimeSettingsMap() {
if err != nil { if key == searchKey {
return err 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 { 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 { for _, setter := range setters {
if err := setter(searchKey, searchVal); err != nil { if err := setter(searchKey, searchVal); err != nil {
if err == ErrSettingNotFound { if err == ErrSettingNotFound {
// fmt.Printf("setting is not found %v \n", searchKey)
continue // not this setter, try the next 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 return nil // successfully set
} }
@ -306,6 +367,7 @@ func validateSettings[T any](
var errs []string var errs []string
for key, s := range settings { for key, s := range settings {
if !customValidator(s) { if !customValidator(s) {
errs = append(errs, fmt.Sprintf("%v is invalid", key)) errs = append(errs, fmt.Sprintf("%v is invalid", key))
} }
} }
@ -378,6 +440,7 @@ func (vsl *ValidSettingList) ValidateAllSettings() error {
for _, validator := range validators { for _, validator := range validators {
if err := validator(); err != nil { if err := validator(); err != nil {
errs = append(errs, err.Error()) errs = append(errs, err.Error())
} }
} }
@ -410,12 +473,12 @@ func ConvertDBGlobalSettingList(settings []dbgen.GlobalSetting) (SettingList, er
if err == ErrSettingNotFound { if err == ErrSettingNotFound {
MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key)) 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 { if err := dbSettingList.ValidateAllSettings(); err != nil {
fmt.Printf("setting validation error: %v \n", err) MongoDBLogger.Warn("setting validation error", zap.Error(err), zap.Any("db_setting_list", dbSettingList))
MongoDBLogger.Warn("setting validation error", zap.Error(err))
return SettingList{}, err return SettingList{}, err
} }
@ -436,7 +499,6 @@ func ConvertDBOverrideSettingList(settings []dbgen.GetOverrideSettingsRow) (Sett
} }
if err := dbSettingList.ValidateAllSettings(); err != nil { 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))
return SettingList{}, err return SettingList{}, err
} }

View File

@ -16,9 +16,6 @@ func (s *Store) SaveEvent(ctx context.Context, e domain.CreateEvent) error {
return s.queries.InsertEvent(ctx, domain.ConvertCreateEvent(e)) 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) { func (s *Store) GetLiveEventIDs(ctx context.Context) ([]string, error) {
return s.queries.ListLiveEvents(ctx) 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) { func (s *Store) GetEventWithSettingByID(ctx context.Context, ID string, companyID int64) (domain.EventWithSettings, error) {
event, err := s.queries.GetEventWithSettingByID(ctx, dbgen.GetEventWithSettingByIDParams{ event, err := s.queries.GetEventWithSettingByID(ctx, dbgen.GetEventWithSettingByIDParams{
ID: ID, ID: ID,
CompanyID: companyID, CompanyID: companyID,
}) })
if err != nil { 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 { 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 { func (s *Store) DeleteEvent(ctx context.Context, eventID string) error {

View File

@ -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) { func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) {
l, err := s.queries.GetAllLeagues(ctx, dbgen.GetAllLeaguesParams{ l, err := s.queries.GetAllLeagues(ctx, dbgen.GetAllLeaguesParams{
Query: filter.Query.ToPG(),
CountryCode: filter.CountryCode.ToPG(), CountryCode: filter.CountryCode.ToPG(),
SportID: filter.SportID.ToPG(), SportID: filter.SportID.ToPG(),
Limit: pgtype.Int4{ 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) { func (s *Store) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, error) {
l, err := s.queries.GetAllLeaguesWithSettings(ctx, dbgen.GetAllLeaguesWithSettingsParams{ l, err := s.queries.GetAllLeaguesWithSettings(ctx, dbgen.GetAllLeaguesWithSettingsParams{
Query: filter.Query.ToPG(),
CompanyID: companyID, CompanyID: companyID,
CountryCode: filter.CountryCode.ToPG(), CountryCode: filter.CountryCode.ToPG(),
SportID: filter.SportID.ToPG(), SportID: filter.SportID.ToPG(),

View File

@ -97,6 +97,21 @@ func (s *Store) GetAllOddsWithSettings(ctx context.Context, companyID int64, fil
return domainOdds, nil 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) { func (s *Store) GetOddsByMarketID(ctx context.Context, marketID string, eventID string) (domain.OddMarket, error) {
odds, err := s.queries.GetOddsByMarketID(ctx, dbgen.GetOddsByMarketIDParams{ odds, err := s.queries.GetOddsByMarketID(ctx, dbgen.GetOddsByMarketIDParams{
@ -134,6 +149,25 @@ func (s *Store) GetOddsWithSettingsByMarketID(ctx context.Context, marketID stri
return convertedOdd, nil 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) { func (s *Store) GetOddsByEventID(ctx context.Context, upcomingID string, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) {
odds, err := s.queries.GetOddsByEventID(ctx, dbgen.GetOddsByEventIDParams{ odds, err := s.queries.GetOddsByEventID(ctx, dbgen.GetOddsByEventIDParams{
EventID: upcomingID, 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 { func (s *Store) DeleteOddsForEvent(ctx context.Context, eventID string) error {
return s.queries.DeleteOddsForEvent(ctx, eventID) 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)
}

View File

@ -17,6 +17,11 @@ type Service interface {
GetALLPrematchOdds(ctx context.Context) ([]domain.OddMarket, error) GetALLPrematchOdds(ctx context.Context) ([]domain.OddMarket, error)
// GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.OddMarket, error) // GetRawOddsByMarketID(ctx context.Context, marketID string, upcomingID string) (domain.OddMarket, error)
DeleteOddsForEvent(ctx context.Context, eventID string) 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 // Odd History
InsertOddHistory(ctx context.Context, odd domain.CreateOddHistory) (domain.OddHistory, error) InsertOddHistory(ctx context.Context, odd domain.CreateOddHistory) (domain.OddHistory, error)

View File

@ -705,6 +705,46 @@ func (s *ServiceImpl) GetAllOddsWithSettings(ctx context.Context, companyID int6
return s.store.GetAllOddsWithSettings(ctx, companyID, filter) 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) { func (s *ServiceImpl) GetOddsByMarketID(ctx context.Context, marketID string, eventID string) (domain.OddMarket, error) {
rows, err := s.store.GetOddsByMarketID(ctx, marketID, eventID) rows, err := s.store.GetOddsByMarketID(ctx, marketID, eventID)
if err != nil { if err != nil {
@ -722,6 +762,10 @@ func (s *ServiceImpl) GetOddsWithSettingsByMarketID(ctx context.Context, marketI
return rows, nil 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) { func (s *ServiceImpl) GetOddsByEventID(ctx context.Context, upcomingID string, filter domain.OddMarketWithEventFilter) ([]domain.OddMarket, error) {
return s.store.GetOddsByEventID(ctx, upcomingID, filter) return s.store.GetOddsByEventID(ctx, upcomingID, filter)
} }

View File

@ -511,7 +511,7 @@ type UpdateEventSettingsReq struct {
// @Success 200 {object} response.APIResponse // @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse // @Failure 400 {object} response.APIResponse
// @Failure 500 {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 { func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64) companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid { if !companyID.Valid {
@ -523,7 +523,7 @@ func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error {
var req UpdateEventSettingsReq var req UpdateEventSettingsReq
if err := c.BodyParser(&req); err != nil { 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.String("eventID", eventID),
zap.Error(err), zap.Error(err),
) )
@ -543,7 +543,7 @@ func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error {
for field, msg := range valErrs { for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg) 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))..., append(logFields, zap.String("errMsg", errMsg))...,
) )
return fiber.NewError(fiber.StatusBadRequest, errMsg) return fiber.NewError(fiber.StatusBadRequest, errMsg)
@ -557,7 +557,63 @@ func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error {
}) })
if err != nil { 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()) return fiber.NewError(fiber.StatusInternalServerError, err.Error())
} }

View File

@ -33,6 +33,12 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
Valid: true, Valid: true,
} }
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
countryCodeQuery := c.Query("cc") countryCodeQuery := c.Query("cc")
countryCode := domain.ValidString{ countryCode := domain.ValidString{
Value: countryCodeQuery, Value: countryCodeQuery,
@ -73,6 +79,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
zap.Bool("is_active_valid", isActive.Valid), zap.Bool("is_active_valid", isActive.Valid),
zap.String("cc_query", countryCodeQuery), zap.String("cc_query", countryCodeQuery),
zap.String("cc", countryCode.Value), zap.String("cc", countryCode.Value),
zap.String("query", searchQuery),
zap.Bool("cc_valid", countryCode.Valid), zap.Bool("cc_valid", countryCode.Valid),
zap.String("sport_id_query", sportIDQuery), zap.String("sport_id_query", sportIDQuery),
zap.Int32("sport_id", sportID.Value), zap.Int32("sport_id", sportID.Value),
@ -85,6 +92,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
SportID: sportID, SportID: sportID,
Limit: limit, Limit: limit,
Offset: offset, Offset: offset,
Query: searchString,
}) })
if err != nil { 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 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 // GetAllLeaguesForTenant godoc
@ -125,6 +136,11 @@ func (h *Handler) GetAllLeaguesForTenant(c *fiber.Ctx) error {
Valid: true, Valid: true,
} }
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
countryCodeQuery := c.Query("cc") countryCodeQuery := c.Query("cc")
countryCode := domain.ValidString{ countryCode := domain.ValidString{
Value: countryCodeQuery, Value: countryCodeQuery,
@ -179,6 +195,7 @@ func (h *Handler) GetAllLeaguesForTenant(c *fiber.Ctx) error {
SportID: sportID, SportID: sportID,
Limit: limit, Limit: limit,
Offset: offset, Offset: offset,
Query: searchString,
}) })
if err != nil { 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))...) 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 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 { type SetLeagueActiveReq struct {

View File

@ -1,6 +1,7 @@
package handlers package handlers
import ( import (
"fmt"
"strconv" "strconv"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "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) 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)
}

View File

@ -17,12 +17,15 @@ func (h *Handler) GetGlobalSettingList(c *fiber.Ctx) error {
h.mongoLoggerSvc.Error("Failed to fetch settings", h.mongoLoggerSvc.Error("Failed to fetch settings",
zap.Int("status_code", fiber.StatusInternalServerError), zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err), zap.Error(err),
zap.Time("timestamp", time.Now()), zap.Time("timestamp", time.Now()),
) )
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get setting list:"+err.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)
} }
func (h *Handler) GetGlobalSettingByKey(c *fiber.Ctx) error { 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 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 { 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 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} // /api/v1/{tenant_slug}/settings/{key}

View File

@ -58,7 +58,7 @@ func (a *App) initAppRoutes() {
a.fiber.Get("/", func(c *fiber.Ctx) error { a.fiber.Get("/", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{ return c.JSON(fiber.Map{
"message": "Welcome to the FortuneBet API", "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", h.GetAllTenantOdds)
tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID) tenant.Get("/odds/upcoming/:upcoming_id", h.GetTenantOddsByUpcomingID)
tenant.Get("/odds/upcoming/:upcoming_id/market/:market_id", h.GetTenantOddsByMarketID) 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", a.authMiddleware, h.GetAllUpcomingEvents)
groupV1.Get("/events/:id", a.authMiddleware, h.GetUpcomingEventByID) groupV1.Get("/events/:id", a.authMiddleware, h.GetUpcomingEventByID)
groupV1.Delete("/events/:id", a.authMiddleware, a.SuperAdminOnly, h.SetEventStatusToRemoved) 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", h.GetTenantUpcomingEvents)
tenant.Get("/events/:id", h.GetTenantEventByID) tenant.Get("/events/:id", h.GetTenantEventByID)