From 66a7affebad8af5a1d486de23812e52e7c8b0ba8 Mon Sep 17 00:00:00 2001 From: Yared Yemane Date: Thu, 22 May 2025 18:35:20 +0300 Subject: [PATCH] chapa integration 1st phase --- cmd/main.go | 17 +- cmd/router.go | 9 + go.mod | 3 +- go.sum | 6 - internal/config/config.go | 21 +- internal/models/models.chapa.go | 2 + internal/router/router.chapa.go | 37 ++++ internal/services/wallet/chapa.go | 1 - internal/utils/utils.chapa.go | 19 ++ internal/web_server/app.go | 4 + internal/web_server/handlers/chapa.go | 250 +++++++++++++++++++++++ internal/web_server/handlers/handlers.go | 4 + internal/web_server/routes.go | 12 ++ makefile | 6 +- 14 files changed, 377 insertions(+), 14 deletions(-) create mode 100644 cmd/router.go create mode 100644 internal/models/models.chapa.go create mode 100644 internal/router/router.chapa.go delete mode 100644 internal/services/wallet/chapa.go create mode 100644 internal/utils/utils.chapa.go create mode 100644 internal/web_server/handlers/chapa.go diff --git a/cmd/main.go b/cmd/main.go index f6fd907..6eedda0 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,12 +7,15 @@ import ( "os" "github.com/go-playground/validator/v10" + // "github.com/gofiber/fiber/v2" "github.com/SamuelTariku/FortuneBet-Backend/internal/config" customlogger "github.com/SamuelTariku/FortuneBet-Backend/internal/logger" mockemail "github.com/SamuelTariku/FortuneBet-Backend/internal/mocks/mock_email" mocksms "github.com/SamuelTariku/FortuneBet-Backend/internal/mocks/mock_sms" "github.com/SamuelTariku/FortuneBet-Backend/internal/repository" + + // "github.com/SamuelTariku/FortuneBet-Backend/internal/router" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch" @@ -27,6 +30,8 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" + + // "github.com/SamuelTariku/FortuneBet-Backend/internal/utils" httpserver "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server" jwtutil "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/jwt" customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator" @@ -46,6 +51,16 @@ import ( // @name Authorization // @BasePath / func main() { + + // utils.Init() + + // fiberApp := fiber.New() + + // fiberApp.Get("/health", func(c *fiber.Ctx) error { + // return c.SendString("Betting service is up and running!") + // }) + // router.ChapaRoutes(fiberApp) + cfg, err := config.NewConfig() if err != nil { slog.Error(" Config error:", "err", err) @@ -92,7 +107,7 @@ func main() { JwtAccessKey: cfg.JwtKey, JwtAccessExpiry: cfg.AccessExpiry, }, userSvc, - ticketSvc, betSvc, walletSvc, transactionSvc, branchSvc, companySvc, notificationSvc, oddsSvc, eventSvc, referalSvc, virtualGameSvc, resultSvc) + ticketSvc, betSvc, walletSvc, transactionSvc, branchSvc, companySvc, notificationSvc, oddsSvc, eventSvc, referalSvc, virtualGameSvc, resultSvc, cfg) logger.Info("Starting server", "port", cfg.Port) if err := app.Run(); err != nil { diff --git a/cmd/router.go b/cmd/router.go new file mode 100644 index 0000000..5c95681 --- /dev/null +++ b/cmd/router.go @@ -0,0 +1,9 @@ +package main + +import "github.com/gofiber/fiber/v2" + +func SetupRoutes(app *fiber.App) { + app.Get("/health", func(c *fiber.Ctx) error { + return c.SendString("Betting service is up and running!") + }) +} diff --git a/go.mod b/go.mod index a510af6..5a8e5eb 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( require ( github.com/KyleBanks/depth v1.2.1 // indirect github.com/andybalholm/brotli v1.1.1 // indirect + // github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/bytedance/sonic/loader v0.2.4 // indirect github.com/cloudwego/base64x v0.1.5 // indirect github.com/fasthttp/websocket v1.5.8 // indirect @@ -31,7 +32,7 @@ require ( github.com/go-openapi/swag v0.23.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/gofiber/contrib/websocket v1.3.4 + // github.com/gofiber/contrib/websocket v1.3.4 github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect diff --git a/go.sum b/go.sum index 9e77972..87d14e2 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,6 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fasthttp/websocket v1.5.3 h1:TPpQuLwJYfd4LJPXvHDYPMFWbLjsT91n3GpWtCQtdek= -github.com/fasthttp/websocket v1.5.3/go.mod h1:46gg/UBmTU1kUaTcwQXpUxtRwG2PvIZYeA8oL6vF3Fs= github.com/fasthttp/websocket v1.5.8 h1:k5DpirKkftIF/w1R8ZzjSgARJrs54Je9YJK37DL/Ah8= github.com/fasthttp/websocket v1.5.8/go.mod h1:d08g8WaT6nnyvg9uMm8K9zMYyDjfKyj3170AtPRuVU0= github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= @@ -51,8 +49,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= -github.com/gofiber/contrib/websocket v1.3.4 h1:tWeBdbJ8q0WFQXariLN4dBIbGH9KBU75s0s7YXplOSg= -github.com/gofiber/contrib/websocket v1.3.4/go.mod h1:kTFBPC6YENCnKfKx0BoOFjgXxdz7E85/STdkmZPEmPs= github.com/gofiber/fiber/v2 v2.32.0/go.mod h1:CMy5ZLiXkn6qwthrl03YMyW1NLfj0rhxz2LKl4t7ZTY= github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI= github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= @@ -118,8 +114,6 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511 h1:KanIMPX0QdEdB4R3CiimCAbxFrhB3j7h0/OvpYGVQa8= github.com/savsgio/gotils v0.0.0-20240303185622-093b76447511/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= diff --git a/internal/config/config.go b/internal/config/config.go index e58f153..9418707 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -21,7 +21,7 @@ var ( ErrInvalidLevel = errors.New("invalid log level") ErrInvalidEnv = errors.New("env not set or invalid") ErrInvalidSMSAPIKey = errors.New("SMS API key is invalid") - ErrMissingBetToken = errors.New("missing BET365_TOKEN in .env") + ErrMissingBetToken = errors.New("missing BET365_TOKEN in .env") ErrInvalidPopOKClientID = errors.New("PopOK client ID is invalid") ErrInvalidPopOKSecretKey = errors.New("PopOK secret key is invalid") ErrInvalidPopOKBaseURL = errors.New("PopOK base URL is invalid") @@ -40,7 +40,13 @@ type Config struct { AFRO_SMS_SENDER_NAME string AFRO_SMS_RECEIVER_PHONE_NUMBER string ADRO_SMS_HOST_URL string - Bet365Token string + CHAPA_SECRET_KEY string + CHAPA_PUBLIC_KEY string + CHAPA_BASE_URL string + CHAPA_ENCRYPTION_KEY string + CHAPA_CALLBACK_URL string + CHAPA_RETURN_URL string + Bet365Token string PopOK domain.PopOKConfig } @@ -115,6 +121,17 @@ func (c *Config) loadEnv() error { if !ok { return ErrInvalidLevel } + + c.CHAPA_SECRET_KEY = os.Getenv("CHAPA_SECRET_KEY") + c.CHAPA_PUBLIC_KEY = os.Getenv("CHAPA_PUBLIC_KEY") + c.CHAPA_ENCRYPTION_KEY = os.Getenv("CHAPA_ENCRYPTION_KEY") + c.CHAPA_BASE_URL = os.Getenv("CHAPA_BASE_URL") + if c.CHAPA_BASE_URL == "" { + c.CHAPA_BASE_URL = "https://api.chapa.co/v1" + } + c.CHAPA_CALLBACK_URL = os.Getenv("CHAPA_CALLBACK_URL") + c.CHAPA_RETURN_URL = os.Getenv("CHAPA_RETURN_URL") + c.LogLevel = lvl c.AFRO_SMS_API_KEY = os.Getenv("AFRO_SMS_API_KEY") diff --git a/internal/models/models.chapa.go b/internal/models/models.chapa.go new file mode 100644 index 0000000..d6a05a4 --- /dev/null +++ b/internal/models/models.chapa.go @@ -0,0 +1,2 @@ +package models + diff --git a/internal/router/router.chapa.go b/internal/router/router.chapa.go new file mode 100644 index 0000000..6b5a09e --- /dev/null +++ b/internal/router/router.chapa.go @@ -0,0 +1,37 @@ +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/wallet/chapa.go b/internal/services/wallet/chapa.go deleted file mode 100644 index 23a7507..0000000 --- a/internal/services/wallet/chapa.go +++ /dev/null @@ -1 +0,0 @@ -package wallet diff --git a/internal/utils/utils.chapa.go b/internal/utils/utils.chapa.go new file mode 100644 index 0000000..5005d3a --- /dev/null +++ b/internal/utils/utils.chapa.go @@ -0,0 +1,19 @@ +package utils + +// import ( +// "log" +// "os" + +// "github.com/SamuelTariku/FortuneBet-Backend/internal/models" +// ) + +// func Init() { +// if err != nil { +// log.Println("No .env file found") +// } +// models.ChapaSecret = os.Getenv("CHAPA_SECRET_KEY") +// models.ChapaBaseURL = os.Getenv("CHAPA_BASE_URL") +// if models.ChapaBaseURL == "" { +// models.ChapaBaseURL = "https://api.chapa.co/v1" +// } +// } diff --git a/internal/web_server/app.go b/internal/web_server/app.go index f3e50bd..c41d9f0 100644 --- a/internal/web_server/app.go +++ b/internal/web_server/app.go @@ -4,6 +4,7 @@ import ( "fmt" "log/slog" + "github.com/SamuelTariku/FortuneBet-Backend/internal/config" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch" @@ -47,6 +48,7 @@ type App struct { prematchSvc *odds.ServiceImpl eventSvc event.Service resultSvc *result.Service + cfg *config.Config } func NewApp( @@ -67,6 +69,7 @@ func NewApp( referralSvc referralservice.ReferralStore, virtualGameSvc virtualgameservice.VirtualGameService, resultSvc *result.Service, + cfg *config.Config, ) *App { app := fiber.New(fiber.Config{ CaseSensitive: true, @@ -103,6 +106,7 @@ func NewApp( eventSvc: eventSvc, virtualGameSvc: virtualGameSvc, resultSvc: resultSvc, + cfg: cfg, } s.initAppRoutes() diff --git a/internal/web_server/handlers/chapa.go b/internal/web_server/handlers/chapa.go new file mode 100644 index 0000000..9165226 --- /dev/null +++ b/internal/web_server/handlers/chapa.go @@ -0,0 +1,250 @@ +package handlers + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + // "github.com/SamuelTariku/FortuneBet-Backend/internal/config" + "github.com/gofiber/fiber/v2" +) + +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"` +} + +func (h *Handler) GetBanks(c *fiber.Ctx) error { + httpReq, err := http.NewRequest("GET", h.Cfg.CHAPA_BASE_URL+"/banks", nil) + // log.Printf("\n\nbase url is: %v\n\n", h.Cfg.CHAPA_BASE_URL) + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to create request", "details": err.Error()}) + } + httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY) + + resp, err := http.DefaultClient.Do(httpReq) + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to fetch banks", "details": err.Error()}) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return c.Status(500).JSON(fiber.Map{"error": "Failed to read response", "details": err.Error()}) + } + + return c.Status(resp.StatusCode).Send(body) +} + +func (h *Handler) InitializePayment(c *fiber.Ctx) error { + var req InitPaymentRequest + if err := c.BodyParser(&req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Invalid request body", + "details": err.Error(), + }) + } + + payload, err := json.Marshal(req) + if err != nil { + return c.Status(500).JSON(fiber.Map{ + "error": "Failed to serialize request", + "details": err.Error(), + }) + } + + httpReq, err := http.NewRequest("POST", h.Cfg.CHAPA_BASE_URL+"/transaction/initialize", bytes.NewBuffer(payload)) + if err != nil { + return c.Status(500).JSON(fiber.Map{ + "error": "Failed to create request", + "details": err.Error(), + }) + } + httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY) + httpReq.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(httpReq) + if err != nil { + return c.Status(500).JSON(fiber.Map{ + "error": "Failed to initialize payment", + "details": err.Error(), + }) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return c.Status(500).JSON(fiber.Map{ + "error": "Failed to read response", + "details": err.Error(), + }) + } + + return c.Status(resp.StatusCode).Send(body) +} + +func (h *Handler) VerifyTransaction(c *fiber.Ctx) error { + txRef := c.Params("tx_ref") + if txRef == "" { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Missing transaction reference", + }) + } + + url := fmt.Sprintf("%s/transaction/verify/%s", h.Cfg.CHAPA_BASE_URL, txRef) + + httpReq, err := http.NewRequest("GET", url, nil) + if err != nil { + return c.Status(500).JSON(fiber.Map{ + "error": "Failed to create request", + "details": err.Error(), + }) + } + httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY) + + resp, err := http.DefaultClient.Do(httpReq) + if err != nil { + return c.Status(500).JSON(fiber.Map{ + "error": "Failed to verify transaction", + "details": err.Error(), + }) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return c.Status(500).JSON(fiber.Map{ + "error": "Failed to read response", + "details": err.Error(), + }) + } + + return c.Status(resp.StatusCode).Send(body) +} + +func (h *Handler) ReceiveWebhook(c *fiber.Ctx) error { + var payload map[string]interface{} + if err := c.BodyParser(&payload); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Invalid webhook data", + "details": err.Error(), + }) + } + + h.logger.Info("Chapa webhook received", "payload", payload) + + // Optional: you can verify tx_ref here again if needed + + return c.SendStatus(fiber.StatusOK) +} + +func (h *Handler) CreateTransfer(c *fiber.Ctx) error { + var req TransferRequest + if err := c.BodyParser(&req); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Invalid request", + "details": err.Error(), + }) + } + + payload, err := json.Marshal(req) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Failed to serialize request", + "details": err.Error(), + }) + } + + httpReq, err := http.NewRequest("POST", h.Cfg.CHAPA_BASE_URL+"/transfers", bytes.NewBuffer(payload)) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Failed to create HTTP request", + "details": err.Error(), + }) + } + + httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY) + httpReq.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(httpReq) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Transfer request failed", + "details": err.Error(), + }) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Failed to read response", + "details": err.Error(), + }) + } + + return c.Status(resp.StatusCode).Send(body) +} + +func (h *Handler) VerifyTransfer(c *fiber.Ctx) error { + transferRef := c.Params("transfer_ref") + if transferRef == "" { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Missing transfer reference in URL", + }) + } + + url := fmt.Sprintf("%s/transfers/%s", h.Cfg.CHAPA_BASE_URL, transferRef) + + httpReq, err := http.NewRequest("GET", url, nil) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Failed to create HTTP request", + "details": err.Error(), + }) + } + + httpReq.Header.Set("Authorization", "Bearer "+h.Cfg.CHAPA_SECRET_KEY) + + resp, err := http.DefaultClient.Do(httpReq) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Verification request failed", + "details": err.Error(), + }) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Failed to read response body", + "details": err.Error(), + }) + } + + return c.Status(resp.StatusCode).Send(body) +} diff --git a/internal/web_server/handlers/handlers.go b/internal/web_server/handlers/handlers.go index b5f811d..2b4b836 100644 --- a/internal/web_server/handlers/handlers.go +++ b/internal/web_server/handlers/handlers.go @@ -3,6 +3,7 @@ package handlers import ( "log/slog" + "github.com/SamuelTariku/FortuneBet-Backend/internal/config" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch" @@ -37,6 +38,7 @@ type Handler struct { authSvc *authentication.Service jwtConfig jwtutil.JwtConfig validator *customvalidator.CustomValidator + Cfg *config.Config } func New( @@ -56,6 +58,7 @@ func New( companySvc *company.Service, prematchSvc *odds.ServiceImpl, eventSvc event.Service, + cfg *config.Config, ) *Handler { return &Handler{ logger: logger, @@ -74,5 +77,6 @@ func New( virtualGameSvc: virtualGameSvc, authSvc: authSvc, jwtConfig: jwtConfig, + Cfg: cfg, } } diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 7b7e22a..6319bc6 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -5,7 +5,10 @@ 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" @@ -30,6 +33,7 @@ func (a *App) initAppRoutes() { a.companySvc, a.prematchSvc, a.eventSvc, + a.cfg, ) a.fiber.Get("/", func(c *fiber.Ctx) error { @@ -162,6 +166,14 @@ func (a *App) initAppRoutes() { a.fiber.Get("/transfer/wallet/:id", a.authMiddleware, h.GetTransfersByWallet) a.fiber.Post("/transfer/refill/:id", a.authMiddleware, h.RefillWallet) + //Chapa Routes + a.fiber.Post("/api/v1/chapa/payments/initialize", a.authMiddleware, h.InitializePayment) + a.fiber.Get("/api/v1/chapa/payments/verify/:tx_ref", a.authMiddleware, h.VerifyTransaction) + a.fiber.Post("/api/v1/chapa/payments/callback", a.authMiddleware, h.ReceiveWebhook) + a.fiber.Get("/api/v1/chapa/banks", a.authMiddleware, h.GetBanks) + a.fiber.Post("/api/v1/chapa/transfers", a.authMiddleware, h.CreateTransfer) + a.fiber.Get("/api/v1/chapa/transfers/:transfer_ref", a.authMiddleware, h.VerifyTransfer) + // Transactions /transactions a.fiber.Post("/transaction", a.authMiddleware, h.CreateTransaction) a.fiber.Get("/transaction", a.authMiddleware, h.GetAllTransactions) diff --git a/makefile b/makefile index 79017cf..ebf6b14 100644 --- a/makefile +++ b/makefile @@ -9,7 +9,7 @@ coverage: @go tool cover -func=coverage.out -o coverage/coverage.txt .PHONY: build build: - @go build -ldflags="-s" -o ./bin/web ./ + @go build -ldflags="-s" -o ./bin/web ./cmd/main.go .PHONY: run run: @echo "Running Go application" @@ -18,7 +18,7 @@ run: air: @echo "Running air" @air -c .air.toml -.PHONY: migrations/up +.PHONY: migrations/new migrations/new: @echo 'Creating migration files for DB_URL' @migrate create -seq -ext=.sql -dir=./db/migrations $(name) @@ -38,4 +38,4 @@ db-down: docker compose -f compose.db.yaml down .PHONY: sqlc-gen sqlc-gen: - @sqlc generate + @sqlc generate \ No newline at end of file