adding result
This commit is contained in:
parent
fcd926223a
commit
14de6859b3
|
|
@ -21,6 +21,7 @@ import (
|
||||||
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notfication"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||||
|
|
@ -69,7 +70,7 @@ func main() {
|
||||||
|
|
||||||
eventSvc := event.New(cfg.Bet365Token, store)
|
eventSvc := event.New(cfg.Bet365Token, store)
|
||||||
oddsSvc := odds.New(cfg.Bet365Token, store)
|
oddsSvc := odds.New(cfg.Bet365Token, store)
|
||||||
|
resultSvc := result.NewService(cfg.Bet365Token,store)
|
||||||
ticketSvc := ticket.NewService(store)
|
ticketSvc := ticket.NewService(store)
|
||||||
betSvc := bet.NewService(store)
|
betSvc := bet.NewService(store)
|
||||||
walletSvc := wallet.NewService(store, store)
|
walletSvc := wallet.NewService(store, store)
|
||||||
|
|
@ -85,7 +86,7 @@ func main() {
|
||||||
referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger)
|
referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger)
|
||||||
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
|
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
|
||||||
|
|
||||||
httpserver.StartDataFetchingCrons(eventSvc, oddsSvc)
|
httpserver.StartDataFetchingCrons(eventSvc, oddsSvc, resultSvc)
|
||||||
|
|
||||||
app := httpserver.NewApp(cfg.Port, v, authSvc, logger, jwtutil.JwtConfig{
|
app := httpserver.NewApp(cfg.Port, v, authSvc, logger, jwtutil.JwtConfig{
|
||||||
JwtAccessKey: cfg.JwtKey,
|
JwtAccessKey: cfg.JwtKey,
|
||||||
|
|
|
||||||
|
|
@ -240,6 +240,7 @@ CREATE TABLE odds (
|
||||||
UNIQUE (event_id, market_id, name, handicap),
|
UNIQUE (event_id, market_id, name, handicap),
|
||||||
UNIQUE (event_id, market_id)
|
UNIQUE (event_id, market_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE companies (
|
CREATE TABLE companies (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
|
|
@ -385,4 +386,13 @@ VALUES (
|
||||||
CURRENT_TIMESTAMP,
|
CURRENT_TIMESTAMP,
|
||||||
CURRENT_TIMESTAMP
|
CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
--------------------------------------------------Bet365 Data Fetching + Event Managment------------------------------------------------
|
--------------------------------------------------Bet365 Data Fetching + Event Managment------------------------------------------------
|
||||||
|
CREATE TABLE results (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
event_id TEXT UNIQUE,
|
||||||
|
full_time_score TEXT,
|
||||||
|
half_time_score TEXT,
|
||||||
|
ss TEXT,
|
||||||
|
scores JSONB,
|
||||||
|
fetched_at TIMESTAMPTZ DEFAULT now()
|
||||||
|
);
|
||||||
|
|
@ -204,4 +204,11 @@ FROM events
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
AND is_live = false
|
AND is_live = false
|
||||||
AND status = 'upcoming'
|
AND status = 'upcoming'
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
|
-- name: UpdateMatchResult :exec
|
||||||
|
UPDATE events
|
||||||
|
SET score = $1,
|
||||||
|
status = $2,
|
||||||
|
fetched_at = NOW()
|
||||||
|
WHERE id = $3;
|
||||||
|
|
|
||||||
8
db/query/result.sql
Normal file
8
db/query/result.sql
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
-- name: InsertResult :one
|
||||||
|
INSERT INTO results (event_id, full_time_score, half_time_score, ss, scores)
|
||||||
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
|
RETURNING id, event_id, full_time_score, half_time_score, ss, scores, fetched_at;
|
||||||
|
|
||||||
|
|
||||||
|
-- name: GetResultByEventID :one
|
||||||
|
SELECT * FROM results WHERE event_id = $1;
|
||||||
398
docs/docs.go
398
docs/docs.go
|
|
@ -1803,6 +1803,147 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/referral/settings": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Retrieves current referral settings (admin only)",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"referral"
|
||||||
|
],
|
||||||
|
"summary": "Get referral settings",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.ReferralSettings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Updates referral settings (admin only)",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"referral"
|
||||||
|
],
|
||||||
|
"summary": "Update referral settings",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Referral settings",
|
||||||
|
"name": "settings",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.ReferralSettings"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/referral/stats": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Retrieves referral statistics for the authenticated user",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"referral"
|
||||||
|
],
|
||||||
|
"summary": "Get referral statistics",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.ReferralStats"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/search/branch": {
|
"/search/branch": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Search branches by name or location",
|
"description": "Search branches by name or location",
|
||||||
|
|
@ -2184,7 +2325,7 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"patch": {
|
"patch": {
|
||||||
"description": "Updates the cashed out field",
|
"description": "Updates the verified status of a transaction",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
|
@ -2194,7 +2335,7 @@ const docTemplate = `{
|
||||||
"tags": [
|
"tags": [
|
||||||
"transaction"
|
"transaction"
|
||||||
],
|
],
|
||||||
"summary": "Updates the cashed out field",
|
"summary": "Updates the verified field of a transaction",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
|
@ -2205,7 +2346,7 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Updates Transaction Verification",
|
"description": "Updates Transaction Verification",
|
||||||
"name": "updateCashOut",
|
"name": "updateVerified",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|
@ -2738,6 +2879,109 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/virtual-game/callback": {
|
||||||
|
"post": {
|
||||||
|
"description": "Processes callbacks from PopOK for game events",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"virtual-game"
|
||||||
|
],
|
||||||
|
"summary": "Handle PopOK game callback",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Callback data",
|
||||||
|
"name": "callback",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.PopOKCallback"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/virtual-game/launch": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Generates a URL to launch a PopOK game",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"virtual-game"
|
||||||
|
],
|
||||||
|
"summary": "Launch a PopOK virtual game",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Game launch details",
|
||||||
|
"name": "launch",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.launchVirtualGameReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.launchVirtualGameRes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/wallet": {
|
"/wallet": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Retrieve all wallets",
|
"description": "Retrieve all wallets",
|
||||||
|
|
@ -3019,6 +3263,34 @@ const docTemplate = `{
|
||||||
"BANK"
|
"BANK"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"domain.PopOKCallback": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"currency": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"session_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"description": "HMAC-SHA256 signature for verification",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"transaction_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"description": "BET, WIN, REFUND, JACKPOT_WIN",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.RawOddsByMarketID": {
|
"domain.RawOddsByMarketID": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -3040,6 +3312,58 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"domain.ReferralSettings": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"betReferralBonusPercentage": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"cashbackPercentage": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"expiresAfterDays": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"maxReferrals": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"referralRewardAmount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updatedBy": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domain.ReferralStats": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"completedReferrals": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"pendingRewards": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"totalReferrals": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"totalRewardEarned": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.Role": {
|
"domain.Role": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
@ -3374,7 +3698,6 @@ const docTemplate = `{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"event_id": {
|
"event_id": {
|
||||||
"description": "BetID int64 ` + "`" + `json:\"bet_id\" example:\"1\"` + "`" + `",
|
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
|
|
@ -3952,17 +4275,25 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"handlers.UpdateTransactionVerifiedReq": {
|
"handlers.UpdateTransactionVerifiedReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"verified"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"verified": {
|
"verified": {
|
||||||
"type": "boolean"
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"handlers.UpdateWalletActiveReq": {
|
"handlers.UpdateWalletActiveReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"is_active"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"isActive": {
|
"is_active": {
|
||||||
"type": "boolean"
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -4046,8 +4377,45 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handlers.launchVirtualGameReq": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"currency",
|
||||||
|
"game_id",
|
||||||
|
"mode"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"currency": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "USD"
|
||||||
|
},
|
||||||
|
"game_id": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "crash_001"
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"REAL",
|
||||||
|
"DEMO"
|
||||||
|
],
|
||||||
|
"example": "REAL"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"handlers.launchVirtualGameRes": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"launch_url": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handlers.loginCustomerReq": {
|
"handlers.loginCustomerReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"password"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
@ -4079,20 +4447,30 @@ const docTemplate = `{
|
||||||
},
|
},
|
||||||
"handlers.logoutReq": {
|
"handlers.logoutReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"refresh_token"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"refresh_token": {
|
"refresh_token": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"example": "\u003crefresh-token\u003e"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"handlers.refreshToken": {
|
"handlers.refreshToken": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"access_token",
|
||||||
|
"refresh_token"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"access_token": {
|
"access_token": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"example": "\u003cjwt-token\u003e"
|
||||||
},
|
},
|
||||||
"refresh_token": {
|
"refresh_token": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"example": "\u003crefresh-token\u003e"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1795,6 +1795,147 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/referral/settings": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Retrieves current referral settings (admin only)",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"referral"
|
||||||
|
],
|
||||||
|
"summary": "Get referral settings",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.ReferralSettings"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"put": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Updates referral settings (admin only)",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"referral"
|
||||||
|
],
|
||||||
|
"summary": "Update referral settings",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Referral settings",
|
||||||
|
"name": "settings",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.ReferralSettings"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/referral/stats": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Retrieves referral statistics for the authenticated user",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"referral"
|
||||||
|
],
|
||||||
|
"summary": "Get referral statistics",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.ReferralStats"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/search/branch": {
|
"/search/branch": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Search branches by name or location",
|
"description": "Search branches by name or location",
|
||||||
|
|
@ -2176,7 +2317,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"patch": {
|
"patch": {
|
||||||
"description": "Updates the cashed out field",
|
"description": "Updates the verified status of a transaction",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
|
|
@ -2186,7 +2327,7 @@
|
||||||
"tags": [
|
"tags": [
|
||||||
"transaction"
|
"transaction"
|
||||||
],
|
],
|
||||||
"summary": "Updates the cashed out field",
|
"summary": "Updates the verified field of a transaction",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
|
|
@ -2197,7 +2338,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Updates Transaction Verification",
|
"description": "Updates Transaction Verification",
|
||||||
"name": "updateCashOut",
|
"name": "updateVerified",
|
||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|
@ -2730,6 +2871,109 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/virtual-game/callback": {
|
||||||
|
"post": {
|
||||||
|
"description": "Processes callbacks from PopOK for game events",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"virtual-game"
|
||||||
|
],
|
||||||
|
"summary": "Handle PopOK game callback",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Callback data",
|
||||||
|
"name": "callback",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/domain.PopOKCallback"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/virtual-game/launch": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Generates a URL to launch a PopOK game",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"virtual-game"
|
||||||
|
],
|
||||||
|
"summary": "Launch a PopOK virtual game",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Game launch details",
|
||||||
|
"name": "launch",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.launchVirtualGameReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/handlers.launchVirtualGameRes"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal Server Error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/response.APIResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/wallet": {
|
"/wallet": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "Retrieve all wallets",
|
"description": "Retrieve all wallets",
|
||||||
|
|
@ -3011,6 +3255,34 @@
|
||||||
"BANK"
|
"BANK"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"domain.PopOKCallback": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"amount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"currency": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"session_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"signature": {
|
||||||
|
"description": "HMAC-SHA256 signature for verification",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"timestamp": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"transaction_id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"description": "BET, WIN, REFUND, JACKPOT_WIN",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.RawOddsByMarketID": {
|
"domain.RawOddsByMarketID": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -3032,6 +3304,58 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"domain.ReferralSettings": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"betReferralBonusPercentage": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"cashbackPercentage": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"expiresAfterDays": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"maxReferrals": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"referralRewardAmount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updatedBy": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"domain.ReferralStats": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"completedReferrals": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"pendingRewards": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"totalReferrals": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"totalRewardEarned": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"domain.Role": {
|
"domain.Role": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
@ -3366,7 +3690,6 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"event_id": {
|
"event_id": {
|
||||||
"description": "BetID int64 `json:\"bet_id\" example:\"1\"`",
|
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"example": 1
|
"example": 1
|
||||||
},
|
},
|
||||||
|
|
@ -3944,17 +4267,25 @@
|
||||||
},
|
},
|
||||||
"handlers.UpdateTransactionVerifiedReq": {
|
"handlers.UpdateTransactionVerifiedReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"verified"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"verified": {
|
"verified": {
|
||||||
"type": "boolean"
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"handlers.UpdateWalletActiveReq": {
|
"handlers.UpdateWalletActiveReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"is_active"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"isActive": {
|
"is_active": {
|
||||||
"type": "boolean"
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -4038,8 +4369,45 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handlers.launchVirtualGameReq": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"currency",
|
||||||
|
"game_id",
|
||||||
|
"mode"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"currency": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "USD"
|
||||||
|
},
|
||||||
|
"game_id": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "crash_001"
|
||||||
|
},
|
||||||
|
"mode": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"REAL",
|
||||||
|
"DEMO"
|
||||||
|
],
|
||||||
|
"example": "REAL"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"handlers.launchVirtualGameRes": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"launch_url": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"handlers.loginCustomerReq": {
|
"handlers.loginCustomerReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"password"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"email": {
|
"email": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
@ -4071,20 +4439,30 @@
|
||||||
},
|
},
|
||||||
"handlers.logoutReq": {
|
"handlers.logoutReq": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"refresh_token"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"refresh_token": {
|
"refresh_token": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"example": "\u003crefresh-token\u003e"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"handlers.refreshToken": {
|
"handlers.refreshToken": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"access_token",
|
||||||
|
"refresh_token"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"access_token": {
|
"access_token": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"example": "\u003cjwt-token\u003e"
|
||||||
},
|
},
|
||||||
"refresh_token": {
|
"refresh_token": {
|
||||||
"type": "string"
|
"type": "string",
|
||||||
|
"example": "\u003crefresh-token\u003e"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,25 @@ definitions:
|
||||||
- TELEBIRR_TRANSACTION
|
- TELEBIRR_TRANSACTION
|
||||||
- ARIFPAY_TRANSACTION
|
- ARIFPAY_TRANSACTION
|
||||||
- BANK
|
- BANK
|
||||||
|
domain.PopOKCallback:
|
||||||
|
properties:
|
||||||
|
amount:
|
||||||
|
type: number
|
||||||
|
currency:
|
||||||
|
type: string
|
||||||
|
session_id:
|
||||||
|
type: string
|
||||||
|
signature:
|
||||||
|
description: HMAC-SHA256 signature for verification
|
||||||
|
type: string
|
||||||
|
timestamp:
|
||||||
|
type: integer
|
||||||
|
transaction_id:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: BET, WIN, REFUND, JACKPOT_WIN
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
domain.RawOddsByMarketID:
|
domain.RawOddsByMarketID:
|
||||||
properties:
|
properties:
|
||||||
fetched_at:
|
fetched_at:
|
||||||
|
|
@ -117,6 +136,40 @@ definitions:
|
||||||
items: {}
|
items: {}
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
|
domain.ReferralSettings:
|
||||||
|
properties:
|
||||||
|
betReferralBonusPercentage:
|
||||||
|
type: number
|
||||||
|
cashbackPercentage:
|
||||||
|
type: number
|
||||||
|
createdAt:
|
||||||
|
type: string
|
||||||
|
expiresAfterDays:
|
||||||
|
type: integer
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
maxReferrals:
|
||||||
|
type: integer
|
||||||
|
referralRewardAmount:
|
||||||
|
type: number
|
||||||
|
updatedAt:
|
||||||
|
type: string
|
||||||
|
updatedBy:
|
||||||
|
type: string
|
||||||
|
version:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
domain.ReferralStats:
|
||||||
|
properties:
|
||||||
|
completedReferrals:
|
||||||
|
type: integer
|
||||||
|
pendingRewards:
|
||||||
|
type: number
|
||||||
|
totalReferrals:
|
||||||
|
type: integer
|
||||||
|
totalRewardEarned:
|
||||||
|
type: number
|
||||||
|
type: object
|
||||||
domain.Role:
|
domain.Role:
|
||||||
enum:
|
enum:
|
||||||
- super_admin
|
- super_admin
|
||||||
|
|
@ -357,7 +410,6 @@ definitions:
|
||||||
handlers.CreateBetOutcomeReq:
|
handlers.CreateBetOutcomeReq:
|
||||||
properties:
|
properties:
|
||||||
event_id:
|
event_id:
|
||||||
description: BetID int64 `json:"bet_id" example:"1"`
|
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
market_id:
|
market_id:
|
||||||
|
|
@ -762,12 +814,18 @@ definitions:
|
||||||
handlers.UpdateTransactionVerifiedReq:
|
handlers.UpdateTransactionVerifiedReq:
|
||||||
properties:
|
properties:
|
||||||
verified:
|
verified:
|
||||||
|
example: true
|
||||||
type: boolean
|
type: boolean
|
||||||
|
required:
|
||||||
|
- verified
|
||||||
type: object
|
type: object
|
||||||
handlers.UpdateWalletActiveReq:
|
handlers.UpdateWalletActiveReq:
|
||||||
properties:
|
properties:
|
||||||
isActive:
|
is_active:
|
||||||
|
example: true
|
||||||
type: boolean
|
type: boolean
|
||||||
|
required:
|
||||||
|
- is_active
|
||||||
type: object
|
type: object
|
||||||
handlers.UserProfileRes:
|
handlers.UserProfileRes:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -824,6 +882,30 @@ definitions:
|
||||||
example: 1
|
example: 1
|
||||||
type: integer
|
type: integer
|
||||||
type: object
|
type: object
|
||||||
|
handlers.launchVirtualGameReq:
|
||||||
|
properties:
|
||||||
|
currency:
|
||||||
|
example: USD
|
||||||
|
type: string
|
||||||
|
game_id:
|
||||||
|
example: crash_001
|
||||||
|
type: string
|
||||||
|
mode:
|
||||||
|
enum:
|
||||||
|
- REAL
|
||||||
|
- DEMO
|
||||||
|
example: REAL
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- currency
|
||||||
|
- game_id
|
||||||
|
- mode
|
||||||
|
type: object
|
||||||
|
handlers.launchVirtualGameRes:
|
||||||
|
properties:
|
||||||
|
launch_url:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
handlers.loginCustomerReq:
|
handlers.loginCustomerReq:
|
||||||
properties:
|
properties:
|
||||||
email:
|
email:
|
||||||
|
|
@ -835,6 +917,8 @@ definitions:
|
||||||
phone_number:
|
phone_number:
|
||||||
example: "1234567890"
|
example: "1234567890"
|
||||||
type: string
|
type: string
|
||||||
|
required:
|
||||||
|
- password
|
||||||
type: object
|
type: object
|
||||||
handlers.loginCustomerRes:
|
handlers.loginCustomerRes:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -848,14 +932,22 @@ definitions:
|
||||||
handlers.logoutReq:
|
handlers.logoutReq:
|
||||||
properties:
|
properties:
|
||||||
refresh_token:
|
refresh_token:
|
||||||
|
example: <refresh-token>
|
||||||
type: string
|
type: string
|
||||||
|
required:
|
||||||
|
- refresh_token
|
||||||
type: object
|
type: object
|
||||||
handlers.refreshToken:
|
handlers.refreshToken:
|
||||||
properties:
|
properties:
|
||||||
access_token:
|
access_token:
|
||||||
|
example: <jwt-token>
|
||||||
type: string
|
type: string
|
||||||
refresh_token:
|
refresh_token:
|
||||||
|
example: <refresh-token>
|
||||||
type: string
|
type: string
|
||||||
|
required:
|
||||||
|
- access_token
|
||||||
|
- refresh_token
|
||||||
type: object
|
type: object
|
||||||
handlers.updateUserReq:
|
handlers.updateUserReq:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -2079,6 +2171,95 @@ paths:
|
||||||
summary: Retrieve raw odds by Market ID
|
summary: Retrieve raw odds by Market ID
|
||||||
tags:
|
tags:
|
||||||
- prematch
|
- prematch
|
||||||
|
/referral/settings:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Retrieves current referral settings (admin only)
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.ReferralSettings'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"403":
|
||||||
|
description: Forbidden
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Get referral settings
|
||||||
|
tags:
|
||||||
|
- referral
|
||||||
|
put:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Updates referral settings (admin only)
|
||||||
|
parameters:
|
||||||
|
- description: Referral settings
|
||||||
|
in: body
|
||||||
|
name: settings
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.ReferralSettings'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"403":
|
||||||
|
description: Forbidden
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Update referral settings
|
||||||
|
tags:
|
||||||
|
- referral
|
||||||
|
/referral/stats:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Retrieves referral statistics for the authenticated user
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.ReferralStats'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Get referral statistics
|
||||||
|
tags:
|
||||||
|
- referral
|
||||||
/search/branch:
|
/search/branch:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -2333,7 +2514,7 @@ paths:
|
||||||
patch:
|
patch:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: Updates the cashed out field
|
description: Updates the verified status of a transaction
|
||||||
parameters:
|
parameters:
|
||||||
- description: Transaction ID
|
- description: Transaction ID
|
||||||
in: path
|
in: path
|
||||||
|
|
@ -2342,7 +2523,7 @@ paths:
|
||||||
type: integer
|
type: integer
|
||||||
- description: Updates Transaction Verification
|
- description: Updates Transaction Verification
|
||||||
in: body
|
in: body
|
||||||
name: updateCashOut
|
name: updateVerified
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/handlers.UpdateTransactionVerifiedReq'
|
$ref: '#/definitions/handlers.UpdateTransactionVerifiedReq'
|
||||||
|
|
@ -2361,7 +2542,7 @@ paths:
|
||||||
description: Internal Server Error
|
description: Internal Server Error
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/response.APIResponse'
|
$ref: '#/definitions/response.APIResponse'
|
||||||
summary: Updates the cashed out field
|
summary: Updates the verified field of a transaction
|
||||||
tags:
|
tags:
|
||||||
- transaction
|
- transaction
|
||||||
/transfer/refill/:id:
|
/transfer/refill/:id:
|
||||||
|
|
@ -2690,6 +2871,72 @@ paths:
|
||||||
summary: Get customer wallet
|
summary: Get customer wallet
|
||||||
tags:
|
tags:
|
||||||
- wallet
|
- wallet
|
||||||
|
/virtual-game/callback:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Processes callbacks from PopOK for game events
|
||||||
|
parameters:
|
||||||
|
- description: Callback data
|
||||||
|
in: body
|
||||||
|
name: callback
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/domain.PopOKCallback'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
summary: Handle PopOK game callback
|
||||||
|
tags:
|
||||||
|
- virtual-game
|
||||||
|
/virtual-game/launch:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Generates a URL to launch a PopOK game
|
||||||
|
parameters:
|
||||||
|
- description: Game launch details
|
||||||
|
in: body
|
||||||
|
name: launch
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handlers.launchVirtualGameReq'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/handlers.launchVirtualGameRes'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal Server Error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/response.APIResponse'
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: Launch a PopOK virtual game
|
||||||
|
tags:
|
||||||
|
- virtual-game
|
||||||
/wallet:
|
/wallet:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
|
||||||
|
|
@ -514,3 +514,22 @@ func (q *Queries) ListLiveEvents(ctx context.Context) ([]string, error) {
|
||||||
}
|
}
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UpdateMatchResult = `-- name: UpdateMatchResult :exec
|
||||||
|
UPDATE events
|
||||||
|
SET score = $1,
|
||||||
|
status = $2,
|
||||||
|
fetched_at = NOW()
|
||||||
|
WHERE id = $3
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateMatchResultParams struct {
|
||||||
|
Score pgtype.Text `json:"score"`
|
||||||
|
Status pgtype.Text `json:"status"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateMatchResult(ctx context.Context, arg UpdateMatchResultParams) error {
|
||||||
|
_, err := q.db.Exec(ctx, UpdateMatchResult, arg.Score, arg.Status, arg.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,16 @@ type RefreshToken struct {
|
||||||
Revoked bool `json:"revoked"`
|
Revoked bool `json:"revoked"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
EventID pgtype.Text `json:"event_id"`
|
||||||
|
FullTimeScore pgtype.Text `json:"full_time_score"`
|
||||||
|
HalfTimeScore pgtype.Text `json:"half_time_score"`
|
||||||
|
Ss pgtype.Text `json:"ss"`
|
||||||
|
Scores []byte `json:"scores"`
|
||||||
|
FetchedAt pgtype.Timestamptz `json:"fetched_at"`
|
||||||
|
}
|
||||||
|
|
||||||
type SupportedOperation struct {
|
type SupportedOperation struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|
|
||||||
66
gen/db/result.sql.go
Normal file
66
gen/db/result.sql.go
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.28.0
|
||||||
|
// source: result.sql
|
||||||
|
|
||||||
|
package dbgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GetResultByEventID = `-- name: GetResultByEventID :one
|
||||||
|
SELECT id, event_id, full_time_score, half_time_score, ss, scores, fetched_at FROM results WHERE event_id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetResultByEventID(ctx context.Context, eventID pgtype.Text) (Result, error) {
|
||||||
|
row := q.db.QueryRow(ctx, GetResultByEventID, eventID)
|
||||||
|
var i Result
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.EventID,
|
||||||
|
&i.FullTimeScore,
|
||||||
|
&i.HalfTimeScore,
|
||||||
|
&i.Ss,
|
||||||
|
&i.Scores,
|
||||||
|
&i.FetchedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const InsertResult = `-- name: InsertResult :one
|
||||||
|
INSERT INTO results (event_id, full_time_score, half_time_score, ss, scores)
|
||||||
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
|
RETURNING id, event_id, full_time_score, half_time_score, ss, scores, fetched_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type InsertResultParams struct {
|
||||||
|
EventID pgtype.Text `json:"event_id"`
|
||||||
|
FullTimeScore pgtype.Text `json:"full_time_score"`
|
||||||
|
HalfTimeScore pgtype.Text `json:"half_time_score"`
|
||||||
|
Ss pgtype.Text `json:"ss"`
|
||||||
|
Scores []byte `json:"scores"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) InsertResult(ctx context.Context, arg InsertResultParams) (Result, error) {
|
||||||
|
row := q.db.QueryRow(ctx, InsertResult,
|
||||||
|
arg.EventID,
|
||||||
|
arg.FullTimeScore,
|
||||||
|
arg.HalfTimeScore,
|
||||||
|
arg.Ss,
|
||||||
|
arg.Scores,
|
||||||
|
)
|
||||||
|
var i Result
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.EventID,
|
||||||
|
&i.FullTimeScore,
|
||||||
|
&i.HalfTimeScore,
|
||||||
|
&i.Ss,
|
||||||
|
&i.Scores,
|
||||||
|
&i.FetchedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
2
go.mod
2
go.mod
|
|
@ -3,6 +3,7 @@ module github.com/SamuelTariku/FortuneBet-Backend
|
||||||
go 1.24.1
|
go 1.24.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/amanuelabay/afrosms-go v1.0.6
|
||||||
github.com/bytedance/sonic v1.13.2
|
github.com/bytedance/sonic v1.13.2
|
||||||
github.com/go-playground/validator/v10 v10.26.0
|
github.com/go-playground/validator/v10 v10.26.0
|
||||||
github.com/gofiber/fiber/v2 v2.52.6
|
github.com/gofiber/fiber/v2 v2.52.6
|
||||||
|
|
@ -19,7 +20,6 @@ require (
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||||
github.com/amanuelabay/afrosms-go v1.0.6 // indirect
|
|
||||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,29 @@ type UpcomingEvent struct {
|
||||||
LeagueName string // League name
|
LeagueName string // League name
|
||||||
LeagueCC string // League country code
|
LeagueCC string // League country code
|
||||||
StartTime time.Time // Converted from "time" field in UNIX format
|
StartTime time.Time // Converted from "time" field in UNIX format
|
||||||
|
}
|
||||||
|
type MatchResult struct {
|
||||||
|
EventID string
|
||||||
|
FullScore string
|
||||||
|
HalfScore string
|
||||||
|
Status string
|
||||||
|
Scores map[string]map[string]string
|
||||||
|
}
|
||||||
|
type Result struct {
|
||||||
|
EventID string
|
||||||
|
FullTimeScore string
|
||||||
|
HalfTimeScore string
|
||||||
|
SS string
|
||||||
|
Scores map[string]Score // "1": {"home": "0", "away": "1"}
|
||||||
|
}
|
||||||
|
type Score struct {
|
||||||
|
Home string `json:"home"`
|
||||||
|
Away string `json:"away"`
|
||||||
|
}
|
||||||
|
type Odds struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
EventID string `json:"event_id"`
|
||||||
|
MarketType string `json:"market_type"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
HitStatus string `json:"hit_status"`
|
||||||
}
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -163,3 +164,17 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Upc
|
||||||
StartTime: event.StartTime.Time.UTC(),
|
StartTime: event.StartTime.Time.UTC(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
func (s *Store) UpdateFinalScore(ctx context.Context, eventID, fullScore, status string) error {
|
||||||
|
params := dbgen.UpdateMatchResultParams{
|
||||||
|
Score: pgtype.Text{String: fullScore, Valid: true},
|
||||||
|
Status: pgtype.Text{String: status, Valid: true},
|
||||||
|
ID: eventID,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := s.queries.UpdateMatchResult(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to update final score for event %s: %w", eventID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
61
internal/repository/result.go
Normal file
61
internal/repository/result.go
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Store) InsertResult(ctx context.Context, result domain.Result) error {
|
||||||
|
scoresJSON, err := json.Marshal(result.Scores)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to marshal Scores: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.queries.InsertResult(ctx, dbgen.InsertResultParams{
|
||||||
|
EventID: pgtype.Text{String: result.EventID, Valid: true},
|
||||||
|
FullTimeScore: pgtype.Text{String: result.FullTimeScore, Valid: true},
|
||||||
|
HalfTimeScore: pgtype.Text{String: result.HalfTimeScore, Valid: true},
|
||||||
|
Ss: pgtype.Text{String: result.SS, Valid: true},
|
||||||
|
Scores: scoresJSON,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to insert result: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) GetResultByEventID(ctx context.Context, eventID string) (domain.Result, error) {
|
||||||
|
eventIDText := pgtype.Text{String: eventID, Valid: true}
|
||||||
|
|
||||||
|
result, err := s.queries.GetResultByEventID(ctx, eventIDText)
|
||||||
|
if err != nil {
|
||||||
|
return domain.Result{}, fmt.Errorf("failed to get result by event ID: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var rawScores map[string]map[string]string
|
||||||
|
if err := json.Unmarshal(result.Scores, &rawScores); err != nil {
|
||||||
|
return domain.Result{}, fmt.Errorf("failed to unmarshal scores: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
scores := make(map[string]domain.Score)
|
||||||
|
for key, value := range rawScores {
|
||||||
|
scores[key] = domain.Score{
|
||||||
|
Home: value["home"],
|
||||||
|
Away: value["away"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.Result{
|
||||||
|
EventID: result.EventID.String,
|
||||||
|
FullTimeScore: result.FullTimeScore.String,
|
||||||
|
HalfTimeScore: result.HalfTimeScore.String,
|
||||||
|
SS: result.Ss.String,
|
||||||
|
Scores: scores,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
@ -12,4 +12,6 @@ type Service interface {
|
||||||
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error)
|
||||||
GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32, leagueID domain.ValidString, sportID domain.ValidString) ([]domain.UpcomingEvent, int64, error)
|
GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32, leagueID domain.ValidString, sportID domain.ValidString) ([]domain.UpcomingEvent, int64, error)
|
||||||
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
|
GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error)
|
||||||
|
// GetAndStoreMatchResult(ctx context.Context, eventID string) error
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,3 +185,39 @@ func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, limit int32, o
|
||||||
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) {
|
||||||
return s.store.GetUpcomingEventByID(ctx, ID)
|
return s.store.GetUpcomingEventByID(ctx, ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (s *service) GetAndStoreMatchResult(ctx context.Context, eventID string) error {
|
||||||
|
// url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%s", s.token, eventID)
|
||||||
|
|
||||||
|
// resp, err := http.Get(url)
|
||||||
|
// if err != nil {
|
||||||
|
// return fmt.Errorf("failed to fetch result: %w", err)
|
||||||
|
// }
|
||||||
|
// defer resp.Body.Close()
|
||||||
|
|
||||||
|
// body, _ := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
// // Parse the API response
|
||||||
|
// var apiResp struct {
|
||||||
|
// Results []struct {
|
||||||
|
// ID string `json:"id"`
|
||||||
|
// Ss string `json:"ss"` // Full-time score
|
||||||
|
// Status string `json:"time_status"`
|
||||||
|
// } `json:"results"`
|
||||||
|
// }
|
||||||
|
|
||||||
|
// err = json.Unmarshal(body, &apiResp)
|
||||||
|
// if err != nil || len(apiResp.Results) == 0 {
|
||||||
|
// return fmt.Errorf("invalid response or no results found")
|
||||||
|
// }
|
||||||
|
|
||||||
|
// result := apiResp.Results[0]
|
||||||
|
|
||||||
|
// err = s.store.UpdateFinalScore(ctx, result.ID, result.Ss, result.Status)
|
||||||
|
// if err != nil {
|
||||||
|
// return fmt.Errorf("failed to update final score in database: %w", err)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
|
||||||
11
internal/services/result/port.go
Normal file
11
internal/services/result/port.go
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
package result
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Store interface {
|
||||||
|
InsertResult(ctx context.Context, result domain.Result) error
|
||||||
|
GetResultByEventID(ctx context.Context, eventID string) (domain.Result, error)
|
||||||
|
}
|
||||||
68
internal/services/result/service.go
Normal file
68
internal/services/result/service.go
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
package result
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
FetchAndStoreResult(ctx context.Context, eventID string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type service struct {
|
||||||
|
token string
|
||||||
|
store *repository.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(token string, store *repository.Store) Service {
|
||||||
|
return &service{
|
||||||
|
token: token,
|
||||||
|
store: store,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *service) FetchAndStoreResult(ctx context.Context, eventID string) error {
|
||||||
|
url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%s", s.token, eventID)
|
||||||
|
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to fetch result: %w", err)
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
var apiResp struct {
|
||||||
|
Results []struct {
|
||||||
|
SS string
|
||||||
|
Scores map[string]domain.Score `json:"scores"`
|
||||||
|
} `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(res.Body).Decode(&apiResp); err != nil {
|
||||||
|
return fmt.Errorf("failed to decode result: %w", err)
|
||||||
|
}
|
||||||
|
if len(apiResp.Results) == 0 {
|
||||||
|
return fmt.Errorf("no result returned from API")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := apiResp.Results[0]
|
||||||
|
|
||||||
|
halfScore := ""
|
||||||
|
if s1, ok := r.Scores["1"]; ok {
|
||||||
|
halfScore = fmt.Sprintf("%s-%s", s1.Home, s1.Away)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := domain.Result{
|
||||||
|
EventID: eventID,
|
||||||
|
FullTimeScore: r.SS,
|
||||||
|
HalfTimeScore: halfScore,
|
||||||
|
SS: r.SS,
|
||||||
|
Scores: r.Scores,
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.store.InsertResult(ctx, result)
|
||||||
|
}
|
||||||
|
|
@ -1,58 +1,75 @@
|
||||||
package httpserver
|
package httpserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
oddssvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
oddssvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||||
"github.com/robfig/cron/v3"
|
resultsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
|
||||||
|
"github.com/robfig/cron/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.Service) {
|
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.Service, resultService resultsvc.Service) {
|
||||||
c := cron.New(cron.WithSeconds())
|
c := cron.New(cron.WithSeconds())
|
||||||
|
|
||||||
schedule := []struct {
|
schedule := []struct {
|
||||||
spec string
|
spec string
|
||||||
task func()
|
task func()
|
||||||
}{
|
}{
|
||||||
|
// {
|
||||||
// {
|
// spec: "*/5 * * * * *", // Every 5 seconds
|
||||||
// spec: "0 0 * * * *", // Every hour
|
|
||||||
// task: func() {
|
// task: func() {
|
||||||
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||||
// log.Printf("FetchUpcomingEvents error: %v", err)
|
// log.Printf("FetchUpcomingEvents error: %v", err)
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// spec: "*/5 * * * * *", // Every 5 seconds
|
// spec: "*/5 * * * * *", // Every 5 seconds
|
||||||
// task: func() {
|
// task: func() {
|
||||||
// if err := eventService.FetchLiveEvents(context.Background()); err != nil {
|
// if err := eventService.FetchLiveEvents(context.Background()); err != nil {
|
||||||
// log.Printf("FetchLiveEvents error: %v", err)
|
// log.Printf("FetchLiveEvents error: %v", err)
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
|
// {
|
||||||
// {
|
// spec: "0 */15 * * * *", // Every 15 minutes
|
||||||
// spec: "0 */15 * * * *", // Every 15 minutes
|
// task: func() {
|
||||||
// task: func() {
|
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||||
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
// log.Printf("FetchNonLiveOdds error: %v", err)
|
||||||
// log.Printf("FetchNonLiveOdds error: %v", err)
|
// }
|
||||||
// }
|
// },
|
||||||
// },
|
// },
|
||||||
// },
|
{
|
||||||
|
spec: "*/10 * * * * *",
|
||||||
|
task: func() {
|
||||||
|
log.Println("🔄 Fetching results for upcoming events...")
|
||||||
|
|
||||||
|
upcomingEvents, err := eventService.GetAllUpcomingEvents(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("❌ Failed to fetch upcoming events: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range upcomingEvents {
|
||||||
|
if err := resultService.FetchAndStoreResult(context.Background(), event.ID); err != nil {
|
||||||
|
log.Printf("❌ Failed to fetch/store result for event %s: %v", event.ID, err)
|
||||||
|
} else {
|
||||||
|
log.Printf("✅ Successfully stored result for event %s", event.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, job := range schedule {
|
for _, job := range schedule {
|
||||||
job.task()
|
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||||
fmt.Printf("here at")
|
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
}
|
||||||
log.Fatalf("Failed to schedule cron job: %v", err)
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Start()
|
c.Start()
|
||||||
log.Println("Cron jobs started for event and odds services")
|
log.Println("Cron jobs started for event and odds services")
|
||||||
}
|
}
|
||||||
|
|
@ -9,8 +9,19 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
// loginCustomerReq represents the request body for the LoginCustomer endpoint.
|
||||||
|
type loginCustomerReq struct {
|
||||||
|
Email string `json:"email" validate:"email" example:"john.doe@example.com"`
|
||||||
|
PhoneNumber string `json:"phone_number" validate:"required_without=Email" example:"1234567890"`
|
||||||
|
Password string `json:"password" validate:"required" example:"password123"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// loginCustomerRes represents the response body for the LoginCustomer endpoint.
|
||||||
|
type loginCustomerRes struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
}
|
||||||
// LoginCustomer godoc
|
// LoginCustomer godoc
|
||||||
// @Summary Login customer
|
// @Summary Login customer
|
||||||
// @Description Login customer
|
// @Description Login customer
|
||||||
|
|
@ -71,6 +82,10 @@ func (h *Handler) LoginCustomer(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Login successful", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Login successful", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type refreshToken struct {
|
||||||
|
AccessToken string `json:"access_token" validate:"required" example:"<jwt-token>"`
|
||||||
|
RefreshToken string `json:"refresh_token" validate:"required" example:"<refresh-token>"`
|
||||||
|
}
|
||||||
|
|
||||||
// RefreshToken godoc
|
// RefreshToken godoc
|
||||||
// @Summary Refresh token
|
// @Summary Refresh token
|
||||||
|
|
@ -135,6 +150,9 @@ func (h *Handler) RefreshToken(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Refresh successful", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Refresh successful", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type logoutReq struct {
|
||||||
|
RefreshToken string `json:"refresh_token" validate:"required" example:"<refresh-token>"`
|
||||||
|
}
|
||||||
// LogOutCustomer godoc
|
// LogOutCustomer godoc
|
||||||
// @Summary Logout customer
|
// @Summary Logout customer
|
||||||
// @Description Logout customer
|
// @Description Logout customer
|
||||||
|
|
|
||||||
|
|
@ -190,3 +190,4 @@ func (h *Handler) GetPrematchOddsByUpcomingID(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,9 @@ func (h *Handler) GetTransactionByID(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Transaction retrieved successfully", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Transaction retrieved successfully", res, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateTransactionVerifiedReq struct {
|
||||||
|
Verified bool `json:"verified" validate:"required" example:"true"`
|
||||||
|
}
|
||||||
// UpdateTransactionVerified godoc
|
// UpdateTransactionVerified godoc
|
||||||
// @Summary Updates the verified field of a transaction
|
// @Summary Updates the verified field of a transaction
|
||||||
// @Description Updates the verified status of a transaction
|
// @Description Updates the verified status of a transaction
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,14 @@ import (
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
type CheckPhoneEmailExistReq struct {
|
||||||
|
Email string `json:"email" example:"john.doe@example.com"`
|
||||||
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
|
}
|
||||||
|
type CheckPhoneEmailExistRes struct {
|
||||||
|
EmailExist bool `json:"email_exist"`
|
||||||
|
PhoneNumberExist bool `json:"phone_number_exist"`
|
||||||
|
}
|
||||||
// CheckPhoneEmailExist godoc
|
// CheckPhoneEmailExist godoc
|
||||||
// @Summary Check if phone number or email exist
|
// @Summary Check if phone number or email exist
|
||||||
// @Description Check if phone number or email exist
|
// @Description Check if phone number or email exist
|
||||||
|
|
@ -53,7 +60,10 @@ func (h *Handler) CheckPhoneEmailExist(c *fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Check successful", res, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Check successful", res, nil)
|
||||||
}
|
}
|
||||||
|
type RegisterCodeReq struct {
|
||||||
|
Email string `json:"email" example:"john.doe@example.com"`
|
||||||
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
|
}
|
||||||
// SendRegisterCode godoc
|
// SendRegisterCode godoc
|
||||||
// @Summary Send register code
|
// @Summary Send register code
|
||||||
// @Description Send register code
|
// @Description Send register code
|
||||||
|
|
@ -100,7 +110,18 @@ func (h *Handler) SendRegisterCode(c *fiber.Ctx) error {
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Code sent successfully", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Code sent successfully", nil, nil)
|
||||||
}
|
}
|
||||||
|
type RegisterUserReq struct {
|
||||||
|
FirstName string `json:"first_name" example:"John"`
|
||||||
|
LastName string `json:"last_name" example:"Doe"`
|
||||||
|
Email string `json:"email" example:"john.doe@example.com"`
|
||||||
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
|
Password string `json:"password" example:"password123"`
|
||||||
|
//Role string
|
||||||
|
Otp string `json:"otp" example:"123456"`
|
||||||
|
ReferalCode string `json:"referal_code" example:"ABC123"`
|
||||||
|
//
|
||||||
|
|
||||||
|
}
|
||||||
// RegisterUser godoc
|
// RegisterUser godoc
|
||||||
// @Summary Register user
|
// @Summary Register user
|
||||||
// @Description Register user
|
// @Description Register user
|
||||||
|
|
@ -192,6 +213,10 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Registration successful", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Registration successful", nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ResetCodeReq struct {
|
||||||
|
Email string `json:"email" example:"john.doe@example.com"`
|
||||||
|
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||||
|
}
|
||||||
// SendResetCode godoc
|
// SendResetCode godoc
|
||||||
// @Summary Send reset code
|
// @Summary Send reset code
|
||||||
// @Description Send reset code
|
// @Description Send reset code
|
||||||
|
|
@ -238,7 +263,12 @@ func (h *Handler) SendResetCode(c *fiber.Ctx) error {
|
||||||
|
|
||||||
return response.WriteJSON(c, fiber.StatusOK, "Code sent successfully", nil, nil)
|
return response.WriteJSON(c, fiber.StatusOK, "Code sent successfully", nil, nil)
|
||||||
}
|
}
|
||||||
|
type ResetPasswordReq struct {
|
||||||
|
Email string
|
||||||
|
PhoneNumber string
|
||||||
|
Password string
|
||||||
|
Otp string
|
||||||
|
}
|
||||||
// ResetPassword godoc
|
// ResetPassword godoc
|
||||||
// @Summary Reset password
|
// @Summary Reset password
|
||||||
// @Description Reset password
|
// @Description Reset password
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,15 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
type launchVirtualGameReq struct {
|
||||||
|
GameID string `json:"game_id" validate:"required" example:"crash_001"`
|
||||||
|
Currency string `json:"currency" validate:"required,len=3" example:"USD"`
|
||||||
|
Mode string `json:"mode" validate:"required,oneof=REAL DEMO" example:"REAL"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type launchVirtualGameRes struct {
|
||||||
|
LaunchURL string `json:"launch_url"`
|
||||||
|
}
|
||||||
|
|
||||||
// LaunchVirtualGame godoc
|
// LaunchVirtualGame godoc
|
||||||
// @Summary Launch a PopOK virtual game
|
// @Summary Launch a PopOK virtual game
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type UpdateWalletActiveReq struct {
|
||||||
|
IsActive bool `json:"is_active" validate:"required" example:"true"`
|
||||||
|
}
|
||||||
type WalletRes struct {
|
type WalletRes struct {
|
||||||
ID int64 `json:"id" example:"1"`
|
ID int64 `json:"id" example:"1"`
|
||||||
Balance float32 `json:"amount" example:"100.0"`
|
Balance float32 `json:"amount" example:"100.0"`
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user