From 14de6859b333802d256a885e7e0a0ef86e663930 Mon Sep 17 00:00:00 2001 From: Samuel Tariku Date: Fri, 25 Apr 2025 15:01:30 +0300 Subject: [PATCH] adding result --- cmd/main.go | 5 +- db/migrations/000001_fortune.up.sql | 12 +- db/query/events.sql | 9 +- db/query/result.sql | 8 + docs/docs.go | 398 +++++++++++++++++- docs/swagger.json | 398 +++++++++++++++++- docs/swagger.yaml | 257 ++++++++++- gen/db/events.sql.go | 19 + gen/db/models.go | 10 + gen/db/result.sql.go | 66 +++ go.mod | 2 +- internal/domain/event.go | 25 ++ internal/repository/event.go | 15 + internal/repository/result.go | 61 +++ internal/services/event/port.go | 2 + internal/services/event/service.go | 36 ++ internal/services/result/port.go | 11 + internal/services/result/service.go | 68 +++ internal/web_server/cron.go | 101 +++-- internal/web_server/handlers/auth_handler.go | 20 +- internal/web_server/handlers/prematch.go | 1 + .../handlers/transaction_handler.go | 3 + internal/web_server/handlers/user.go | 36 +- .../handlers/virtual_games_hadlers.go | 9 + .../web_server/handlers/wallet_handler.go | 3 + 25 files changed, 1499 insertions(+), 76 deletions(-) create mode 100644 db/query/result.sql create mode 100644 gen/db/result.sql.go create mode 100644 internal/repository/result.go create mode 100644 internal/services/result/port.go create mode 100644 internal/services/result/service.go diff --git a/cmd/main.go b/cmd/main.go index 943f67c..cad3798 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -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, diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index 111aa73..dcacb70 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -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, @@ -385,4 +386,13 @@ VALUES ( CURRENT_TIMESTAMP, CURRENT_TIMESTAMP ); ---------------------------------------------------Bet365 Data Fetching + Event Managment------------------------------------------------ \ No newline at end of file +--------------------------------------------------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() +); \ No newline at end of file diff --git a/db/query/events.sql b/db/query/events.sql index ab459ae..c9fbd1c 100644 --- a/db/query/events.sql +++ b/db/query/events.sql @@ -204,4 +204,11 @@ FROM events WHERE id = $1 AND is_live = false AND status = 'upcoming' -LIMIT 1; \ No newline at end of file +LIMIT 1; + +-- name: UpdateMatchResult :exec +UPDATE events +SET score = $1, + status = $2, + fetched_at = NOW() +WHERE id = $3; diff --git a/db/query/result.sql b/db/query/result.sql new file mode 100644 index 0000000..34063d4 --- /dev/null +++ b/db/query/result.sql @@ -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; \ No newline at end of file diff --git a/docs/docs.go b/docs/docs.go index cb1802c..6d094d8 100644 --- a/docs/docs.go +++ b/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" } } }, diff --git a/docs/swagger.json b/docs/swagger.json index ad7007a..ad87ae6 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -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" } } }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index cfa3120..0e92823 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -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: type: string + required: + - refresh_token type: object handlers.refreshToken: properties: access_token: + example: type: string refresh_token: + example: 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: diff --git a/gen/db/events.sql.go b/gen/db/events.sql.go index 16fad8f..d556187 100644 --- a/gen/db/events.sql.go +++ b/gen/db/events.sql.go @@ -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 +} diff --git a/gen/db/models.go b/gen/db/models.go index 0d2bea0..bff18a8 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -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"` diff --git a/gen/db/result.sql.go b/gen/db/result.sql.go new file mode 100644 index 0000000..9808e69 --- /dev/null +++ b/gen/db/result.sql.go @@ -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 +} diff --git a/go.mod b/go.mod index 2c2e549..4231585 100644 --- a/go.mod +++ b/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 diff --git a/internal/domain/event.go b/internal/domain/event.go index 0a69607..4deada2 100644 --- a/internal/domain/event.go +++ b/internal/domain/event.go @@ -38,4 +38,29 @@ type UpcomingEvent struct { LeagueName string // League name 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"` } \ No newline at end of file diff --git a/internal/repository/event.go b/internal/repository/event.go index b64973d..9dbc88a 100644 --- a/internal/repository/event.go +++ b/internal/repository/event.go @@ -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 +} \ No newline at end of file diff --git a/internal/repository/result.go b/internal/repository/result.go new file mode 100644 index 0000000..3088e6e --- /dev/null +++ b/internal/repository/result.go @@ -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 +} \ No newline at end of file diff --git a/internal/services/event/port.go b/internal/services/event/port.go index 1404b09..0a60c6a 100644 --- a/internal/services/event/port.go +++ b/internal/services/event/port.go @@ -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 + } diff --git a/internal/services/event/service.go b/internal/services/event/service.go index 4eb5601..13ea1ec 100644 --- a/internal/services/event/service.go +++ b/internal/services/event/service.go @@ -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 +// } + diff --git a/internal/services/result/port.go b/internal/services/result/port.go new file mode 100644 index 0000000..ab0fedc --- /dev/null +++ b/internal/services/result/port.go @@ -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) +} diff --git a/internal/services/result/service.go b/internal/services/result/service.go new file mode 100644 index 0000000..68aa009 --- /dev/null +++ b/internal/services/result/service.go @@ -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) +} \ No newline at end of file diff --git a/internal/web_server/cron.go b/internal/web_server/cron.go index 3106cb8..4455309 100644 --- a/internal/web_server/cron.go +++ b/internal/web_server/cron.go @@ -1,58 +1,75 @@ 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) // } // }, // }, - - // { - // 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: "*/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...") + + 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") +} \ No newline at end of file diff --git a/internal/web_server/handlers/auth_handler.go b/internal/web_server/handlers/auth_handler.go index db9e4e4..d453b80 100644 --- a/internal/web_server/handlers/auth_handler.go +++ b/internal/web_server/handlers/auth_handler.go @@ -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:""` + RefreshToken string `json:"refresh_token" validate:"required" example:""` +} // 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:""` +} // LogOutCustomer godoc // @Summary Logout customer // @Description Logout customer diff --git a/internal/web_server/handlers/prematch.go b/internal/web_server/handlers/prematch.go index 1970aa0..5dc7fc1 100644 --- a/internal/web_server/handlers/prematch.go +++ b/internal/web_server/handlers/prematch.go @@ -190,3 +190,4 @@ func (h *Handler) GetPrematchOddsByUpcomingID(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusOK, "Prematch odds retrieved successfully", odds, nil) } + diff --git a/internal/web_server/handlers/transaction_handler.go b/internal/web_server/handlers/transaction_handler.go index c00fa85..7e17211 100644 --- a/internal/web_server/handlers/transaction_handler.go +++ b/internal/web_server/handlers/transaction_handler.go @@ -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 diff --git a/internal/web_server/handlers/user.go b/internal/web_server/handlers/user.go index 3761518..1a45374 100644 --- a/internal/web_server/handlers/user.go +++ b/internal/web_server/handlers/user.go @@ -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 diff --git a/internal/web_server/handlers/virtual_games_hadlers.go b/internal/web_server/handlers/virtual_games_hadlers.go index ddd6bb5..ed57a1a 100644 --- a/internal/web_server/handlers/virtual_games_hadlers.go +++ b/internal/web_server/handlers/virtual_games_hadlers.go @@ -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 diff --git a/internal/web_server/handlers/wallet_handler.go b/internal/web_server/handlers/wallet_handler.go index c15f5d0..0aaddf5 100644 --- a/internal/web_server/handlers/wallet_handler.go +++ b/internal/web_server/handlers/wallet_handler.go @@ -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"`