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"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
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/transaction"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||
|
|
@ -69,7 +70,7 @@ func main() {
|
|||
|
||||
eventSvc := event.New(cfg.Bet365Token, store)
|
||||
oddsSvc := odds.New(cfg.Bet365Token, store)
|
||||
|
||||
resultSvc := result.NewService(cfg.Bet365Token,store)
|
||||
ticketSvc := ticket.NewService(store)
|
||||
betSvc := bet.NewService(store)
|
||||
walletSvc := wallet.NewService(store, store)
|
||||
|
|
@ -85,7 +86,7 @@ func main() {
|
|||
referalSvc := referralservice.New(referalRepo, *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{
|
||||
JwtAccessKey: cfg.JwtKey,
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@ CREATE TABLE odds (
|
|||
UNIQUE (event_id, market_id, name, handicap),
|
||||
UNIQUE (event_id, market_id)
|
||||
);
|
||||
|
||||
CREATE TABLE companies (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
|
|
@ -386,3 +387,12 @@ VALUES (
|
|||
CURRENT_TIMESTAMP
|
||||
);
|
||||
--------------------------------------------------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()
|
||||
);
|
||||
|
|
@ -205,3 +205,10 @@ WHERE id = $1
|
|||
AND is_live = false
|
||||
AND status = 'upcoming'
|
||||
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": {
|
||||
"get": {
|
||||
"description": "Search branches by name or location",
|
||||
|
|
@ -2184,7 +2325,7 @@ const docTemplate = `{
|
|||
}
|
||||
},
|
||||
"patch": {
|
||||
"description": "Updates the cashed out field",
|
||||
"description": "Updates the verified status of a transaction",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
|
@ -2194,7 +2335,7 @@ const docTemplate = `{
|
|||
"tags": [
|
||||
"transaction"
|
||||
],
|
||||
"summary": "Updates the cashed out field",
|
||||
"summary": "Updates the verified field of a transaction",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
|
|
@ -2205,7 +2346,7 @@ const docTemplate = `{
|
|||
},
|
||||
{
|
||||
"description": "Updates Transaction Verification",
|
||||
"name": "updateCashOut",
|
||||
"name": "updateVerified",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"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": {
|
||||
"get": {
|
||||
"description": "Retrieve all wallets",
|
||||
|
|
@ -3019,6 +3263,34 @@ const docTemplate = `{
|
|||
"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": {
|
||||
"type": "object",
|
||||
"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": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
|
@ -3374,7 +3698,6 @@ const docTemplate = `{
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"event_id": {
|
||||
"description": "BetID int64 ` + "`" + `json:\"bet_id\" example:\"1\"` + "`" + `",
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
|
|
@ -3952,17 +4275,25 @@ const docTemplate = `{
|
|||
},
|
||||
"handlers.UpdateTransactionVerifiedReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"verified"
|
||||
],
|
||||
"properties": {
|
||||
"verified": {
|
||||
"type": "boolean"
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.UpdateWalletActiveReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"is_active"
|
||||
],
|
||||
"properties": {
|
||||
"isActive": {
|
||||
"type": "boolean"
|
||||
"is_active": {
|
||||
"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": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string",
|
||||
|
|
@ -4079,20 +4447,30 @@ const docTemplate = `{
|
|||
},
|
||||
"handlers.logoutReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"refresh_token"
|
||||
],
|
||||
"properties": {
|
||||
"refresh_token": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "\u003crefresh-token\u003e"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.refreshToken": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"access_token",
|
||||
"refresh_token"
|
||||
],
|
||||
"properties": {
|
||||
"access_token": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "\u003cjwt-token\u003e"
|
||||
},
|
||||
"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": {
|
||||
"get": {
|
||||
"description": "Search branches by name or location",
|
||||
|
|
@ -2176,7 +2317,7 @@
|
|||
}
|
||||
},
|
||||
"patch": {
|
||||
"description": "Updates the cashed out field",
|
||||
"description": "Updates the verified status of a transaction",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
|
|
@ -2186,7 +2327,7 @@
|
|||
"tags": [
|
||||
"transaction"
|
||||
],
|
||||
"summary": "Updates the cashed out field",
|
||||
"summary": "Updates the verified field of a transaction",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
|
|
@ -2197,7 +2338,7 @@
|
|||
},
|
||||
{
|
||||
"description": "Updates Transaction Verification",
|
||||
"name": "updateCashOut",
|
||||
"name": "updateVerified",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"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": {
|
||||
"get": {
|
||||
"description": "Retrieve all wallets",
|
||||
|
|
@ -3011,6 +3255,34 @@
|
|||
"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": {
|
||||
"type": "object",
|
||||
"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": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
|
@ -3366,7 +3690,6 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"event_id": {
|
||||
"description": "BetID int64 `json:\"bet_id\" example:\"1\"`",
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
|
|
@ -3944,17 +4267,25 @@
|
|||
},
|
||||
"handlers.UpdateTransactionVerifiedReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"verified"
|
||||
],
|
||||
"properties": {
|
||||
"verified": {
|
||||
"type": "boolean"
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.UpdateWalletActiveReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"is_active"
|
||||
],
|
||||
"properties": {
|
||||
"isActive": {
|
||||
"type": "boolean"
|
||||
"is_active": {
|
||||
"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": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string",
|
||||
|
|
@ -4071,20 +4439,30 @@
|
|||
},
|
||||
"handlers.logoutReq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"refresh_token"
|
||||
],
|
||||
"properties": {
|
||||
"refresh_token": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "\u003crefresh-token\u003e"
|
||||
}
|
||||
}
|
||||
},
|
||||
"handlers.refreshToken": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"access_token",
|
||||
"refresh_token"
|
||||
],
|
||||
"properties": {
|
||||
"access_token": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "\u003cjwt-token\u003e"
|
||||
},
|
||||
"refresh_token": {
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"example": "\u003crefresh-token\u003e"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -103,6 +103,25 @@ definitions:
|
|||
- TELEBIRR_TRANSACTION
|
||||
- ARIFPAY_TRANSACTION
|
||||
- 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:
|
||||
properties:
|
||||
fetched_at:
|
||||
|
|
@ -117,6 +136,40 @@ definitions:
|
|||
items: {}
|
||||
type: array
|
||||
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:
|
||||
enum:
|
||||
- super_admin
|
||||
|
|
@ -357,7 +410,6 @@ definitions:
|
|||
handlers.CreateBetOutcomeReq:
|
||||
properties:
|
||||
event_id:
|
||||
description: BetID int64 `json:"bet_id" example:"1"`
|
||||
example: 1
|
||||
type: integer
|
||||
market_id:
|
||||
|
|
@ -762,12 +814,18 @@ definitions:
|
|||
handlers.UpdateTransactionVerifiedReq:
|
||||
properties:
|
||||
verified:
|
||||
example: true
|
||||
type: boolean
|
||||
required:
|
||||
- verified
|
||||
type: object
|
||||
handlers.UpdateWalletActiveReq:
|
||||
properties:
|
||||
isActive:
|
||||
is_active:
|
||||
example: true
|
||||
type: boolean
|
||||
required:
|
||||
- is_active
|
||||
type: object
|
||||
handlers.UserProfileRes:
|
||||
properties:
|
||||
|
|
@ -824,6 +882,30 @@ definitions:
|
|||
example: 1
|
||||
type: integer
|
||||
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:
|
||||
properties:
|
||||
email:
|
||||
|
|
@ -835,6 +917,8 @@ definitions:
|
|||
phone_number:
|
||||
example: "1234567890"
|
||||
type: string
|
||||
required:
|
||||
- password
|
||||
type: object
|
||||
handlers.loginCustomerRes:
|
||||
properties:
|
||||
|
|
@ -848,14 +932,22 @@ definitions:
|
|||
handlers.logoutReq:
|
||||
properties:
|
||||
refresh_token:
|
||||
example: <refresh-token>
|
||||
type: string
|
||||
required:
|
||||
- refresh_token
|
||||
type: object
|
||||
handlers.refreshToken:
|
||||
properties:
|
||||
access_token:
|
||||
example: <jwt-token>
|
||||
type: string
|
||||
refresh_token:
|
||||
example: <refresh-token>
|
||||
type: string
|
||||
required:
|
||||
- access_token
|
||||
- refresh_token
|
||||
type: object
|
||||
handlers.updateUserReq:
|
||||
properties:
|
||||
|
|
@ -2079,6 +2171,95 @@ paths:
|
|||
summary: Retrieve raw odds by Market ID
|
||||
tags:
|
||||
- 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:
|
||||
get:
|
||||
consumes:
|
||||
|
|
@ -2333,7 +2514,7 @@ paths:
|
|||
patch:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Updates the cashed out field
|
||||
description: Updates the verified status of a transaction
|
||||
parameters:
|
||||
- description: Transaction ID
|
||||
in: path
|
||||
|
|
@ -2342,7 +2523,7 @@ paths:
|
|||
type: integer
|
||||
- description: Updates Transaction Verification
|
||||
in: body
|
||||
name: updateCashOut
|
||||
name: updateVerified
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/handlers.UpdateTransactionVerifiedReq'
|
||||
|
|
@ -2361,7 +2542,7 @@ paths:
|
|||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.APIResponse'
|
||||
summary: Updates the cashed out field
|
||||
summary: Updates the verified field of a transaction
|
||||
tags:
|
||||
- transaction
|
||||
/transfer/refill/:id:
|
||||
|
|
@ -2690,6 +2871,72 @@ paths:
|
|||
summary: Get customer wallet
|
||||
tags:
|
||||
- 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:
|
||||
get:
|
||||
consumes:
|
||||
|
|
|
|||
|
|
@ -514,3 +514,22 @@ func (q *Queries) ListLiveEvents(ctx context.Context) ([]string, error) {
|
|||
}
|
||||
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"`
|
||||
}
|
||||
|
||||
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 {
|
||||
ID int64 `json:"id"`
|
||||
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
|
||||
|
||||
require (
|
||||
github.com/amanuelabay/afrosms-go v1.0.6
|
||||
github.com/bytedance/sonic v1.13.2
|
||||
github.com/go-playground/validator/v10 v10.26.0
|
||||
github.com/gofiber/fiber/v2 v2.52.6
|
||||
|
|
@ -19,7 +20,6 @@ require (
|
|||
|
||||
require (
|
||||
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/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
|
|
|
|||
|
|
@ -39,3 +39,28 @@ type UpcomingEvent struct {
|
|||
LeagueCC string // League country code
|
||||
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 (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
|
|
@ -163,3 +164,17 @@ func (s *Store) GetUpcomingEventByID(ctx context.Context, ID string) (domain.Upc
|
|||
StartTime: event.StartTime.Time.UTC(),
|
||||
}, 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)
|
||||
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)
|
||||
// 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) {
|
||||
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,24 +1,24 @@
|
|||
package httpserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"context"
|
||||
"log"
|
||||
|
||||
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
oddssvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
"github.com/robfig/cron/v3"
|
||||
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
oddssvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
resultsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.Service) {
|
||||
c := cron.New(cron.WithSeconds())
|
||||
func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.Service, resultService resultsvc.Service) {
|
||||
c := cron.New(cron.WithSeconds())
|
||||
|
||||
schedule := []struct {
|
||||
spec string
|
||||
task func()
|
||||
}{
|
||||
|
||||
// {
|
||||
// spec: "0 0 * * * *", // Every hour
|
||||
schedule := []struct {
|
||||
spec string
|
||||
task func()
|
||||
}{
|
||||
// {
|
||||
// spec: "*/5 * * * * *", // Every 5 seconds
|
||||
// task: func() {
|
||||
// if err := eventService.FetchUpcomingEvents(context.Background()); err != nil {
|
||||
// log.Printf("FetchUpcomingEvents error: %v", err)
|
||||
|
|
@ -26,33 +26,50 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
|
|||
// },
|
||||
// },
|
||||
|
||||
// {
|
||||
// spec: "*/5 * * * * *", // Every 5 seconds
|
||||
// task: func() {
|
||||
// if err := eventService.FetchLiveEvents(context.Background()); err != nil {
|
||||
// log.Printf("FetchLiveEvents error: %v", err)
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// spec: "*/5 * * * * *", // Every 5 seconds
|
||||
// task: func() {
|
||||
// if err := eventService.FetchLiveEvents(context.Background()); err != nil {
|
||||
// log.Printf("FetchLiveEvents error: %v", err)
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// spec: "0 */15 * * * *", // Every 15 minutes
|
||||
// task: func() {
|
||||
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||
// log.Printf("FetchNonLiveOdds error: %v", err)
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
{
|
||||
spec: "*/10 * * * * *",
|
||||
task: func() {
|
||||
log.Println("🔄 Fetching results for upcoming events...")
|
||||
|
||||
// {
|
||||
// spec: "0 */15 * * * *", // Every 15 minutes
|
||||
// task: func() {
|
||||
// if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil {
|
||||
// log.Printf("FetchNonLiveOdds error: %v", err)
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
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 {
|
||||
job.task()
|
||||
fmt.Printf("here at")
|
||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||
}
|
||||
}
|
||||
for _, job := range schedule {
|
||||
if _, err := c.AddFunc(job.spec, job.task); err != nil {
|
||||
log.Fatalf("Failed to schedule cron job: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
c.Start()
|
||||
log.Println("Cron jobs started for event and odds services")
|
||||
c.Start()
|
||||
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/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
|
||||
// @Summary 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)
|
||||
}
|
||||
|
||||
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
|
||||
// @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)
|
||||
}
|
||||
|
||||
type logoutReq struct {
|
||||
RefreshToken string `json:"refresh_token" validate:"required" example:"<refresh-token>"`
|
||||
}
|
||||
// LogOutCustomer godoc
|
||||
// @Summary 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)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -232,6 +232,9 @@ func (h *Handler) GetTransactionByID(c *fiber.Ctx) error {
|
|||
return response.WriteJSON(c, fiber.StatusOK, "Transaction retrieved successfully", res, nil)
|
||||
}
|
||||
|
||||
type UpdateTransactionVerifiedReq struct {
|
||||
Verified bool `json:"verified" validate:"required" example:"true"`
|
||||
}
|
||||
// UpdateTransactionVerified godoc
|
||||
// @Summary Updates the verified field of a transaction
|
||||
// @Description Updates the verified status of a transaction
|
||||
|
|
|
|||
|
|
@ -9,7 +9,14 @@ import (
|
|||
|
||||
"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
|
||||
// @Summary 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)
|
||||
}
|
||||
|
||||
type RegisterCodeReq struct {
|
||||
Email string `json:"email" example:"john.doe@example.com"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
}
|
||||
// SendRegisterCode godoc
|
||||
// @Summary 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)
|
||||
}
|
||||
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
|
||||
// @Summary 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)
|
||||
}
|
||||
|
||||
type ResetCodeReq struct {
|
||||
Email string `json:"email" example:"john.doe@example.com"`
|
||||
PhoneNumber string `json:"phone_number" example:"1234567890"`
|
||||
}
|
||||
// SendResetCode godoc
|
||||
// @Summary 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)
|
||||
}
|
||||
|
||||
type ResetPasswordReq struct {
|
||||
Email string
|
||||
PhoneNumber string
|
||||
Password string
|
||||
Otp string
|
||||
}
|
||||
// ResetPassword godoc
|
||||
// @Summary Reset password
|
||||
// @Description Reset password
|
||||
|
|
|
|||
|
|
@ -5,6 +5,15 @@ import (
|
|||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||
"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
|
||||
// @Summary Launch a PopOK virtual game
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ import (
|
|||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type UpdateWalletActiveReq struct {
|
||||
IsActive bool `json:"is_active" validate:"required" example:"true"`
|
||||
}
|
||||
type WalletRes struct {
|
||||
ID int64 `json:"id" example:"1"`
|
||||
Balance float32 `json:"amount" example:"100.0"`
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user