favourtie game and virtual games + providers orchestration fixes
This commit is contained in:
parent
1c7e076be5
commit
299825e797
|
|
@ -71,6 +71,15 @@ CREATE TABLE IF NOT EXISTS virtual_games (
|
||||||
);
|
);
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS ux_virtual_games_provider_game ON virtual_games (provider_id, game_id);
|
CREATE UNIQUE INDEX IF NOT EXISTS ux_virtual_games_provider_game ON virtual_games (provider_id, game_id);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS virtual_game_favourites (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
game_id BIGINT NOT NULL REFERENCES virtual_games(id) ON DELETE CASCADE,
|
||||||
|
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(id) ON DELETE CASCADE,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE (game_id, user_id)
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS virtual_game_reports (
|
CREATE TABLE IF NOT EXISTS virtual_game_reports (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
game_id VARCHAR(150) NOT NULL REFERENCES virtual_games(game_id) ON DELETE CASCADE,
|
game_id VARCHAR(150) NOT NULL REFERENCES virtual_games(game_id) ON DELETE CASCADE,
|
||||||
|
|
|
||||||
|
|
@ -200,17 +200,28 @@ WHERE vgt.transaction_type = 'BET'
|
||||||
AND vgt.created_at BETWEEN $1 AND $2
|
AND vgt.created_at BETWEEN $1 AND $2
|
||||||
GROUP BY c.name,
|
GROUP BY c.name,
|
||||||
vg.name;
|
vg.name;
|
||||||
|
|
||||||
-- name: AddFavoriteGame :exec
|
-- name: AddFavoriteGame :exec
|
||||||
INSERT INTO favorite_games (user_id, game_id, created_at)
|
INSERT INTO virtual_game_favourites (user_id, game_id, provider_id, created_at)
|
||||||
VALUES ($1, $2, NOW()) ON CONFLICT (user_id, game_id) DO NOTHING;
|
VALUES ($1, $2, $3, NOW())
|
||||||
|
ON CONFLICT (game_id, user_id) DO NOTHING;
|
||||||
|
|
||||||
-- name: RemoveFavoriteGame :exec
|
-- name: RemoveFavoriteGame :exec
|
||||||
DELETE FROM favorite_games
|
DELETE FROM virtual_game_favourites
|
||||||
WHERE user_id = $1
|
WHERE user_id = $1 AND game_id = $2 AND provider_id = $3;
|
||||||
AND game_id = $2;
|
|
||||||
-- name: ListFavoriteGames :many
|
-- name: GetUserFavoriteGamesPaginated :many
|
||||||
SELECT game_id
|
SELECT
|
||||||
FROM favorite_games
|
vg.*
|
||||||
WHERE user_id = $1;
|
FROM virtual_games vg
|
||||||
|
JOIN virtual_game_favourites vf
|
||||||
|
ON vf.game_id = vg.id
|
||||||
|
WHERE
|
||||||
|
vf.user_id = $1
|
||||||
|
AND ($2::varchar IS NULL OR vf.provider_id = $2)
|
||||||
|
ORDER BY vf.created_at DESC
|
||||||
|
LIMIT $3 OFFSET $4;
|
||||||
|
|
||||||
-- name: CreateVirtualGame :one
|
-- name: CreateVirtualGame :one
|
||||||
INSERT INTO virtual_games (
|
INSERT INTO virtual_games (
|
||||||
game_id,
|
game_id,
|
||||||
|
|
|
||||||
42
docs/docs.go
42
docs/docs.go
|
|
@ -8108,16 +8108,42 @@ const docTemplate = `{
|
||||||
"VirtualGames - Favourites"
|
"VirtualGames - Favourites"
|
||||||
],
|
],
|
||||||
"summary": "Get user's favorite games",
|
"summary": "Get user's favorite games",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Filter by provider ID",
|
||||||
|
"name": "providerID",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Number of results to return",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Results offset",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/domain.GameRecommendation"
|
"$ref": "#/definitions/domain.UnifiedGame"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.ErrorResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
"500": {
|
"500": {
|
||||||
"description": "Internal Server Error",
|
"description": "Internal Server Error",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|
@ -8140,7 +8166,7 @@ const docTemplate = `{
|
||||||
"summary": "Add game to favorites",
|
"summary": "Add game to favorites",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "Game ID to add",
|
"description": "Game ID and Provider ID to add",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
|
|
@ -8188,13 +8214,20 @@ const docTemplate = `{
|
||||||
"name": "gameID",
|
"name": "gameID",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Provider ID of the game",
|
||||||
|
"name": "providerID",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "removed",
|
"description": "removed",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"$ref": "#/definitions/domain.Response"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
|
|
@ -12740,6 +12773,9 @@ const docTemplate = `{
|
||||||
"properties": {
|
"properties": {
|
||||||
"game_id": {
|
"game_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"provider_id": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -8100,16 +8100,42 @@
|
||||||
"VirtualGames - Favourites"
|
"VirtualGames - Favourites"
|
||||||
],
|
],
|
||||||
"summary": "Get user's favorite games",
|
"summary": "Get user's favorite games",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Filter by provider ID",
|
||||||
|
"name": "providerID",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Number of results to return",
|
||||||
|
"name": "limit",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Results offset",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "OK",
|
"description": "OK",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/domain.GameRecommendation"
|
"$ref": "#/definitions/domain.UnifiedGame"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.ErrorResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
"500": {
|
"500": {
|
||||||
"description": "Internal Server Error",
|
"description": "Internal Server Error",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|
@ -8132,7 +8158,7 @@
|
||||||
"summary": "Add game to favorites",
|
"summary": "Add game to favorites",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "Game ID to add",
|
"description": "Game ID and Provider ID to add",
|
||||||
"name": "body",
|
"name": "body",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
|
|
@ -8180,13 +8206,20 @@
|
||||||
"name": "gameID",
|
"name": "gameID",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Provider ID of the game",
|
||||||
|
"name": "providerID",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "removed",
|
"description": "removed",
|
||||||
"schema": {
|
"schema": {
|
||||||
"type": "string"
|
"$ref": "#/definitions/domain.Response"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
|
|
@ -12732,6 +12765,9 @@
|
||||||
"properties": {
|
"properties": {
|
||||||
"game_id": {
|
"game_id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"provider_id": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1430,6 +1430,8 @@ definitions:
|
||||||
properties:
|
properties:
|
||||||
game_id:
|
game_id:
|
||||||
type: integer
|
type: integer
|
||||||
|
provider_id:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
domain.FreeSpinRequest:
|
domain.FreeSpinRequest:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -9783,6 +9785,19 @@ paths:
|
||||||
/api/v1/virtual-game/favorites:
|
/api/v1/virtual-game/favorites:
|
||||||
get:
|
get:
|
||||||
description: Lists the games that the user marked as favorite
|
description: Lists the games that the user marked as favorite
|
||||||
|
parameters:
|
||||||
|
- description: Filter by provider ID
|
||||||
|
in: query
|
||||||
|
name: providerID
|
||||||
|
type: string
|
||||||
|
- description: Number of results to return
|
||||||
|
in: query
|
||||||
|
name: limit
|
||||||
|
type: integer
|
||||||
|
- description: Results offset
|
||||||
|
in: query
|
||||||
|
name: offset
|
||||||
|
type: integer
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
|
|
@ -9790,8 +9805,12 @@ paths:
|
||||||
description: OK
|
description: OK
|
||||||
schema:
|
schema:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/domain.GameRecommendation'
|
$ref: '#/definitions/domain.UnifiedGame'
|
||||||
type: array
|
type: array
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.ErrorResponse'
|
||||||
"500":
|
"500":
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
|
|
@ -9804,7 +9823,7 @@ paths:
|
||||||
- application/json
|
- application/json
|
||||||
description: Adds a game to the user's favorite games list
|
description: Adds a game to the user's favorite games list
|
||||||
parameters:
|
parameters:
|
||||||
- description: Game ID to add
|
- description: Game ID and Provider ID to add
|
||||||
in: body
|
in: body
|
||||||
name: body
|
name: body
|
||||||
required: true
|
required: true
|
||||||
|
|
@ -9837,13 +9856,18 @@ paths:
|
||||||
name: gameID
|
name: gameID
|
||||||
required: true
|
required: true
|
||||||
type: integer
|
type: integer
|
||||||
|
- description: Provider ID of the game
|
||||||
|
in: query
|
||||||
|
name: providerID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: removed
|
description: removed
|
||||||
schema:
|
schema:
|
||||||
type: string
|
$ref: '#/definitions/domain.Response'
|
||||||
"400":
|
"400":
|
||||||
description: Bad Request
|
description: Bad Request
|
||||||
schema:
|
schema:
|
||||||
|
|
|
||||||
|
|
@ -1157,9 +1157,16 @@ type VirtualGame struct {
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VirtualGameFavourite struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
GameID int64 `json:"game_id"`
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
ProviderID string `json:"provider_id"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
type VirtualGameHistory struct {
|
type VirtualGameHistory struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
SessionID pgtype.Text `json:"session_id"`
|
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
CompanyID pgtype.Int8 `json:"company_id"`
|
CompanyID pgtype.Int8 `json:"company_id"`
|
||||||
Provider pgtype.Text `json:"provider"`
|
Provider pgtype.Text `json:"provider"`
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,19 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const AddFavoriteGame = `-- name: AddFavoriteGame :exec
|
const AddFavoriteGame = `-- name: AddFavoriteGame :exec
|
||||||
INSERT INTO favorite_games (user_id, game_id, created_at)
|
INSERT INTO virtual_game_favourites (user_id, game_id, provider_id, created_at)
|
||||||
VALUES ($1, $2, NOW()) ON CONFLICT (user_id, game_id) DO NOTHING
|
VALUES ($1, $2, $3, NOW())
|
||||||
|
ON CONFLICT (game_id, user_id) DO NOTHING
|
||||||
`
|
`
|
||||||
|
|
||||||
type AddFavoriteGameParams struct {
|
type AddFavoriteGameParams struct {
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
GameID int64 `json:"game_id"`
|
GameID int64 `json:"game_id"`
|
||||||
|
ProviderID string `json:"provider_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) AddFavoriteGame(ctx context.Context, arg AddFavoriteGameParams) error {
|
func (q *Queries) AddFavoriteGame(ctx context.Context, arg AddFavoriteGameParams) error {
|
||||||
_, err := q.db.Exec(ctx, AddFavoriteGame, arg.UserID, arg.GameID)
|
_, err := q.db.Exec(ctx, AddFavoriteGame, arg.UserID, arg.GameID, arg.ProviderID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,7 +139,7 @@ func (q *Queries) CreateVirtualGame(ctx context.Context, arg CreateVirtualGamePa
|
||||||
|
|
||||||
const CreateVirtualGameHistory = `-- name: CreateVirtualGameHistory :one
|
const CreateVirtualGameHistory = `-- name: CreateVirtualGameHistory :one
|
||||||
INSERT INTO virtual_game_histories (
|
INSERT INTO virtual_game_histories (
|
||||||
session_id,
|
-- session_id,
|
||||||
user_id,
|
user_id,
|
||||||
company_id,
|
company_id,
|
||||||
provider,
|
provider,
|
||||||
|
|
@ -161,11 +163,11 @@ VALUES (
|
||||||
$8,
|
$8,
|
||||||
$9,
|
$9,
|
||||||
$10,
|
$10,
|
||||||
$11,
|
$11
|
||||||
$12
|
-- $12
|
||||||
)
|
)
|
||||||
RETURNING id,
|
RETURNING id,
|
||||||
session_id,
|
-- session_id,
|
||||||
user_id,
|
user_id,
|
||||||
company_id,
|
company_id,
|
||||||
provider,
|
provider,
|
||||||
|
|
@ -182,7 +184,6 @@ RETURNING id,
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateVirtualGameHistoryParams struct {
|
type CreateVirtualGameHistoryParams struct {
|
||||||
SessionID pgtype.Text `json:"session_id"`
|
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
CompanyID pgtype.Int8 `json:"company_id"`
|
CompanyID pgtype.Int8 `json:"company_id"`
|
||||||
Provider pgtype.Text `json:"provider"`
|
Provider pgtype.Text `json:"provider"`
|
||||||
|
|
@ -198,7 +199,6 @@ type CreateVirtualGameHistoryParams struct {
|
||||||
|
|
||||||
func (q *Queries) CreateVirtualGameHistory(ctx context.Context, arg CreateVirtualGameHistoryParams) (VirtualGameHistory, error) {
|
func (q *Queries) CreateVirtualGameHistory(ctx context.Context, arg CreateVirtualGameHistoryParams) (VirtualGameHistory, error) {
|
||||||
row := q.db.QueryRow(ctx, CreateVirtualGameHistory,
|
row := q.db.QueryRow(ctx, CreateVirtualGameHistory,
|
||||||
arg.SessionID,
|
|
||||||
arg.UserID,
|
arg.UserID,
|
||||||
arg.CompanyID,
|
arg.CompanyID,
|
||||||
arg.Provider,
|
arg.Provider,
|
||||||
|
|
@ -214,7 +214,6 @@ func (q *Queries) CreateVirtualGameHistory(ctx context.Context, arg CreateVirtua
|
||||||
var i VirtualGameHistory
|
var i VirtualGameHistory
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ID,
|
&i.ID,
|
||||||
&i.SessionID,
|
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.CompanyID,
|
&i.CompanyID,
|
||||||
&i.Provider,
|
&i.Provider,
|
||||||
|
|
@ -662,6 +661,67 @@ func (q *Queries) GetAllVirtualGames(ctx context.Context, arg GetAllVirtualGames
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetUserFavoriteGamesPaginated = `-- name: GetUserFavoriteGamesPaginated :many
|
||||||
|
SELECT
|
||||||
|
vg.id, vg.game_id, vg.provider_id, vg.name, vg.category, vg.device_type, vg.volatility, vg.rtp, vg.has_demo, vg.has_free_bets, vg.bets, vg.thumbnail, vg.status, vg.created_at, vg.updated_at
|
||||||
|
FROM virtual_games vg
|
||||||
|
JOIN virtual_game_favourites vf
|
||||||
|
ON vf.game_id = vg.id
|
||||||
|
WHERE
|
||||||
|
vf.user_id = $1
|
||||||
|
AND ($2::varchar IS NULL OR vf.provider_id = $2)
|
||||||
|
ORDER BY vf.created_at DESC
|
||||||
|
LIMIT $3 OFFSET $4
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetUserFavoriteGamesPaginatedParams struct {
|
||||||
|
UserID int64 `json:"user_id"`
|
||||||
|
Column2 string `json:"column_2"`
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetUserFavoriteGamesPaginated(ctx context.Context, arg GetUserFavoriteGamesPaginatedParams) ([]VirtualGame, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetUserFavoriteGamesPaginated,
|
||||||
|
arg.UserID,
|
||||||
|
arg.Column2,
|
||||||
|
arg.Limit,
|
||||||
|
arg.Offset,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []VirtualGame
|
||||||
|
for rows.Next() {
|
||||||
|
var i VirtualGame
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GameID,
|
||||||
|
&i.ProviderID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Category,
|
||||||
|
&i.DeviceType,
|
||||||
|
&i.Volatility,
|
||||||
|
&i.Rtp,
|
||||||
|
&i.HasDemo,
|
||||||
|
&i.HasFreeBets,
|
||||||
|
&i.Bets,
|
||||||
|
&i.Thumbnail,
|
||||||
|
&i.Status,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const GetVirtualGameProviderByID = `-- name: GetVirtualGameProviderByID :one
|
const GetVirtualGameProviderByID = `-- name: GetVirtualGameProviderByID :one
|
||||||
SELECT id,
|
SELECT id,
|
||||||
provider_id,
|
provider_id,
|
||||||
|
|
@ -874,32 +934,6 @@ func (q *Queries) GetVirtualGameTransactionByExternalID(ctx context.Context, ext
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListFavoriteGames = `-- name: ListFavoriteGames :many
|
|
||||||
SELECT game_id
|
|
||||||
FROM favorite_games
|
|
||||||
WHERE user_id = $1
|
|
||||||
`
|
|
||||||
|
|
||||||
func (q *Queries) ListFavoriteGames(ctx context.Context, userID int64) ([]int64, error) {
|
|
||||||
rows, err := q.db.Query(ctx, ListFavoriteGames, userID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer rows.Close()
|
|
||||||
var items []int64
|
|
||||||
for rows.Next() {
|
|
||||||
var game_id int64
|
|
||||||
if err := rows.Scan(&game_id); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
items = append(items, game_id)
|
|
||||||
}
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return items, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const ListVirtualGameProviderReportsByGamesPlayedAsc = `-- name: ListVirtualGameProviderReportsByGamesPlayedAsc :many
|
const ListVirtualGameProviderReportsByGamesPlayedAsc = `-- name: ListVirtualGameProviderReportsByGamesPlayedAsc :many
|
||||||
SELECT id, provider_id, report_date, total_games_played, total_bets, total_payouts, total_profit, total_players, report_type, created_at, updated_at
|
SELECT id, provider_id, report_date, total_games_played, total_bets, total_payouts, total_profit, total_players, report_type, created_at, updated_at
|
||||||
FROM virtual_game_provider_reports
|
FROM virtual_game_provider_reports
|
||||||
|
|
@ -1025,18 +1059,18 @@ func (q *Queries) ListVirtualGameProviders(ctx context.Context, arg ListVirtualG
|
||||||
}
|
}
|
||||||
|
|
||||||
const RemoveFavoriteGame = `-- name: RemoveFavoriteGame :exec
|
const RemoveFavoriteGame = `-- name: RemoveFavoriteGame :exec
|
||||||
DELETE FROM favorite_games
|
DELETE FROM virtual_game_favourites
|
||||||
WHERE user_id = $1
|
WHERE user_id = $1 AND game_id = $2 AND provider_id = $3
|
||||||
AND game_id = $2
|
|
||||||
`
|
`
|
||||||
|
|
||||||
type RemoveFavoriteGameParams struct {
|
type RemoveFavoriteGameParams struct {
|
||||||
UserID int64 `json:"user_id"`
|
UserID int64 `json:"user_id"`
|
||||||
GameID int64 `json:"game_id"`
|
GameID int64 `json:"game_id"`
|
||||||
|
ProviderID string `json:"provider_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) RemoveFavoriteGame(ctx context.Context, arg RemoveFavoriteGameParams) error {
|
func (q *Queries) RemoveFavoriteGame(ctx context.Context, arg RemoveFavoriteGameParams) error {
|
||||||
_, err := q.db.Exec(ctx, RemoveFavoriteGame, arg.UserID, arg.GameID)
|
_, err := q.db.Exec(ctx, RemoveFavoriteGame, arg.UserID, arg.GameID, arg.ProviderID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,10 @@ type Response struct {
|
||||||
MetaData interface{} `json:"metadata"`
|
MetaData interface{} `json:"metadata"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CallbackErrorResponse struct {
|
// type CallbackErrorResponse struct {
|
||||||
Error string `json:"error,omitempty"`
|
// ErrorData interface
|
||||||
}
|
// Error string `json:"error,omitempty"`
|
||||||
|
// }
|
||||||
|
|
||||||
func CalculateWinnings(amount Currency, totalOdds float32) Currency {
|
func CalculateWinnings(amount Currency, totalOdds float32) Currency {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
|
type VeliCallbackErrorResponse struct {
|
||||||
|
ErrorStatus int `json:"errorStatus"`
|
||||||
|
ErrorData struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
} `json:"errorData"`
|
||||||
|
}
|
||||||
|
|
||||||
type ProviderRequest struct {
|
type ProviderRequest struct {
|
||||||
BrandID string `json:"brandId"`
|
BrandID string `json:"brandId"`
|
||||||
ExtraData bool `json:"extraData"`
|
ExtraData bool `json:"extraData"`
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ type FavoriteGame struct {
|
||||||
|
|
||||||
type FavoriteGameRequest struct {
|
type FavoriteGameRequest struct {
|
||||||
GameID int64 `json:"game_id"`
|
GameID int64 `json:"game_id"`
|
||||||
|
ProviderID string `json:"provider_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type FavoriteGameResponse struct {
|
type FavoriteGameResponse struct {
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,14 @@ type VirtualGameRepository interface {
|
||||||
GetVirtualGameTransactionByExternalID(ctx context.Context, externalID string) (*domain.VirtualGameTransaction, error)
|
GetVirtualGameTransactionByExternalID(ctx context.Context, externalID string) (*domain.VirtualGameTransaction, error)
|
||||||
UpdateVirtualGameTransactionStatus(ctx context.Context, id int64, status string) error
|
UpdateVirtualGameTransactionStatus(ctx context.Context, id int64, status string) error
|
||||||
// WithTransaction(ctx context.Context, fn func(ctx context.Context) error) error
|
// WithTransaction(ctx context.Context, fn func(ctx context.Context) error) error
|
||||||
AddFavoriteGame(ctx context.Context, userID, gameID int64) error
|
AddFavoriteGame(ctx context.Context, userID, gameID int64, providerID string) error
|
||||||
RemoveFavoriteGame(ctx context.Context, userID, gameID int64) error
|
RemoveFavoriteGame(ctx context.Context, userID, gameID int64, providerID string) error
|
||||||
ListFavoriteGames(ctx context.Context, userID int64) ([]int64, error)
|
ListFavoriteGames(
|
||||||
|
ctx context.Context,
|
||||||
|
userID int64,
|
||||||
|
providerID *string,
|
||||||
|
limit, offset int32,
|
||||||
|
) ([]dbgen.VirtualGame, error)
|
||||||
// GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
// GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
||||||
GetUserGameHistory(ctx context.Context, userID int64) ([]domain.VirtualGameHistory, error)
|
GetUserGameHistory(ctx context.Context, userID int64) ([]domain.VirtualGameHistory, error)
|
||||||
CreateVirtualGameHistory(ctx context.Context, his *domain.VirtualGameHistory) error
|
CreateVirtualGameHistory(ctx context.Context, his *domain.VirtualGameHistory) error
|
||||||
|
|
@ -138,24 +142,46 @@ func (r *VirtualGameRepo) UpdateVirtualGameProviderEnabled(ctx context.Context,
|
||||||
return r.store.queries.UpdateVirtualGameProviderEnabled(ctx, params)
|
return r.store.queries.UpdateVirtualGameProviderEnabled(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *VirtualGameRepo) AddFavoriteGame(ctx context.Context, userID, gameID int64) error {
|
func (r *VirtualGameRepo) AddFavoriteGame(ctx context.Context, userID, gameID int64, providerID string) error {
|
||||||
params := dbgen.AddFavoriteGameParams{
|
params := dbgen.AddFavoriteGameParams{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
GameID: gameID,
|
GameID: gameID,
|
||||||
|
ProviderID: providerID,
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.store.queries.AddFavoriteGame(ctx, params)
|
return r.store.queries.AddFavoriteGame(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *VirtualGameRepo) RemoveFavoriteGame(ctx context.Context, userID, gameID int64) error {
|
func (r *VirtualGameRepo) RemoveFavoriteGame(ctx context.Context, userID, gameID int64, providerID string) error {
|
||||||
params := dbgen.RemoveFavoriteGameParams{
|
params := dbgen.RemoveFavoriteGameParams{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
GameID: gameID,
|
GameID: gameID,
|
||||||
|
ProviderID: providerID,
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.store.queries.RemoveFavoriteGame(ctx, params)
|
return r.store.queries.RemoveFavoriteGame(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *VirtualGameRepo) ListFavoriteGames(ctx context.Context, userID int64) ([]int64, error) {
|
func (r *VirtualGameRepo) ListFavoriteGames(
|
||||||
return r.store.queries.ListFavoriteGames(ctx, userID)
|
ctx context.Context,
|
||||||
|
userID int64,
|
||||||
|
providerID *string,
|
||||||
|
limit, offset int32,
|
||||||
|
) ([]dbgen.VirtualGame, error) {
|
||||||
|
|
||||||
|
params := dbgen.GetUserFavoriteGamesPaginatedParams{
|
||||||
|
UserID: userID,
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
}
|
||||||
|
|
||||||
|
if providerID != nil {
|
||||||
|
params.Column2 = *providerID
|
||||||
|
} else {
|
||||||
|
params.Column2 = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.store.queries.GetUserFavoriteGamesPaginated(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *VirtualGameRepo) CountVirtualGameProviders(ctx context.Context) (int64, error) {
|
func (r *VirtualGameRepo) CountVirtualGameProviders(ctx context.Context) (int64, error) {
|
||||||
|
|
|
||||||
71
internal/services/virtualGame/orchestration/favourites.go
Normal file
71
internal/services/virtualGame/orchestration/favourites.go
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
package orchestration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Service) AddFavoriteGame(ctx context.Context, userID, gameID int64, providerID string) error {
|
||||||
|
return s.repo.AddFavoriteGame(ctx, userID, gameID, providerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) RemoveFavoriteGame(ctx context.Context, userID, gameID int64, providerID string) error {
|
||||||
|
return s.repo.RemoveFavoriteGame(ctx, userID, gameID, providerID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) ListFavoriteGames(
|
||||||
|
ctx context.Context,
|
||||||
|
userID int64,
|
||||||
|
providerID *string,
|
||||||
|
limit, offset int32,
|
||||||
|
) ([]domain.UnifiedGame, error) {
|
||||||
|
|
||||||
|
// Fetch favorite games directly from repository
|
||||||
|
games, err := s.repo.ListFavoriteGames(ctx, userID, providerID, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
// s.logger.Error("Failed to list favorite games", "userID", userID, "error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no favorites, return empty list
|
||||||
|
if len(games) == 0 {
|
||||||
|
return []domain.UnifiedGame{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
favorites := make([]domain.UnifiedGame, 0, len(games))
|
||||||
|
|
||||||
|
for _, g := range games {
|
||||||
|
var rtpPtr *float64
|
||||||
|
if g.Rtp.Valid {
|
||||||
|
if f, err := g.Rtp.Float64Value(); err == nil {
|
||||||
|
rtpPtr = new(float64)
|
||||||
|
*rtpPtr = f.Float64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bets := make([]float64, len(g.Bets))
|
||||||
|
for i, b := range g.Bets {
|
||||||
|
bets[i] = float64(b.Exp)
|
||||||
|
}
|
||||||
|
|
||||||
|
favorites = append(favorites, domain.UnifiedGame{
|
||||||
|
GameID: g.GameID, // assuming g.GameID is string
|
||||||
|
ProviderID: g.ProviderID, // provider id
|
||||||
|
Provider: g.ProviderID, // you can map a full name if needed
|
||||||
|
Name: g.Name,
|
||||||
|
Category: g.Category.String, // nullable
|
||||||
|
DeviceType: g.DeviceType.String, // nullable
|
||||||
|
Volatility: g.Volatility.String, // nullable
|
||||||
|
RTP: rtpPtr,
|
||||||
|
HasDemo: g.HasDemo.Bool,
|
||||||
|
HasFreeBets: g.HasFreeBets.Bool,
|
||||||
|
Bets: bets,
|
||||||
|
Thumbnail: g.Thumbnail.String,
|
||||||
|
Status: int(g.Status.Int32),
|
||||||
|
// DemoURL: g..String,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return favorites, nil
|
||||||
|
}
|
||||||
1
internal/services/virtualGame/orchestration/report.go
Normal file
1
internal/services/virtualGame/orchestration/report.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package orchestration
|
||||||
|
|
@ -297,7 +297,7 @@ func (s *Service) FetchAndStoreAllVirtualGames(ctx context.Context, req domain.P
|
||||||
unified := domain.UnifiedGame{
|
unified := domain.UnifiedGame{
|
||||||
GameID: fmt.Sprintf("%d", g.ID),
|
GameID: fmt.Sprintf("%d", g.ID),
|
||||||
ProviderID: "popok",
|
ProviderID: "popok",
|
||||||
Provider: "PopOK",
|
Provider: "Popok Gaming",
|
||||||
Name: g.GameName,
|
Name: g.GameName,
|
||||||
Category: "Crash",
|
Category: "Crash",
|
||||||
Bets: g.Bets,
|
Bets: g.Bets,
|
||||||
|
|
@ -416,6 +416,15 @@ func (s *Service) SetProviderEnabled(ctx context.Context, providerID string, ena
|
||||||
return domainProvider, nil
|
return domainProvider, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func (s *Service) CreateVirtualGameProviderReport(ctx context.Context, report domain.CreateVirtualGameProviderReport) (domain.VirtualGameProviderReport, error) {
|
func (s *Service) CreateVirtualGameProviderReport(ctx context.Context, report domain.CreateVirtualGameProviderReport) (domain.VirtualGameProviderReport, error) {
|
||||||
// Example: logger := s.mongoLogger.With(zap.String("service", "CreateVirtualGameProviderReport"), zap.Any("Report", report))
|
// Example: logger := s.mongoLogger.With(zap.String("service", "CreateVirtualGameProviderReport"), zap.Any("Report", report))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ type VirtualGameService interface {
|
||||||
// GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
// GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
||||||
ListGames(ctx context.Context, currency string) ([]domain.PopOKGame, error)
|
ListGames(ctx context.Context, currency string) ([]domain.PopOKGame, error)
|
||||||
RecommendGames(ctx context.Context, userID int64) ([]domain.GameRecommendation, error)
|
RecommendGames(ctx context.Context, userID int64) ([]domain.GameRecommendation, error)
|
||||||
AddFavoriteGame(ctx context.Context, userID, gameID int64) error
|
// AddFavoriteGame(ctx context.Context, userID, gameID int64) error
|
||||||
RemoveFavoriteGame(ctx context.Context, userID, gameID int64) error
|
// RemoveFavoriteGame(ctx context.Context, userID, gameID int64) error
|
||||||
ListFavoriteGames(ctx context.Context, userID int64) ([]domain.GameRecommendation, error)
|
// ListFavoriteGames(ctx context.Context, userID int64) ([]domain.GameRecommendation, error)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -823,47 +823,5 @@ func toInt64Ptr(s string) *int64 {
|
||||||
return &id
|
return &id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) AddFavoriteGame(ctx context.Context, userID, gameID int64) error {
|
|
||||||
return s.repo.AddFavoriteGame(ctx, userID, gameID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) RemoveFavoriteGame(ctx context.Context, userID, gameID int64) error {
|
|
||||||
return s.repo.RemoveFavoriteGame(ctx, userID, gameID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *service) ListFavoriteGames(ctx context.Context, userID int64) ([]domain.GameRecommendation, error) {
|
|
||||||
gameIDs, err := s.repo.ListFavoriteGames(ctx, userID)
|
|
||||||
if err != nil {
|
|
||||||
s.logger.Error("Failed to list favorite games", "userID", userID, "error", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(gameIDs) == 0 {
|
|
||||||
return []domain.GameRecommendation{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
allGames, err := s.ListGames(ctx, "ETB") // You can use dynamic currency if needed
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var favorites []domain.GameRecommendation
|
|
||||||
idMap := make(map[int64]bool)
|
|
||||||
for _, id := range gameIDs {
|
|
||||||
idMap[id] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, g := range allGames {
|
|
||||||
if idMap[int64(g.ID)] {
|
|
||||||
favorites = append(favorites, domain.GameRecommendation{
|
|
||||||
GameID: g.ID,
|
|
||||||
GameName: g.GameName,
|
|
||||||
Thumbnail: g.Thumbnail,
|
|
||||||
Bets: g.Bets,
|
|
||||||
Reason: "Marked as favorite",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return favorites, nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ type loginAdminReq struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// loginAdminRes represents the response body for the LoginAdmin endpoint.
|
// loginAdminRes represents the response body for the LoginAdmin endpoint.
|
||||||
type loginAdminRes struct {
|
type LoginAdminRes struct {
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
RefreshToken string `json:"refresh_token"`
|
RefreshToken string `json:"refresh_token"`
|
||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ func (h *Handler) CreateDirectDeposit(c *fiber.Ctx) error {
|
||||||
// Call service
|
// Call service
|
||||||
deposit, err := h.directDepositSvc.CreateDirectDeposit(c.Context(), req)
|
deposit, err := h.directDepositSvc.CreateDirectDeposit(c.Context(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("CreateDirectDeposit error", err.Error())
|
// h.logger.Error("CreateDirectDeposit error", err.Error())
|
||||||
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to create direct deposit",
|
Message: "Failed to create direct deposit",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
|
@ -73,7 +73,7 @@ func (h *Handler) GetDirectDepositsByStatus(c *fiber.Ctx) error {
|
||||||
|
|
||||||
deposits, total, err := h.directDepositSvc.GetDirectDepositsByStatus(c.Context(), status, page, pageSize)
|
deposits, total, err := h.directDepositSvc.GetDirectDepositsByStatus(c.Context(), status, page, pageSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("GetDirectDepositsByStatus error", err)
|
// h.logger.Error("GetDirectDepositsByStatus error", err)
|
||||||
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to fetch direct deposits",
|
Message: "Failed to fetch direct deposits",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
|
@ -125,7 +125,7 @@ func (h *Handler) ApproveDirectDeposit(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.directDepositSvc.ApproveDirectDeposit(c.Context(), depositID, adminID); err != nil {
|
if err := h.directDepositSvc.ApproveDirectDeposit(c.Context(), depositID, adminID); err != nil {
|
||||||
h.logger.Error("ApproveDirectDeposit error", err)
|
// h.logger.Error("ApproveDirectDeposit error", err)
|
||||||
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to approve direct deposit",
|
Message: "Failed to approve direct deposit",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
|
@ -178,7 +178,7 @@ func (h *Handler) RejectDirectDeposit(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.directDepositSvc.RejectDirectDeposit(c.Context(), depositID, adminID, reason); err != nil {
|
if err := h.directDepositSvc.RejectDirectDeposit(c.Context(), depositID, adminID, reason); err != nil {
|
||||||
h.logger.Error("RejectDirectDeposit error", err)
|
// h.logger.Error("RejectDirectDeposit error", err)
|
||||||
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to reject direct deposit",
|
Message: "Failed to reject direct deposit",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
|
@ -215,7 +215,7 @@ func (h *Handler) GetDirectDepositByID(c *fiber.Ctx) error {
|
||||||
|
|
||||||
deposit, err := h.directDepositSvc.GetDirectDepositByID(c.Context(), depositID)
|
deposit, err := h.directDepositSvc.GetDirectDepositByID(c.Context(), depositID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.logger.Error("GetDirectDepositByID error", err)
|
// h.logger.Error("GetDirectDepositByID error", err)
|
||||||
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to fetch direct deposit",
|
Message: "Failed to fetch direct deposit",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
|
@ -251,7 +251,7 @@ func (h *Handler) DeleteDirectDeposit(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.directDepositSvc.DeleteDirectDeposit(c.Context(), depositID); err != nil {
|
if err := h.directDepositSvc.DeleteDirectDeposit(c.Context(), depositID); err != nil {
|
||||||
h.logger.Error("DeleteDirectDeposit error", err)
|
// h.logger.Error("DeleteDirectDeposit error", err)
|
||||||
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to delete direct deposit",
|
Message: "Failed to delete direct deposit",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ func ParseLeagueIDFromQuery(c *fiber.Ctx) (domain.ValidInt64, error) {
|
||||||
if leagueIDQuery != "" {
|
if leagueIDQuery != "" {
|
||||||
leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64)
|
leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.ValidInt64{}, fmt.Errorf("Failed to parse league_id %v: %w", leagueIDQuery, err)
|
return domain.ValidInt64{}, fmt.Errorf("failed to parse league_id %v: %w", leagueIDQuery, err)
|
||||||
}
|
}
|
||||||
return domain.ValidInt64{
|
return domain.ValidInt64{
|
||||||
Value: leagueIDInt,
|
Value: leagueIDInt,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
@ -346,19 +345,40 @@ func (h *Handler) HandleBet(c *fiber.Ctx) error {
|
||||||
res, err := h.veliVirtualGameSvc.ProcessBet(c.Context(), req)
|
res, err := h.veliVirtualGameSvc.ProcessBet(c.Context(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), veli.ErrDuplicateTransaction.Error()) {
|
if strings.Contains(err.Error(), veli.ErrDuplicateTransaction.Error()) {
|
||||||
return c.Status(fiber.StatusConflict).JSON(domain.CallbackErrorResponse{
|
return c.Status(fiber.StatusConflict).JSON(domain.VeliCallbackErrorResponse{
|
||||||
// Message: "Duplicate transaction",
|
// Message: "Duplicate transaction",
|
||||||
|
ErrorStatus: 409,
|
||||||
|
ErrorData: struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
}{
|
||||||
Error: veli.ErrDuplicateTransaction.Error(),
|
Error: veli.ErrDuplicateTransaction.Error(),
|
||||||
|
Details: nil,
|
||||||
|
},
|
||||||
|
// ErrorData.Er: veli.ErrDuplicateTransaction.Error(),
|
||||||
})
|
})
|
||||||
} else if strings.Contains(err.Error(), veli.ErrInsufficientBalance.Error()) {
|
} else if strings.Contains(err.Error(), veli.ErrInsufficientBalance.Error()) {
|
||||||
return c.Status(fiber.StatusConflict).JSON(domain.CallbackErrorResponse{
|
return c.Status(fiber.StatusConflict).JSON(domain.VeliCallbackErrorResponse{
|
||||||
// Message: "Wallet balance is insufficient",
|
// Message: "Wallet balance is insufficient",
|
||||||
|
ErrorStatus: 409,
|
||||||
|
ErrorData: struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
}{
|
||||||
Error: veli.ErrInsufficientBalance.Error(),
|
Error: veli.ErrInsufficientBalance.Error(),
|
||||||
})
|
Details: nil,
|
||||||
|
}})
|
||||||
} else if strings.Contains(err.Error(), veli.ErrPlayerNotFound.Error()) {
|
} else if strings.Contains(err.Error(), veli.ErrPlayerNotFound.Error()) {
|
||||||
return c.Status(fiber.StatusConflict).JSON(domain.CallbackErrorResponse{
|
return c.Status(fiber.StatusConflict).JSON(domain.VeliCallbackErrorResponse{
|
||||||
// Message: "User not found",
|
// Message: "User not found",
|
||||||
|
ErrorStatus: 409,
|
||||||
|
ErrorData: struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
}{
|
||||||
Error: veli.ErrPlayerNotFound.Error(),
|
Error: veli.ErrPlayerNotFound.Error(),
|
||||||
|
Details: nil,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
|
@ -472,15 +492,29 @@ func (h *Handler) HandleWin(c *fiber.Ctx) error {
|
||||||
|
|
||||||
res, err := h.veliVirtualGameSvc.ProcessWin(c.Context(), req)
|
res, err := h.veliVirtualGameSvc.ProcessWin(c.Context(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, veli.ErrDuplicateTransaction) {
|
if strings.Contains(err.Error(), veli.ErrDuplicateTransaction.Error()) {
|
||||||
return c.Status(fiber.StatusConflict).JSON(domain.CallbackErrorResponse{
|
return c.Status(fiber.StatusConflict).JSON(domain.VeliCallbackErrorResponse{
|
||||||
// Message: "Duplicate transaction",
|
// Message: "Duplicate transaction",
|
||||||
|
ErrorStatus: 409,
|
||||||
|
ErrorData: struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
}{
|
||||||
Error: veli.ErrDuplicateTransaction.Error(),
|
Error: veli.ErrDuplicateTransaction.Error(),
|
||||||
|
Details: nil,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
} else if errors.Is(err, veli.ErrPlayerNotFound) {
|
} else if strings.Contains(err.Error(), veli.ErrPlayerNotFound.Error()) {
|
||||||
return c.Status(fiber.StatusConflict).JSON(domain.CallbackErrorResponse{
|
return c.Status(fiber.StatusConflict).JSON(domain.VeliCallbackErrorResponse{
|
||||||
// Message: "Duplicate transaction",
|
// Message: "Duplicate transaction",
|
||||||
|
ErrorStatus: 409,
|
||||||
|
ErrorData: struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
}{
|
||||||
Error: veli.ErrPlayerNotFound.Error(),
|
Error: veli.ErrPlayerNotFound.Error(),
|
||||||
|
Details: nil,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
|
@ -550,14 +584,28 @@ func (h *Handler) HandleCancel(c *fiber.Ctx) error {
|
||||||
res, err := h.veliVirtualGameSvc.ProcessCancel(c.Context(), req)
|
res, err := h.veliVirtualGameSvc.ProcessCancel(c.Context(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), veli.ErrDuplicateTransaction.Error()) {
|
if strings.Contains(err.Error(), veli.ErrDuplicateTransaction.Error()) {
|
||||||
return c.Status(fiber.StatusConflict).JSON(domain.CallbackErrorResponse{
|
return c.Status(fiber.StatusConflict).JSON(domain.VeliCallbackErrorResponse{
|
||||||
// Message: "Duplicate transaction",
|
// Message: "Duplicate transaction",
|
||||||
|
ErrorStatus: 409,
|
||||||
|
ErrorData: struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
}{
|
||||||
Error: veli.ErrDuplicateTransaction.Error(),
|
Error: veli.ErrDuplicateTransaction.Error(),
|
||||||
|
Details: nil,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
} else if strings.Contains(err.Error(), veli.ErrPlayerNotFound.Error()) {
|
} else if strings.Contains(err.Error(), veli.ErrPlayerNotFound.Error()) {
|
||||||
return c.Status(fiber.StatusConflict).JSON(domain.CallbackErrorResponse{
|
return c.Status(fiber.StatusConflict).JSON(domain.VeliCallbackErrorResponse{
|
||||||
// Message: "User not found",
|
// Message: "User not found",
|
||||||
|
ErrorStatus: 409,
|
||||||
|
ErrorData: struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
Details *string `json:"details"`
|
||||||
|
}{
|
||||||
Error: veli.ErrPlayerNotFound.Error(),
|
Error: veli.ErrPlayerNotFound.Error(),
|
||||||
|
Details: nil,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
|
@ -696,7 +744,7 @@ func (h *Handler) HandlePromoWin(c *fiber.Ctx) error {
|
||||||
// @Tags VirtualGames - Favourites
|
// @Tags VirtualGames - Favourites
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body domain.FavoriteGameRequest true "Game ID to add"
|
// @Param body body domain.FavoriteGameRequest true "Game ID and Provider ID to add"
|
||||||
// @Success 201 {string} domain.Response "created"
|
// @Success 201 {string} domain.Response "created"
|
||||||
// @Failure 400 {object} domain.ErrorResponse
|
// @Failure 400 {object} domain.ErrorResponse
|
||||||
// @Failure 500 {object} domain.ErrorResponse
|
// @Failure 500 {object} domain.ErrorResponse
|
||||||
|
|
@ -706,23 +754,36 @@ func (h *Handler) AddFavorite(c *fiber.Ctx) error {
|
||||||
|
|
||||||
var req domain.FavoriteGameRequest
|
var req domain.FavoriteGameRequest
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Could not add favorite game",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
err := h.virtualGameSvc.AddFavoriteGame(c.Context(), userID, req.GameID)
|
// Validate required fields
|
||||||
|
if req.GameID == 0 || req.ProviderID == "" {
|
||||||
|
// return fiber.NewError(fiber.StatusBadRequest, "game_id and provider_id are required")
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Could not remove favorite",
|
||||||
|
Error: "game_id and provider_id are required",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call service layer with providerID
|
||||||
|
err := h.orchestrationSvc.AddFavoriteGame(c.Context(), userID, req.GameID, req.ProviderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
Message: "Could not add favorite",
|
Message: "Could not add favorite",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
// return fiber.NewError(fiber.StatusInternalServerError, "Could not add favorite")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
||||||
Message: "Game added to favorites",
|
Message: "Game added to favorites",
|
||||||
StatusCode: fiber.StatusCreated,
|
StatusCode: fiber.StatusCreated,
|
||||||
Success: true,
|
Success: true,
|
||||||
})
|
})
|
||||||
// return c.SendStatus(fiber.StatusCreated)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveFavoriteGame godoc
|
// RemoveFavoriteGame godoc
|
||||||
|
|
@ -731,19 +792,46 @@ func (h *Handler) AddFavorite(c *fiber.Ctx) error {
|
||||||
// @Tags VirtualGames - Favourites
|
// @Tags VirtualGames - Favourites
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param gameID path int64 true "Game ID to remove"
|
// @Param gameID path int64 true "Game ID to remove"
|
||||||
// @Success 200 {string} domain.Response "removed"
|
// @Param providerID query string true "Provider ID of the game"
|
||||||
|
// @Success 200 {object} domain.Response "removed"
|
||||||
// @Failure 400 {object} domain.ErrorResponse
|
// @Failure 400 {object} domain.ErrorResponse
|
||||||
// @Failure 500 {object} domain.ErrorResponse
|
// @Failure 500 {object} domain.ErrorResponse
|
||||||
// @Router /api/v1/virtual-game/favorites/{gameID} [delete]
|
// @Router /api/v1/virtual-game/favorites/{gameID} [delete]
|
||||||
func (h *Handler) RemoveFavorite(c *fiber.Ctx) error {
|
func (h *Handler) RemoveFavorite(c *fiber.Ctx) error {
|
||||||
userID := c.Locals("user_id").(int64)
|
userID := c.Locals("user_id").(int64)
|
||||||
gameID, _ := strconv.ParseInt(c.Params("gameID"), 10, 64)
|
|
||||||
|
|
||||||
err := h.virtualGameSvc.RemoveFavoriteGame(c.Context(), userID, gameID)
|
var req domain.FavoriteGameRequest
|
||||||
if err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Could not remove favorite")
|
// return fiber.NewError(fiber.StatusBadRequest, "Invalid request")
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Could not remove favorite",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return c.SendStatus(fiber.StatusOK)
|
|
||||||
|
// Parse gameID from path
|
||||||
|
if req.GameID == 0 || req.ProviderID == "" {
|
||||||
|
// return fiber.NewError(fiber.StatusBadRequest, "game_id and provider_id are required")
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Could not remove favorite",
|
||||||
|
Error: "game_id and provider_id are required",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call service layer
|
||||||
|
err := h.orchestrationSvc.RemoveFavoriteGame(c.Context(), userID, req.GameID, req.ProviderID)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Could not remove favorite",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||||
|
Message: "Game removed from favorites",
|
||||||
|
StatusCode: fiber.StatusOK,
|
||||||
|
Success: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListFavoriteGames godoc
|
// ListFavoriteGames godoc
|
||||||
|
|
@ -751,17 +839,45 @@ func (h *Handler) RemoveFavorite(c *fiber.Ctx) error {
|
||||||
// @Description Lists the games that the user marked as favorite
|
// @Description Lists the games that the user marked as favorite
|
||||||
// @Tags VirtualGames - Favourites
|
// @Tags VirtualGames - Favourites
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {array} domain.GameRecommendation
|
// @Param providerID query string false "Filter by provider ID"
|
||||||
|
// @Param limit query int false "Number of results to return"
|
||||||
|
// @Param offset query int false "Results offset"
|
||||||
|
// @Success 200 {array} domain.UnifiedGame
|
||||||
|
// @Failure 400 {object} domain.ErrorResponse
|
||||||
// @Failure 500 {object} domain.ErrorResponse
|
// @Failure 500 {object} domain.ErrorResponse
|
||||||
// @Router /api/v1/virtual-game/favorites [get]
|
// @Router /api/v1/virtual-game/favorites [get]
|
||||||
func (h *Handler) ListFavorites(c *fiber.Ctx) error {
|
func (h *Handler) ListFavorites(c *fiber.Ctx) error {
|
||||||
userID := c.Locals("user_id").(int64)
|
userID := c.Locals("user_id").(int64)
|
||||||
|
|
||||||
games, err := h.virtualGameSvc.ListFavoriteGames(c.Context(), userID)
|
// Parse optional query params
|
||||||
if err != nil {
|
providerIDQuery := c.Query("providerID")
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Could not fetch favorites")
|
var providerID *string
|
||||||
|
if providerIDQuery != "" {
|
||||||
|
providerID = &providerIDQuery
|
||||||
}
|
}
|
||||||
return c.Status(fiber.StatusOK).JSON(games)
|
|
||||||
|
limitQuery := c.QueryInt("limit", 10) // default limit 20
|
||||||
|
offsetQuery := c.QueryInt("offset", 0) // default offset 0
|
||||||
|
|
||||||
|
// Call service method
|
||||||
|
games, err := h.orchestrationSvc.ListFavoriteGames(c.Context(), userID, providerID, int32(limitQuery), int32(offsetQuery))
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Could not fetch favorites",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||||
|
Message: "Favorite games retrieved successfully",
|
||||||
|
Data: games,
|
||||||
|
StatusCode: fiber.StatusOK,
|
||||||
|
Success: true,
|
||||||
|
MetaData: map[string]interface{}{
|
||||||
|
"offset": offsetQuery,
|
||||||
|
"limit": limitQuery,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func IdentifyBetProvider(body []byte) (string, error) {
|
func IdentifyBetProvider(body []byte) (string, error) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user