From 9dd566417e7bc700eef1976d2e13ba99d47824b9 Mon Sep 17 00:00:00 2001 From: Yared Yemane Date: Fri, 23 May 2025 20:11:26 +0300 Subject: [PATCH] Alea Play Service --- cmd/main.go | 9 +- docs/docs.go | 779 +++++++++++------- docs/swagger.json | 779 +++++++++++------- docs/swagger.yaml | 517 +++++++----- internal/config/config.go | 13 + internal/domain/chapa.go | 108 ++- internal/domain/virtual_game.go | 63 +- internal/middleware/alea.go | 34 + internal/repository/virtual_game.go | 1 + internal/router/router.chapa.go | 37 - internal/services/virtualGame/Alea/port.go | 12 + internal/services/virtualGame/Alea/service.go | 159 ++++ internal/services/virtualGame/port.go | 1 + internal/services/virtualGame/service.go | 3 +- internal/web_server/app.go | 88 +- internal/web_server/handlers/alea_games.go | 76 ++ internal/web_server/handlers/chapa.go | 22 +- internal/web_server/handlers/handlers.go | 72 +- internal/web_server/routes.go | 10 +- 19 files changed, 1823 insertions(+), 960 deletions(-) create mode 100644 internal/middleware/alea.go delete mode 100644 internal/router/router.chapa.go create mode 100644 internal/services/virtualGame/Alea/port.go create mode 100644 internal/services/virtualGame/Alea/service.go create mode 100644 internal/web_server/handlers/alea_games.go diff --git a/cmd/main.go b/cmd/main.go index 0045fca..c5eebd7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -29,6 +29,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame" + alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" // "github.com/SamuelTariku/FortuneBet-Backend/internal/utils" @@ -91,6 +92,12 @@ func main() { notificationSvc := notificationservice.New(notificationRepo, logger, cfg) referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger) virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger) + aleaService := alea.NewAleaPlayService( + vitualGameRepo, + *walletSvc, + cfg, + logger, + ) httpserver.StartDataFetchingCrons(eventSvc, oddsSvc, resultSvc) @@ -98,7 +105,7 @@ func main() { JwtAccessKey: cfg.JwtKey, JwtAccessExpiry: cfg.AccessExpiry, }, userSvc, - ticketSvc, betSvc, walletSvc, transactionSvc, branchSvc, companySvc, notificationSvc, oddsSvc, eventSvc, referalSvc, virtualGameSvc, resultSvc, cfg) + ticketSvc, betSvc, walletSvc, transactionSvc, branchSvc, companySvc, notificationSvc, oddsSvc, eventSvc, referalSvc, virtualGameSvc, aleaService, resultSvc, cfg) logger.Info("Starting server", "port", cfg.Port) if err := app.Run(); err != nil { diff --git a/docs/docs.go b/docs/docs.go index f9b5d61..235d7ff 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -129,6 +129,108 @@ const docTemplate = `{ } } }, + "/api/v1/alea-games/launch": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Generates an authenticated launch URL for Alea Play virtual games", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Alea Virtual Games" + ], + "summary": "Launch an Alea Play virtual game", + "parameters": [ + { + "type": "string", + "description": "Game identifier (e.g., 'aviator', 'plinko')", + "name": "game_id", + "in": "query", + "required": true + }, + { + "enum": [ + "USD", + "EUR", + "GBP" + ], + "type": "string", + "default": "USD", + "description": "Currency code (ISO 4217)", + "name": "currency", + "in": "query" + }, + { + "enum": [ + "real", + "demo" + ], + "type": "string", + "default": "real", + "description": "Game mode", + "name": "mode", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Returns authenticated game launch URL", + "schema": { + "type": "object", + "additionalProperties": { + "allOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "launch_url": { + "type": "string" + } + } + } + ] + } + } + }, + "400": { + "description": "Invalid request parameters", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, "/api/v1/chapa/banks": { "get": { "description": "Fetch all supported banks from Chapa", @@ -146,7 +248,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.ChapaSupportedBanksResponse" + "$ref": "#/definitions/domain.ChapaSupportedBanksResponse" } } } @@ -206,7 +308,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.InitPaymentRequest" + "$ref": "#/definitions/domain.InitPaymentRequest" } } ], @@ -214,25 +316,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.InitPaymentResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/domain.InitPaymentResponse" } } } @@ -264,25 +348,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.VerifyTransactionResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/domain.VerifyTransactionResponse" } } } @@ -308,7 +374,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.TransferRequest" + "$ref": "#/definitions/domain.TransferRequest" } } ], @@ -316,25 +382,7 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.CreateTransferResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/domain.CreateTransferResponse" } } } @@ -366,11 +414,78 @@ const docTemplate = `{ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.VerifyTransferResponse" + "$ref": "#/definitions/domain.VerifyTransferResponse" + } + } + } + } + }, + "/api/v1/webhooks/alea": { + "post": { + "description": "Handles webhook callbacks from Alea Play virtual games for bet settlement", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Alea Virtual Games" + ], + "summary": "Process Alea Play game callback", + "parameters": [ + { + "description": "Callback payload", + "name": "callback", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.AleaPlayCallback" + } + } + ], + "responses": { + "200": { + "description": "Callback processed successfully", + "schema": { + "type": "object", + "additionalProperties": { + "allOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "status": { + "type": "string" + } + } + } + ] + } } }, "400": { - "description": "Bad Request", + "description": "Invalid callback format", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "401": { + "description": "Invalid signature", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "409": { + "description": "Duplicate transaction", "schema": { "type": "object", "additionalProperties": { @@ -379,7 +494,7 @@ const docTemplate = `{ } }, "500": { - "description": "Internal Server Error", + "description": "Internal processing error", "schema": { "type": "object", "additionalProperties": { @@ -3578,6 +3693,54 @@ const docTemplate = `{ } }, "definitions": { + "domain.AleaPlayCallback": { + "type": "object", + "properties": { + "amount": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "event_id": { + "type": "string" + }, + "game_id": { + "type": "string" + }, + "is_free_round": { + "type": "boolean" + }, + "multiplier": { + "type": "number" + }, + "operator_id": { + "type": "string" + }, + "round_id": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "signature": { + "type": "string" + }, + "timestamp": { + "type": "integer" + }, + "transaction_id": { + "type": "string" + }, + "type": { + "description": "BET, WIN, CASHOUT, etc.", + "type": "string" + }, + "user_id": { + "type": "string" + } + } + }, "domain.BetOutcome": { "type": "object", "properties": { @@ -3647,6 +3810,143 @@ const docTemplate = `{ } } }, + "domain.ChapaSupportedBank": { + "type": "object", + "properties": { + "acct_length": { + "type": "integer" + }, + "acct_number_regex": { + "type": "string" + }, + "active": { + "type": "integer" + }, + "country_id": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "example_value": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "is_24hrs": { + "type": "integer" + }, + "is_active": { + "type": "integer" + }, + "is_mobilemoney": { + "type": "integer" + }, + "is_rtgs": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "swift": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "domain.ChapaSupportedBanksResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ChapaSupportedBank" + } + }, + "message": { + "type": "string" + } + } + }, + "domain.CreateTransferResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.TransferData" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "domain.InitPaymentData": { + "type": "object", + "properties": { + "checkout_url": { + "type": "string" + }, + "tx_ref": { + "type": "string" + } + } + }, + "domain.InitPaymentRequest": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "callback_url": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "email": { + "type": "string" + }, + "first_name": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "return_url": { + "type": "string" + }, + "tx_ref": { + "type": "string" + } + } + }, + "domain.InitPaymentResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.InitPaymentData" + }, + "message": { + "description": "e.g., \"Payment initialized\"", + "type": "string" + }, + "status": { + "description": "\"success\"", + "type": "string" + } + } + }, "domain.Odd": { "type": "object", "properties": { @@ -3917,6 +4217,86 @@ const docTemplate = `{ } } }, + "domain.TransactionData": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "email": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tx_ref": { + "type": "string" + } + } + }, + "domain.TransferData": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "domain.TransferRequest": { + "type": "object", + "properties": { + "account_number": { + "type": "string" + }, + "amount": { + "type": "string" + }, + "bank_code": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "recipient_name": { + "type": "string" + }, + "reference": { + "type": "string" + } + } + }, + "domain.TransferVerificationData": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "bank_code": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, "domain.UpcomingEvent": { "type": "object", "properties": { @@ -3974,6 +4354,34 @@ const docTemplate = `{ } } }, + "domain.VerifyTransactionResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.TransactionData" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "domain.VerifyTransferResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.TransferVerificationData" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, "handlers.AdminRes": { "type": "object", "properties": { @@ -4164,73 +4572,6 @@ const docTemplate = `{ } } }, - "handlers.ChapaSupportedBank": { - "type": "object", - "properties": { - "acct_length": { - "type": "integer" - }, - "acct_number_regex": { - "type": "string" - }, - "active": { - "type": "integer" - }, - "country_id": { - "type": "integer" - }, - "created_at": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "example_value": { - "type": "string" - }, - "id": { - "type": "integer" - }, - "is_24hrs": { - "type": "integer" - }, - "is_active": { - "type": "integer" - }, - "is_mobilemoney": { - "type": "integer" - }, - "is_rtgs": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "slug": { - "type": "string" - }, - "swift": { - "type": "string" - }, - "updated_at": { - "type": "string" - } - } - }, - "handlers.ChapaSupportedBanksResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.ChapaSupportedBank" - } - }, - "message": { - "type": "string" - } - } - }, "handlers.CheckPhoneEmailExistReq": { "type": "object", "properties": { @@ -4614,20 +4955,6 @@ const docTemplate = `{ } } }, - "handlers.CreateTransferResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handlers.TransferData" - }, - "message": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, "handlers.CustomerWalletRes": { "type": "object", "properties": { @@ -4670,62 +4997,6 @@ const docTemplate = `{ } } }, - "handlers.InitPaymentData": { - "type": "object", - "properties": { - "checkout_url": { - "type": "string" - }, - "tx_ref": { - "type": "string" - } - } - }, - "handlers.InitPaymentRequest": { - "type": "object", - "properties": { - "amount": { - "type": "string" - }, - "callback_url": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "email": { - "type": "string" - }, - "first_name": { - "type": "string" - }, - "last_name": { - "type": "string" - }, - "return_url": { - "type": "string" - }, - "tx_ref": { - "type": "string" - } - } - }, - "handlers.InitPaymentResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handlers.InitPaymentData" - }, - "message": { - "description": "e.g., \"Payment initialized\"", - "type": "string" - }, - "status": { - "description": "\"success\"", - "type": "string" - } - } - }, "handlers.ManagersRes": { "type": "object", "properties": { @@ -4903,26 +5174,6 @@ const docTemplate = `{ } } }, - "handlers.TransactionData": { - "type": "object", - "properties": { - "amount": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "email": { - "type": "string" - }, - "status": { - "type": "string" - }, - "tx_ref": { - "type": "string" - } - } - }, "handlers.TransactionRes": { "type": "object", "properties": { @@ -5021,66 +5272,6 @@ const docTemplate = `{ } } }, - "handlers.TransferData": { - "type": "object", - "properties": { - "amount": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "reference": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, - "handlers.TransferRequest": { - "type": "object", - "properties": { - "account_number": { - "type": "string" - }, - "amount": { - "type": "string" - }, - "bank_code": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "reason": { - "type": "string" - }, - "recipient_name": { - "type": "string" - }, - "reference": { - "type": "string" - } - } - }, - "handlers.TransferVerificationData": { - "type": "object", - "properties": { - "account_name": { - "type": "string" - }, - "bank_code": { - "type": "string" - }, - "reference": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, "handlers.TransferWalletRes": { "type": "object", "properties": { @@ -5212,34 +5403,6 @@ const docTemplate = `{ } } }, - "handlers.VerifyTransactionResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handlers.TransactionData" - }, - "message": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, - "handlers.VerifyTransferResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handlers.TransferVerificationData" - }, - "message": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, "handlers.WalletRes": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index b01b99e..1b046b1 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -121,6 +121,108 @@ } } }, + "/api/v1/alea-games/launch": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Generates an authenticated launch URL for Alea Play virtual games", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Alea Virtual Games" + ], + "summary": "Launch an Alea Play virtual game", + "parameters": [ + { + "type": "string", + "description": "Game identifier (e.g., 'aviator', 'plinko')", + "name": "game_id", + "in": "query", + "required": true + }, + { + "enum": [ + "USD", + "EUR", + "GBP" + ], + "type": "string", + "default": "USD", + "description": "Currency code (ISO 4217)", + "name": "currency", + "in": "query" + }, + { + "enum": [ + "real", + "demo" + ], + "type": "string", + "default": "real", + "description": "Game mode", + "name": "mode", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Returns authenticated game launch URL", + "schema": { + "type": "object", + "additionalProperties": { + "allOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "launch_url": { + "type": "string" + } + } + } + ] + } + } + }, + "400": { + "description": "Invalid request parameters", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "500": { + "description": "Internal server error", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, "/api/v1/chapa/banks": { "get": { "description": "Fetch all supported banks from Chapa", @@ -138,7 +240,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.ChapaSupportedBanksResponse" + "$ref": "#/definitions/domain.ChapaSupportedBanksResponse" } } } @@ -198,7 +300,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.InitPaymentRequest" + "$ref": "#/definitions/domain.InitPaymentRequest" } } ], @@ -206,25 +308,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.InitPaymentResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/domain.InitPaymentResponse" } } } @@ -256,25 +340,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.VerifyTransactionResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/domain.VerifyTransactionResponse" } } } @@ -300,7 +366,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handlers.TransferRequest" + "$ref": "#/definitions/domain.TransferRequest" } } ], @@ -308,25 +374,7 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.CreateTransferResponse" - } - }, - "400": { - "description": "Bad Request", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "type": "object", - "additionalProperties": { - "type": "string" - } + "$ref": "#/definitions/domain.CreateTransferResponse" } } } @@ -358,11 +406,78 @@ "200": { "description": "OK", "schema": { - "$ref": "#/definitions/handlers.VerifyTransferResponse" + "$ref": "#/definitions/domain.VerifyTransferResponse" + } + } + } + } + }, + "/api/v1/webhooks/alea": { + "post": { + "description": "Handles webhook callbacks from Alea Play virtual games for bet settlement", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Alea Virtual Games" + ], + "summary": "Process Alea Play game callback", + "parameters": [ + { + "description": "Callback payload", + "name": "callback", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/domain.AleaPlayCallback" + } + } + ], + "responses": { + "200": { + "description": "Callback processed successfully", + "schema": { + "type": "object", + "additionalProperties": { + "allOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "status": { + "type": "string" + } + } + } + ] + } } }, "400": { - "description": "Bad Request", + "description": "Invalid callback format", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "401": { + "description": "Invalid signature", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "409": { + "description": "Duplicate transaction", "schema": { "type": "object", "additionalProperties": { @@ -371,7 +486,7 @@ } }, "500": { - "description": "Internal Server Error", + "description": "Internal processing error", "schema": { "type": "object", "additionalProperties": { @@ -3570,6 +3685,54 @@ } }, "definitions": { + "domain.AleaPlayCallback": { + "type": "object", + "properties": { + "amount": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "event_id": { + "type": "string" + }, + "game_id": { + "type": "string" + }, + "is_free_round": { + "type": "boolean" + }, + "multiplier": { + "type": "number" + }, + "operator_id": { + "type": "string" + }, + "round_id": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "signature": { + "type": "string" + }, + "timestamp": { + "type": "integer" + }, + "transaction_id": { + "type": "string" + }, + "type": { + "description": "BET, WIN, CASHOUT, etc.", + "type": "string" + }, + "user_id": { + "type": "string" + } + } + }, "domain.BetOutcome": { "type": "object", "properties": { @@ -3639,6 +3802,143 @@ } } }, + "domain.ChapaSupportedBank": { + "type": "object", + "properties": { + "acct_length": { + "type": "integer" + }, + "acct_number_regex": { + "type": "string" + }, + "active": { + "type": "integer" + }, + "country_id": { + "type": "integer" + }, + "created_at": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "example_value": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "is_24hrs": { + "type": "integer" + }, + "is_active": { + "type": "integer" + }, + "is_mobilemoney": { + "type": "integer" + }, + "is_rtgs": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "swift": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, + "domain.ChapaSupportedBanksResponse": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/domain.ChapaSupportedBank" + } + }, + "message": { + "type": "string" + } + } + }, + "domain.CreateTransferResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.TransferData" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "domain.InitPaymentData": { + "type": "object", + "properties": { + "checkout_url": { + "type": "string" + }, + "tx_ref": { + "type": "string" + } + } + }, + "domain.InitPaymentRequest": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "callback_url": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "email": { + "type": "string" + }, + "first_name": { + "type": "string" + }, + "last_name": { + "type": "string" + }, + "return_url": { + "type": "string" + }, + "tx_ref": { + "type": "string" + } + } + }, + "domain.InitPaymentResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.InitPaymentData" + }, + "message": { + "description": "e.g., \"Payment initialized\"", + "type": "string" + }, + "status": { + "description": "\"success\"", + "type": "string" + } + } + }, "domain.Odd": { "type": "object", "properties": { @@ -3909,6 +4209,86 @@ } } }, + "domain.TransactionData": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "email": { + "type": "string" + }, + "status": { + "type": "string" + }, + "tx_ref": { + "type": "string" + } + } + }, + "domain.TransferData": { + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "domain.TransferRequest": { + "type": "object", + "properties": { + "account_number": { + "type": "string" + }, + "amount": { + "type": "string" + }, + "bank_code": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "reason": { + "type": "string" + }, + "recipient_name": { + "type": "string" + }, + "reference": { + "type": "string" + } + } + }, + "domain.TransferVerificationData": { + "type": "object", + "properties": { + "account_name": { + "type": "string" + }, + "bank_code": { + "type": "string" + }, + "reference": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, "domain.UpcomingEvent": { "type": "object", "properties": { @@ -3966,6 +4346,34 @@ } } }, + "domain.VerifyTransactionResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.TransactionData" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "domain.VerifyTransferResponse": { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/domain.TransferVerificationData" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, "handlers.AdminRes": { "type": "object", "properties": { @@ -4156,73 +4564,6 @@ } } }, - "handlers.ChapaSupportedBank": { - "type": "object", - "properties": { - "acct_length": { - "type": "integer" - }, - "acct_number_regex": { - "type": "string" - }, - "active": { - "type": "integer" - }, - "country_id": { - "type": "integer" - }, - "created_at": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "example_value": { - "type": "string" - }, - "id": { - "type": "integer" - }, - "is_24hrs": { - "type": "integer" - }, - "is_active": { - "type": "integer" - }, - "is_mobilemoney": { - "type": "integer" - }, - "is_rtgs": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "slug": { - "type": "string" - }, - "swift": { - "type": "string" - }, - "updated_at": { - "type": "string" - } - } - }, - "handlers.ChapaSupportedBanksResponse": { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/definitions/handlers.ChapaSupportedBank" - } - }, - "message": { - "type": "string" - } - } - }, "handlers.CheckPhoneEmailExistReq": { "type": "object", "properties": { @@ -4606,20 +4947,6 @@ } } }, - "handlers.CreateTransferResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handlers.TransferData" - }, - "message": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, "handlers.CustomerWalletRes": { "type": "object", "properties": { @@ -4662,62 +4989,6 @@ } } }, - "handlers.InitPaymentData": { - "type": "object", - "properties": { - "checkout_url": { - "type": "string" - }, - "tx_ref": { - "type": "string" - } - } - }, - "handlers.InitPaymentRequest": { - "type": "object", - "properties": { - "amount": { - "type": "string" - }, - "callback_url": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "email": { - "type": "string" - }, - "first_name": { - "type": "string" - }, - "last_name": { - "type": "string" - }, - "return_url": { - "type": "string" - }, - "tx_ref": { - "type": "string" - } - } - }, - "handlers.InitPaymentResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handlers.InitPaymentData" - }, - "message": { - "description": "e.g., \"Payment initialized\"", - "type": "string" - }, - "status": { - "description": "\"success\"", - "type": "string" - } - } - }, "handlers.ManagersRes": { "type": "object", "properties": { @@ -4895,26 +5166,6 @@ } } }, - "handlers.TransactionData": { - "type": "object", - "properties": { - "amount": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "email": { - "type": "string" - }, - "status": { - "type": "string" - }, - "tx_ref": { - "type": "string" - } - } - }, "handlers.TransactionRes": { "type": "object", "properties": { @@ -5013,66 +5264,6 @@ } } }, - "handlers.TransferData": { - "type": "object", - "properties": { - "amount": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "reference": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, - "handlers.TransferRequest": { - "type": "object", - "properties": { - "account_number": { - "type": "string" - }, - "amount": { - "type": "string" - }, - "bank_code": { - "type": "string" - }, - "currency": { - "type": "string" - }, - "reason": { - "type": "string" - }, - "recipient_name": { - "type": "string" - }, - "reference": { - "type": "string" - } - } - }, - "handlers.TransferVerificationData": { - "type": "object", - "properties": { - "account_name": { - "type": "string" - }, - "bank_code": { - "type": "string" - }, - "reference": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, "handlers.TransferWalletRes": { "type": "object", "properties": { @@ -5204,34 +5395,6 @@ } } }, - "handlers.VerifyTransactionResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handlers.TransactionData" - }, - "message": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, - "handlers.VerifyTransferResponse": { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handlers.TransferVerificationData" - }, - "message": { - "type": "string" - }, - "status": { - "type": "string" - } - } - }, "handlers.WalletRes": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 4219293..cc038bf 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,4 +1,36 @@ definitions: + domain.AleaPlayCallback: + properties: + amount: + type: number + currency: + type: string + event_id: + type: string + game_id: + type: string + is_free_round: + type: boolean + multiplier: + type: number + operator_id: + type: string + round_id: + type: string + session_id: + type: string + signature: + type: string + timestamp: + type: integer + transaction_id: + type: string + type: + description: BET, WIN, CASHOUT, etc. + type: string + user_id: + type: string + type: object domain.BetOutcome: properties: away_team_name: @@ -48,6 +80,96 @@ definitions: - $ref: '#/definitions/domain.OutcomeStatus' example: 1 type: object + domain.ChapaSupportedBank: + properties: + acct_length: + type: integer + acct_number_regex: + type: string + active: + type: integer + country_id: + type: integer + created_at: + type: string + currency: + type: string + example_value: + type: string + id: + type: integer + is_24hrs: + type: integer + is_active: + type: integer + is_mobilemoney: + type: integer + is_rtgs: + type: integer + name: + type: string + slug: + type: string + swift: + type: string + updated_at: + type: string + type: object + domain.ChapaSupportedBanksResponse: + properties: + data: + items: + $ref: '#/definitions/domain.ChapaSupportedBank' + type: array + message: + type: string + type: object + domain.CreateTransferResponse: + properties: + data: + $ref: '#/definitions/domain.TransferData' + message: + type: string + status: + type: string + type: object + domain.InitPaymentData: + properties: + checkout_url: + type: string + tx_ref: + type: string + type: object + domain.InitPaymentRequest: + properties: + amount: + type: string + callback_url: + type: string + currency: + type: string + email: + type: string + first_name: + type: string + last_name: + type: string + return_url: + type: string + tx_ref: + type: string + type: object + domain.InitPaymentResponse: + properties: + data: + $ref: '#/definitions/domain.InitPaymentData' + message: + description: e.g., "Payment initialized" + type: string + status: + description: '"success"' + type: string + type: object domain.Odd: properties: category: @@ -238,6 +360,58 @@ definitions: example: 1 type: integer type: object + domain.TransactionData: + properties: + amount: + type: string + currency: + type: string + email: + type: string + status: + type: string + tx_ref: + type: string + type: object + domain.TransferData: + properties: + amount: + type: string + currency: + type: string + reference: + type: string + status: + type: string + type: object + domain.TransferRequest: + properties: + account_number: + type: string + amount: + type: string + bank_code: + type: string + currency: + type: string + reason: + type: string + recipient_name: + type: string + reference: + type: string + type: object + domain.TransferVerificationData: + properties: + account_name: + type: string + bank_code: + type: string + reference: + type: string + status: + type: string + type: object domain.UpcomingEvent: properties: awayKitImage: @@ -280,6 +454,24 @@ definitions: description: Converted from "time" field in UNIX format type: string type: object + domain.VerifyTransactionResponse: + properties: + data: + $ref: '#/definitions/domain.TransactionData' + message: + type: string + status: + type: string + type: object + domain.VerifyTransferResponse: + properties: + data: + $ref: '#/definitions/domain.TransferVerificationData' + message: + type: string + status: + type: string + type: object handlers.AdminRes: properties: created_at: @@ -413,50 +605,6 @@ definitions: example: 1 type: integer type: object - handlers.ChapaSupportedBank: - properties: - acct_length: - type: integer - acct_number_regex: - type: string - active: - type: integer - country_id: - type: integer - created_at: - type: string - currency: - type: string - example_value: - type: string - id: - type: integer - is_24hrs: - type: integer - is_active: - type: integer - is_mobilemoney: - type: integer - is_rtgs: - type: integer - name: - type: string - slug: - type: string - swift: - type: string - updated_at: - type: string - type: object - handlers.ChapaSupportedBanksResponse: - properties: - data: - items: - $ref: '#/definitions/handlers.ChapaSupportedBank' - type: array - message: - type: string - type: object handlers.CheckPhoneEmailExistReq: properties: email: @@ -726,15 +874,6 @@ definitions: example: cash type: string type: object - handlers.CreateTransferResponse: - properties: - data: - $ref: '#/definitions/handlers.TransferData' - message: - type: string - status: - type: string - type: object handlers.CustomerWalletRes: properties: company_id: @@ -765,43 +904,6 @@ definitions: static_updated_at: type: string type: object - handlers.InitPaymentData: - properties: - checkout_url: - type: string - tx_ref: - type: string - type: object - handlers.InitPaymentRequest: - properties: - amount: - type: string - callback_url: - type: string - currency: - type: string - email: - type: string - first_name: - type: string - last_name: - type: string - return_url: - type: string - tx_ref: - type: string - type: object - handlers.InitPaymentResponse: - properties: - data: - $ref: '#/definitions/handlers.InitPaymentData' - message: - description: e.g., "Payment initialized" - type: string - status: - description: '"success"' - type: string - type: object handlers.ManagersRes: properties: created_at: @@ -925,19 +1027,6 @@ definitions: example: 4.22 type: number type: object - handlers.TransactionData: - properties: - amount: - type: string - currency: - type: string - email: - type: string - status: - type: string - tx_ref: - type: string - type: object handlers.TransactionRes: properties: account_name: @@ -1007,45 +1096,6 @@ definitions: example: true type: boolean type: object - handlers.TransferData: - properties: - amount: - type: string - currency: - type: string - reference: - type: string - status: - type: string - type: object - handlers.TransferRequest: - properties: - account_number: - type: string - amount: - type: string - bank_code: - type: string - currency: - type: string - reason: - type: string - recipient_name: - type: string - reference: - type: string - type: object - handlers.TransferVerificationData: - properties: - account_name: - type: string - bank_code: - type: string - reference: - type: string - status: - type: string - type: object handlers.TransferWalletRes: properties: amount: @@ -1136,24 +1186,6 @@ definitions: updated_at: type: string type: object - handlers.VerifyTransactionResponse: - properties: - data: - $ref: '#/definitions/handlers.TransactionData' - message: - type: string - status: - type: string - type: object - handlers.VerifyTransferResponse: - properties: - data: - $ref: '#/definitions/handlers.TransferVerificationData' - message: - type: string - status: - type: string - type: object handlers.WalletRes: properties: amount: @@ -1366,6 +1398,71 @@ paths: summary: Create Admin tags: - admin + /api/v1/alea-games/launch: + get: + consumes: + - application/json + description: Generates an authenticated launch URL for Alea Play virtual games + parameters: + - description: Game identifier (e.g., 'aviator', 'plinko') + in: query + name: game_id + required: true + type: string + - default: USD + description: Currency code (ISO 4217) + enum: + - USD + - EUR + - GBP + in: query + name: currency + type: string + - default: real + description: Game mode + enum: + - real + - demo + in: query + name: mode + type: string + produces: + - application/json + responses: + "200": + description: Returns authenticated game launch URL + schema: + additionalProperties: + allOf: + - type: string + - properties: + launch_url: + type: string + type: object + type: object + "400": + description: Invalid request parameters + schema: + additionalProperties: + type: string + type: object + "401": + description: Unauthorized + schema: + additionalProperties: + type: string + type: object + "500": + description: Internal server error + schema: + additionalProperties: + type: string + type: object + security: + - BearerAuth: [] + summary: Launch an Alea Play virtual game + tags: + - Alea Virtual Games /api/v1/chapa/banks: get: consumes: @@ -1377,7 +1474,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/handlers.ChapaSupportedBanksResponse' + $ref: '#/definitions/domain.ChapaSupportedBanksResponse' summary: Get list of banks tags: - Chapa @@ -1414,26 +1511,14 @@ paths: name: payload required: true schema: - $ref: '#/definitions/handlers.InitPaymentRequest' + $ref: '#/definitions/domain.InitPaymentRequest' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/handlers.InitPaymentResponse' - "400": - description: Bad Request - schema: - additionalProperties: - type: string - type: object - "500": - description: Internal Server Error - schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/domain.InitPaymentResponse' summary: Initialize a payment transaction tags: - Chapa @@ -1454,19 +1539,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/handlers.VerifyTransactionResponse' - "400": - description: Bad Request - schema: - additionalProperties: - type: string - type: object - "500": - description: Internal Server Error - schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/domain.VerifyTransactionResponse' summary: Verify a payment transaction tags: - Chapa @@ -1481,26 +1554,14 @@ paths: name: payload required: true schema: - $ref: '#/definitions/handlers.TransferRequest' + $ref: '#/definitions/domain.TransferRequest' produces: - application/json responses: "200": description: OK schema: - $ref: '#/definitions/handlers.CreateTransferResponse' - "400": - description: Bad Request - schema: - additionalProperties: - type: string - type: object - "500": - description: Internal Server Error - schema: - additionalProperties: - type: string - type: object + $ref: '#/definitions/domain.CreateTransferResponse' summary: Create a money transfer tags: - Chapa @@ -1521,22 +1582,64 @@ paths: "200": description: OK schema: - $ref: '#/definitions/handlers.VerifyTransferResponse' + $ref: '#/definitions/domain.VerifyTransferResponse' + summary: Verify a transfer + tags: + - Chapa + /api/v1/webhooks/alea: + post: + consumes: + - application/json + description: Handles webhook callbacks from Alea Play virtual games for bet + settlement + parameters: + - description: Callback payload + in: body + name: callback + required: true + schema: + $ref: '#/definitions/domain.AleaPlayCallback' + produces: + - application/json + responses: + "200": + description: Callback processed successfully + schema: + additionalProperties: + allOf: + - type: string + - properties: + status: + type: string + type: object + type: object "400": - description: Bad Request + description: Invalid callback format + schema: + additionalProperties: + type: string + type: object + "401": + description: Invalid signature + schema: + additionalProperties: + type: string + type: object + "409": + description: Duplicate transaction schema: additionalProperties: type: string type: object "500": - description: Internal Server Error + description: Internal processing error schema: additionalProperties: type: string type: object - summary: Verify a transfer + summary: Process Alea Play game callback tags: - - Chapa + - Alea Virtual Games /auth/login: post: consumes: diff --git a/internal/config/config.go b/internal/config/config.go index 9418707..5187325 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -28,6 +28,18 @@ var ( ErrInvalidPopOKCallbackURL = errors.New("PopOK callback URL is invalid") ) +type AleaPlayConfig struct { + Enabled bool `mapstructure:"enabled"` + BaseURL string `mapstructure:"base_url"` // "https://api.aleaplay.com" + OperatorID string `mapstructure:"operator_id"` // Your operator ID with Alea + SecretKey string `mapstructure:"secret_key"` // API secret for signatures + GameListURL string `mapstructure:"game_list_url"` // Endpoint to fetch available games + + // Optional settings + DefaultCurrency string `mapstructure:"default_currency"` // "USD", "EUR", etc. + SessionTimeout int `mapstructure:"session_timeout"` // In hours +} + type Config struct { Port int DbUrl string @@ -48,6 +60,7 @@ type Config struct { CHAPA_RETURN_URL string Bet365Token string PopOK domain.PopOKConfig + AleaPlay AleaPlayConfig `mapstructure:"alea_play"` } func NewConfig() (*Config, error) { diff --git a/internal/domain/chapa.go b/internal/domain/chapa.go index 7d0427a..f630a6d 100644 --- a/internal/domain/chapa.go +++ b/internal/domain/chapa.go @@ -1 +1,107 @@ -package domain \ No newline at end of file +package domain + +import "time" + +var ( + ChapaSecret string + ChapaBaseURL string +) + +type InitPaymentRequest struct { + Amount string `json:"amount"` + Currency string `json:"currency"` + Email string `json:"email"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` + TxRef string `json:"tx_ref"` + CallbackURL string `json:"callback_url"` + ReturnURL string `json:"return_url"` +} + +type TransferRequest struct { + AccountNumber string `json:"account_number"` + BankCode string `json:"bank_code"` + Amount string `json:"amount"` + Currency string `json:"currency"` + Reference string `json:"reference"` + Reason string `json:"reason"` + RecipientName string `json:"recipient_name"` +} + +type ChapaSupportedBank struct { + Id int64 `json:"id"` + Slug string `json:"slug"` + Swift string `json:"swift"` + Name string `json:"name"` + AcctLength int `json:"acct_length"` + AcctNumberRegex string `json:"acct_number_regex"` + ExampleValue string `json:"example_value"` + CountryId int `json:"country_id"` + IsMobilemoney *int `json:"is_mobilemoney"` + + IsActive int `json:"is_active"` + IsRtgs *int `json:"is_rtgs"` + Active int `json:"active"` + Is24Hrs *int `json:"is_24hrs"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Currency string `json:"currency"` +} + +type ChapaSupportedBanksResponse struct { + Message string `json:"message"` + Data []ChapaSupportedBank `json:"data"` +} + +type InitPaymentData struct { + TxRef string `json:"tx_ref"` + CheckoutURL string `json:"checkout_url"` +} + +type InitPaymentResponse struct { + Status string `json:"status"` // "success" + Message string `json:"message"` // e.g., "Payment initialized" + Data InitPaymentData `json:"data"` +} + +type WebhookPayload map[string]interface{} + +type TransactionData struct { + TxRef string `json:"tx_ref"` + Status string `json:"status"` + Amount string `json:"amount"` + Currency string `json:"currency"` + CustomerEmail string `json:"email"` +} + +type VerifyTransactionResponse struct { + Status string `json:"status"` + Message string `json:"message"` + Data TransactionData `json:"data"` +} + +type TransferData struct { + Reference string `json:"reference"` + Status string `json:"status"` + Amount string `json:"amount"` + Currency string `json:"currency"` +} + +type CreateTransferResponse struct { + Status string `json:"status"` + Message string `json:"message"` + Data TransferData `json:"data"` +} + +type TransferVerificationData struct { + Reference string `json:"reference"` + Status string `json:"status"` + BankCode string `json:"bank_code"` + AccountName string `json:"account_name"` +} + +type VerifyTransferResponse struct { + Status string `json:"status"` + Message string `json:"message"` + Data TransferVerificationData `json:"data"` +} diff --git a/internal/domain/virtual_game.go b/internal/domain/virtual_game.go index 8b981af..1866519 100644 --- a/internal/domain/virtual_game.go +++ b/internal/domain/virtual_game.go @@ -14,6 +14,11 @@ type VirtualGameSession struct { CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` ExpiresAt time.Time `json:"expires_at"` + + // Alea Play specific fields + ExternalSessionID string `json:"external_session_id"` // Alea's session reference + OperatorID string `json:"operator_id"` // Your operator ID with Alea + GameMode string `json:"game_mode"` // real, demo, tournament } type VirtualGameTransaction struct { @@ -21,15 +26,35 @@ type VirtualGameTransaction struct { SessionID int64 `json:"session_id"` UserID int64 `json:"user_id"` WalletID int64 `json:"wallet_id"` - TransactionType string `json:"transaction_type"` // BET, WIN, REFUND, JACKPOT_WIN - Amount int64 `json:"amount"` + TransactionType string `json:"transaction_type"` // BET, WIN, REFUND, CASHOUT, etc. + Amount int64 `json:"amount"` // Always in cents Currency string `json:"currency"` ExternalTransactionID string `json:"external_transaction_id"` Status string `json:"status"` // PENDING, COMPLETED, FAILED CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` + + // Alea Play specific fields + GameRoundID string `json:"game_round_id"` // Round identifier + Multiplier float64 `json:"multiplier"` // For games like Aviator + IsFreeRound bool `json:"is_free_round"` // For bonus play + OperatorID string `json:"operator_id"` // Your operator ID } +// type VirtualGameTransaction struct { +// ID int64 `json:"id"` +// SessionID int64 `json:"session_id"` +// UserID int64 `json:"user_id"` +// WalletID int64 `json:"wallet_id"` +// TransactionType string `json:"transaction_type"` // BET, WIN, REFUND, JACKPOT_WIN +// Amount int64 `json:"amount"` +// Currency string `json:"currency"` +// ExternalTransactionID string `json:"external_transaction_id"` +// Status string `json:"status"` // PENDING, COMPLETED, FAILED +// CreatedAt time.Time `json:"created_at"` +// UpdatedAt time.Time `json:"updated_at"` +// } + type CreateVirtualGameSession struct { UserID int64 GameID string @@ -53,3 +78,37 @@ type PopOKCallback struct { Timestamp int64 `json:"timestamp"` Signature string `json:"signature"` // HMAC-SHA256 signature for verification } + +type AleaPlayCallback struct { + EventID string `json:"event_id"` + TransactionID string `json:"transaction_id"` + SessionID string `json:"session_id"` + UserID string `json:"user_id"` + GameID string `json:"game_id"` + Type string `json:"type"` // BET, WIN, CASHOUT, etc. + Amount float64 `json:"amount"` + Currency string `json:"currency"` + RoundID string `json:"round_id"` + Multiplier float64 `json:"multiplier"` + IsFreeRound bool `json:"is_free_round"` + OperatorID string `json:"operator_id"` + Timestamp int64 `json:"timestamp"` + Signature string `json:"signature"` +} + +// // Extend VirtualGameTransaction for Alea compatibility +// type VirtualGameTransaction struct { +// ID string `json:"id"` +// SessionID string `json:"session_id"` +// UserID int64 `json:"user_id"` +// WalletID int64 `json:"wallet_id"` +// TransactionType string `json:"transaction_type"` // Matches Alea's types +// Amount int64 `json:"amount"` // In cents +// Currency string `json:"currency"` +// ExternalTransactionID string `json:"external_transaction_id"` +// Status string `json:"status"` +// GameID string `json:"game_id"` // Track which game this was for +// RoundID string `json:"round_id,omitempty"` +// CreatedAt time.Time `json:"created_at"` +// UpdatedAt time.Time `json:"updated_at"` +// } diff --git a/internal/middleware/alea.go b/internal/middleware/alea.go new file mode 100644 index 0000000..36e3f1b --- /dev/null +++ b/internal/middleware/alea.go @@ -0,0 +1,34 @@ +package middleware + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + + "github.com/gofiber/fiber/v2" +) + +func AleaWebhookMiddleware(secretKey string) fiber.Handler { + return func(c *fiber.Ctx) error { + // Verify IP comes from Alea's allowed IPs + // OR verify a signature header + + // Example signature verification: + receivedSig := c.Get("X-Alea-Signature") + body := c.Body() + + h := hmac.New(sha256.New, []byte(secretKey)) + h.Write(body) + expectedSig := hex.EncodeToString(h.Sum(nil)) + + if receivedSig != expectedSig { + return c.Status(fiber.StatusForbidden).JSON(fiber.Map{ + "error": "invalid signature", + }) + } + + return c.Next() + } +} + +// Then update your route: diff --git a/internal/repository/virtual_game.go b/internal/repository/virtual_game.go index cfa6fee..0fa5429 100644 --- a/internal/repository/virtual_game.go +++ b/internal/repository/virtual_game.go @@ -14,6 +14,7 @@ type VirtualGameRepository interface { CreateVirtualGameSession(ctx context.Context, session *domain.VirtualGameSession) error GetVirtualGameSessionByToken(ctx context.Context, token string) (*domain.VirtualGameSession, error) UpdateVirtualGameSessionStatus(ctx context.Context, id int64, status string) error + // UpdateVirtualGameSessionStatus(ctx context.Context, id int64, status string) error CreateVirtualGameTransaction(ctx context.Context, tx *domain.VirtualGameTransaction) error GetVirtualGameTransactionByExternalID(ctx context.Context, externalID string) (*domain.VirtualGameTransaction, error) UpdateVirtualGameTransactionStatus(ctx context.Context, id int64, status string) error diff --git a/internal/router/router.chapa.go b/internal/router/router.chapa.go deleted file mode 100644 index 6b5a09e..0000000 --- a/internal/router/router.chapa.go +++ /dev/null @@ -1,37 +0,0 @@ -package router - -// @title FortuneBet Chapa API - -// import ( -// "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" -// "github.com/gofiber/fiber/v2" -// ) - -// func ChapaRoutes(app *fiber.App) { - -// chapaRouter := app.Group("/api/v1/chapa") - -// chapaRouter.Post("/payments/initialize", -// wallet.InitializePayment, -// ) - -// chapaRouter.Get("/payments/verify/:tx_ref", -// wallet.VerifyTransaction, -// ) - -// chapaRouter.Post("/payments/callback", -// wallet.ReceiveWebhook, -// ) - -// chapaRouter.Get("/banks", -// wallet.GetBanks, -// ) - -// chapaRouter.Post("/transfers", -// wallet.CreateTransfer, -// ) - -// chapaRouter.Get("/transfers/:transfer_ref", -// wallet.VerifyTransfer, -// ) -// } diff --git a/internal/services/virtualGame/Alea/port.go b/internal/services/virtualGame/Alea/port.go new file mode 100644 index 0000000..c5d4ac0 --- /dev/null +++ b/internal/services/virtualGame/Alea/port.go @@ -0,0 +1,12 @@ +package alea + +import ( + "context" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" +) + +type AleaVirtualGameService interface { + GenerateGameLaunchURL(ctx context.Context, userID int64, gameID, currency, mode string) (string, error) + HandleCallback(ctx context.Context, callback *domain.AleaPlayCallback) error +} diff --git a/internal/services/virtualGame/Alea/service.go b/internal/services/virtualGame/Alea/service.go new file mode 100644 index 0000000..aadd179 --- /dev/null +++ b/internal/services/virtualGame/Alea/service.go @@ -0,0 +1,159 @@ +package alea + +import ( + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "log/slog" + "net/url" + "time" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/config" + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" + "github.com/SamuelTariku/FortuneBet-Backend/internal/repository" + "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" +) + +type AleaPlayService struct { + repo repository.VirtualGameRepository + walletSvc wallet.Service + config *config.AleaPlayConfig + logger *slog.Logger +} + +func NewAleaPlayService( + repo repository.VirtualGameRepository, + walletSvc wallet.Service, + cfg *config.Config, + logger *slog.Logger, +) *AleaPlayService { + return &AleaPlayService{ + repo: repo, + walletSvc: walletSvc, + config: &cfg.AleaPlay, + logger: logger, + } +} + +func (s *AleaPlayService) GenerateGameLaunchURL(ctx context.Context, userID int64, gameID, currency, mode string) (string, error) { + session := &domain.VirtualGameSession{ + UserID: userID, + GameID: gameID, + SessionToken: generateSessionToken(userID), + Currency: currency, + Status: "ACTIVE", + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + ExpiresAt: time.Now().Add(24 * time.Hour), + } + + if err := s.repo.CreateVirtualGameSession(ctx, session); err != nil { + return "", fmt.Errorf("failed to create game session: %w", err) + } + + params := url.Values{ + "operator_id": []string{s.config.OperatorID}, + "user_id": []string{fmt.Sprintf("%d", userID)}, + "game_id": []string{gameID}, + "currency": []string{currency}, + "session_token": []string{session.SessionToken}, + "mode": []string{mode}, + "timestamp": []string{fmt.Sprintf("%d", time.Now().Unix())}, + } + + signature := s.generateSignature(params.Encode()) + params.Add("signature", signature) + + return fmt.Sprintf("%s/launch?%s", s.config.BaseURL, params.Encode()), nil +} + +func (s *AleaPlayService) HandleCallback(ctx context.Context, callback *domain.AleaPlayCallback) error { + if !s.verifyCallbackSignature(callback) { + return errors.New("invalid callback signature") + } + + if existing, _ := s.repo.GetVirtualGameTransactionByExternalID(ctx, callback.TransactionID); existing != nil { + s.logger.Warn("duplicate transaction detected", "tx_id", callback.TransactionID) + return nil + } + + session, err := s.repo.GetVirtualGameSessionByToken(ctx, callback.SessionID) + if err != nil { + return fmt.Errorf("failed to get game session: %w", err) + } + + tx := &domain.VirtualGameTransaction{ + SessionID: session.ID, + UserID: session.UserID, + TransactionType: callback.Type, + Amount: convertAmount(callback.Amount, callback.Type), + Currency: callback.Currency, + ExternalTransactionID: callback.TransactionID, + Status: "COMPLETED", + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + if err := s.processTransaction(ctx, tx, session.UserID); err != nil { + return fmt.Errorf("failed to process transaction: %w", err) + } + + // Update session status using the proper repository method + if callback.Type == "SESSION_END" { + if err := s.repo.UpdateVirtualGameSessionStatus(ctx, session.ID, "COMPLETED"); err != nil { + s.logger.Error("failed to update session status", + "sessionID", session.ID, + "error", err) + } + } + + return nil +} + +func convertAmount(amount float64, txType string) int64 { + cents := int64(amount * 100) + if txType == "BET" { + return -cents + } + return cents +} + +func (s *AleaPlayService) processTransaction(ctx context.Context, tx *domain.VirtualGameTransaction, userID int64) error { + wallets, err := s.walletSvc.GetWalletsByUser(ctx, userID) + if err != nil || len(wallets) == 0 { + return errors.New("no wallet available for user") + } + tx.WalletID = wallets[0].ID + + if err := s.walletSvc.AddToWallet(ctx, tx.WalletID, domain.Currency(tx.Amount)); err != nil { + return fmt.Errorf("wallet update failed: %w", err) + } + + return s.repo.CreateVirtualGameTransaction(ctx, tx) +} + +func (s *AleaPlayService) generateSignature(data string) string { + h := hmac.New(sha256.New, []byte(s.config.SecretKey)) + h.Write([]byte(data)) + return hex.EncodeToString(h.Sum(nil)) +} + +func (s *AleaPlayService) verifyCallbackSignature(cb *domain.AleaPlayCallback) bool { + signData := fmt.Sprintf("%s%s%s%.2f%s%d", + cb.TransactionID, + cb.SessionID, + cb.Type, + cb.Amount, + cb.Currency, + cb.Timestamp, + ) + expectedSig := s.generateSignature(signData) + return expectedSig == cb.Signature +} + +func generateSessionToken(userID int64) string { + return fmt.Sprintf("alea-%d-%d", userID, time.Now().UnixNano()) +} diff --git a/internal/services/virtualGame/port.go b/internal/services/virtualGame/port.go index d473355..0814a07 100644 --- a/internal/services/virtualGame/port.go +++ b/internal/services/virtualGame/port.go @@ -10,3 +10,4 @@ type VirtualGameService interface { GenerateGameLaunchURL(ctx context.Context, userID int64, gameID, currency, mode string) (string, error) HandleCallback(ctx context.Context, callback *domain.PopOKCallback) error } + diff --git a/internal/services/virtualGame/service.go b/internal/services/virtualGame/service.go index 1b5824e..688c8ef 100644 --- a/internal/services/virtualGame/service.go +++ b/internal/services/virtualGame/service.go @@ -32,8 +32,7 @@ func New(repo repository.VirtualGameRepository, walletSvc wallet.Service, store walletSvc: walletSvc, store: store, config: cfg, - logger: logger, - } + logger: logger} } func (s *service) GenerateGameLaunchURL(ctx context.Context, userID int64, gameID, currency, mode string) (string, error) { diff --git a/internal/web_server/app.go b/internal/web_server/app.go index c41d9f0..e036a6b 100644 --- a/internal/web_server/app.go +++ b/internal/web_server/app.go @@ -17,6 +17,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame" + alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt" customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator" @@ -28,27 +29,28 @@ import ( ) type App struct { - fiber *fiber.App - logger *slog.Logger - NotidicationStore notificationservice.NotificationStore - referralSvc referralservice.ReferralStore - port int - authSvc *authentication.Service - userSvc *user.Service - betSvc *bet.Service - virtualGameSvc virtualgameservice.VirtualGameService - walletSvc *wallet.Service - transactionSvc *transaction.Service - ticketSvc *ticket.Service - branchSvc *branch.Service - companySvc *company.Service - validator *customvalidator.CustomValidator - JwtConfig jwtutil.JwtConfig - Logger *slog.Logger - prematchSvc *odds.ServiceImpl - eventSvc event.Service - resultSvc *result.Service - cfg *config.Config + fiber *fiber.App + logger *slog.Logger + NotidicationStore notificationservice.NotificationStore + referralSvc referralservice.ReferralStore + port int + authSvc *authentication.Service + userSvc *user.Service + betSvc *bet.Service + virtualGameSvc virtualgameservice.VirtualGameService + aleaVirtualGameService alea.AleaVirtualGameService + walletSvc *wallet.Service + transactionSvc *transaction.Service + ticketSvc *ticket.Service + branchSvc *branch.Service + companySvc *company.Service + validator *customvalidator.CustomValidator + JwtConfig jwtutil.JwtConfig + Logger *slog.Logger + prematchSvc *odds.ServiceImpl + eventSvc event.Service + resultSvc *result.Service + cfg *config.Config } func NewApp( @@ -68,6 +70,7 @@ func NewApp( eventSvc event.Service, referralSvc referralservice.ReferralStore, virtualGameSvc virtualgameservice.VirtualGameService, + aleaVirtualGameService alea.AleaVirtualGameService, resultSvc *result.Service, cfg *config.Config, ) *App { @@ -86,27 +89,28 @@ func NewApp( })) s := &App{ - fiber: app, - port: port, - authSvc: authSvc, - validator: validator, - logger: logger, - JwtConfig: JwtConfig, - userSvc: userSvc, - ticketSvc: ticketSvc, - betSvc: betSvc, - walletSvc: walletSvc, - transactionSvc: transactionSvc, - branchSvc: branchSvc, - companySvc: companySvc, - NotidicationStore: notidicationStore, - referralSvc: referralSvc, - Logger: logger, - prematchSvc: prematchSvc, - eventSvc: eventSvc, - virtualGameSvc: virtualGameSvc, - resultSvc: resultSvc, - cfg: cfg, + fiber: app, + port: port, + authSvc: authSvc, + validator: validator, + logger: logger, + JwtConfig: JwtConfig, + userSvc: userSvc, + ticketSvc: ticketSvc, + betSvc: betSvc, + walletSvc: walletSvc, + transactionSvc: transactionSvc, + branchSvc: branchSvc, + companySvc: companySvc, + NotidicationStore: notidicationStore, + referralSvc: referralSvc, + Logger: logger, + prematchSvc: prematchSvc, + eventSvc: eventSvc, + virtualGameSvc: virtualGameSvc, + aleaVirtualGameService: aleaVirtualGameService, + resultSvc: resultSvc, + cfg: cfg, } s.initAppRoutes() diff --git a/internal/web_server/handlers/alea_games.go b/internal/web_server/handlers/alea_games.go new file mode 100644 index 0000000..01e4bb6 --- /dev/null +++ b/internal/web_server/handlers/alea_games.go @@ -0,0 +1,76 @@ +package handlers + +import ( + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" + "github.com/gofiber/fiber/v2" +) + +// LaunchAleaGame godoc +// @Summary Launch an Alea Play virtual game +// @Description Generates an authenticated launch URL for Alea Play virtual games +// @Tags Alea Virtual Games +// @Accept json +// @Produce json +// @Security BearerAuth +// @Param game_id query string true "Game identifier (e.g., 'aviator', 'plinko')" +// @Param currency query string false "Currency code (ISO 4217)" Enums(USD, EUR, GBP) default(USD) +// @Param mode query string false "Game mode" Enums(real, demo) default(real) +// @Success 200 {object} map[string]string{launch_url=string} "Returns authenticated game launch URL" +// @Failure 400 {object} map[string]string "Invalid request parameters" +// @Failure 401 {object} map[string]string "Unauthorized" +// @Failure 500 {object} map[string]string "Internal server error" +// @Router /api/v1/alea-games/launch [get] +func (h *Handler) LaunchAleaGame(c *fiber.Ctx) error { + userID := c.Locals("userID").(int64) + gameID := c.Query("game_id") + currency := c.Query("currency", "USD") + mode := c.Query("mode", "real") // real or demo + + launchURL, err := h.aleaVirtualGameSvc.GenerateGameLaunchURL(c.Context(), userID, gameID, currency, mode) + if err != nil { + h.logger.Error("failed to generate Alea launch URL", "error", err) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "failed to launch game", + }) + } + + return c.JSON(fiber.Map{ + "launch_url": launchURL, + }) +} + +// HandleAleaCallback godoc +// @Summary Process Alea Play game callback +// @Description Handles webhook callbacks from Alea Play virtual games for bet settlement +// @Tags Alea Virtual Games +// @Accept json +// @Produce json +// @Param callback body domain.AleaPlayCallback true "Callback payload" +// @Success 200 {object} map[string]string{status=string} "Callback processed successfully" +// @Failure 400 {object} map[string]string "Invalid callback format" +// @Failure 401 {object} map[string]string "Invalid signature" +// @Failure 409 {object} map[string]string "Duplicate transaction" +// @Failure 500 {object} map[string]string "Internal processing error" +// @Router /api/v1/webhooks/alea [post] +func (h *Handler) HandleAleaCallback(c *fiber.Ctx) error { + var cb domain.AleaPlayCallback + if err := c.BodyParser(&cb); err != nil { + h.logger.Error("invalid Alea callback format", "error", err) + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "invalid callback format", + }) + } + + if err := h.aleaVirtualGameSvc.HandleCallback(c.Context(), &cb); err != nil { + h.logger.Error("failed to process Alea callback", + "transactionID", cb.TransactionID, + "error", err) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "failed to process callback", + }) + } + + return c.JSON(fiber.Map{ + "status": "processed", + }) +} diff --git a/internal/web_server/handlers/chapa.go b/internal/web_server/handlers/chapa.go index 1f80787..3fc66c0 100644 --- a/internal/web_server/handlers/chapa.go +++ b/internal/web_server/handlers/chapa.go @@ -17,7 +17,7 @@ import ( // @Tags Chapa // @Accept json // @Produce json -// @Success 200 {object} ChapaSupportedBanksResponse +// @Success 200 {object} domain.ChapaSupportedBanksResponse // @Router /api/v1/chapa/banks [get] func (h *Handler) GetBanks(c *fiber.Ctx) error { httpReq, err := http.NewRequest("GET", h.Cfg.CHAPA_BASE_URL+"/banks", nil) @@ -47,10 +47,8 @@ func (h *Handler) GetBanks(c *fiber.Ctx) error { // @Tags Chapa // @Accept json // @Produce json -// @Param payload body InitPaymentRequest true "Payment initialization request" -// @Success 200 {object} InitPaymentResponse -// @Failure 400 {object} map[string]string -// @Failure 500 {object} map[string]string +// @Param payload body domain.InitPaymentRequest true "Payment initialization request" +// @Success 200 {object} domain.InitPaymentResponse // @Router /api/v1/chapa/payments/initialize [post] func (h *Handler) InitializePayment(c *fiber.Ctx) error { var req InitPaymentRequest @@ -109,9 +107,7 @@ func (h *Handler) InitializePayment(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param tx_ref path string true "Transaction Reference" -// @Success 200 {object} VerifyTransactionResponse -// @Failure 400 {object} map[string]string -// @Failure 500 {object} map[string]string +// @Success 200 {object} domain.VerifyTransactionResponse // @Router /api/v1/chapa/payments/verify/{tx_ref} [get] func (h *Handler) VerifyTransaction(c *fiber.Ctx) error { txRef := c.Params("tx_ref") @@ -183,10 +179,8 @@ func (h *Handler) ReceiveWebhook(c *fiber.Ctx) error { // @Tags Chapa // @Accept json // @Produce json -// @Param payload body TransferRequest true "Transfer request body" -// @Success 200 {object} CreateTransferResponse -// @Failure 400 {object} map[string]string -// @Failure 500 {object} map[string]string +// @Param payload body domain.TransferRequest true "Transfer request body" +// @Success 200 {object} domain.CreateTransferResponse // @Router /api/v1/chapa/transfers [post] func (h *Handler) CreateTransfer(c *fiber.Ctx) error { var req TransferRequest @@ -246,9 +240,7 @@ func (h *Handler) CreateTransfer(c *fiber.Ctx) error { // @Accept json // @Produce json // @Param transfer_ref path string true "Transfer Reference" -// @Success 200 {object} VerifyTransferResponse -// @Failure 400 {object} map[string]string -// @Failure 500 {object} map[string]string +// @Success 200 {object} domain.VerifyTransferResponse // @Router /api/v1/chapa/transfers/verify/{transfer_ref} [get] func (h *Handler) VerifyTransfer(c *fiber.Ctx) error { transferRef := c.Params("transfer_ref") diff --git a/internal/web_server/handlers/handlers.go b/internal/web_server/handlers/handlers.go index 2b4b836..ac4d495 100644 --- a/internal/web_server/handlers/handlers.go +++ b/internal/web_server/handlers/handlers.go @@ -16,29 +16,31 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame" + alea "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/Alea" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt" customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator" ) type Handler struct { - logger *slog.Logger - notificationSvc notificationservice.NotificationStore - userSvc *user.Service - referralSvc referralservice.ReferralStore - walletSvc *wallet.Service - transactionSvc *transaction.Service - ticketSvc *ticket.Service - betSvc *bet.Service - branchSvc *branch.Service - companySvc *company.Service - prematchSvc *odds.ServiceImpl - eventSvc event.Service - virtualGameSvc virtualgameservice.VirtualGameService - authSvc *authentication.Service - jwtConfig jwtutil.JwtConfig - validator *customvalidator.CustomValidator - Cfg *config.Config + logger *slog.Logger + notificationSvc notificationservice.NotificationStore + userSvc *user.Service + referralSvc referralservice.ReferralStore + walletSvc *wallet.Service + transactionSvc *transaction.Service + ticketSvc *ticket.Service + betSvc *bet.Service + branchSvc *branch.Service + companySvc *company.Service + prematchSvc *odds.ServiceImpl + eventSvc event.Service + virtualGameSvc virtualgameservice.VirtualGameService + aleaVirtualGameSvc alea.AleaVirtualGameService + authSvc *authentication.Service + jwtConfig jwtutil.JwtConfig + validator *customvalidator.CustomValidator + Cfg *config.Config } func New( @@ -48,6 +50,7 @@ func New( walletSvc *wallet.Service, referralSvc referralservice.ReferralStore, virtualGameSvc virtualgameservice.VirtualGameService, + aleaVirtualGameSvc alea.AleaVirtualGameService, userSvc *user.Service, transactionSvc *transaction.Service, ticketSvc *ticket.Service, @@ -61,22 +64,23 @@ func New( cfg *config.Config, ) *Handler { return &Handler{ - logger: logger, - notificationSvc: notificationSvc, - walletSvc: walletSvc, - referralSvc: referralSvc, - validator: validator, - userSvc: userSvc, - transactionSvc: transactionSvc, - ticketSvc: ticketSvc, - betSvc: betSvc, - branchSvc: branchSvc, - companySvc: companySvc, - prematchSvc: prematchSvc, - eventSvc: eventSvc, - virtualGameSvc: virtualGameSvc, - authSvc: authSvc, - jwtConfig: jwtConfig, - Cfg: cfg, + logger: logger, + notificationSvc: notificationSvc, + walletSvc: walletSvc, + referralSvc: referralSvc, + validator: validator, + userSvc: userSvc, + transactionSvc: transactionSvc, + ticketSvc: ticketSvc, + betSvc: betSvc, + branchSvc: branchSvc, + companySvc: companySvc, + prematchSvc: prematchSvc, + eventSvc: eventSvc, + virtualGameSvc: virtualGameSvc, + aleaVirtualGameSvc: aleaVirtualGameSvc, + authSvc: authSvc, + jwtConfig: jwtConfig, + Cfg: cfg, } } diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 20e84f5..fad2586 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -5,10 +5,8 @@ import ( "strconv" _ "github.com/SamuelTariku/FortuneBet-Backend/docs" - // "github.com/SamuelTariku/FortuneBet-Backend/internal/config" - // "github.com/SamuelTariku/FortuneBet-Backend/internal/config" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" - // "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" + "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/handlers" "github.com/gofiber/fiber/v2" @@ -23,6 +21,7 @@ func (a *App) initAppRoutes() { a.walletSvc, a.referralSvc, a.virtualGameSvc, + a.aleaVirtualGameService, a.userSvc, a.transactionSvc, a.ticketSvc, @@ -174,6 +173,11 @@ func (a *App) initAppRoutes() { a.fiber.Post("/api/v1/chapa/transfers", h.CreateTransfer) a.fiber.Get("/api/v1/chapa/transfers/verify/:transfer_ref", h.VerifyTransfer) + //Alea Play Virtual Game Routes + a.fiber.Get("/api/v1/alea-games/launch", h.LaunchAleaGame) + a.fiber.Post("/api/v1/webhooks/alea", h.HandleAleaCallback) + // a.fiber.Post("/webhooks/alea", middleware.AleaWebhookMiddleware(a.cfg.AleaPlay.SecretKey), h.HandleAleaCallback) + // Transactions /transactions a.fiber.Post("/transaction", a.authMiddleware, h.CreateTransaction) a.fiber.Get("/transaction", a.authMiddleware, h.GetAllTransactions)