From eebcdd360c950de64f1fdef896b984505fd88576 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 19 May 2024 19:00:03 +0300 Subject: [PATCH 1/8] api controllers full rework for fiber --- internal/interface/swagger/api.2.go | 501 ++++++++++++----------- internal/interface/swagger/models.gen.go | 299 -------------- 2 files changed, 273 insertions(+), 527 deletions(-) delete mode 100644 internal/interface/swagger/models.gen.go diff --git a/internal/interface/swagger/api.2.go b/internal/interface/swagger/api.2.go index 7ee99a4..d23e780 100644 --- a/internal/interface/swagger/api.2.go +++ b/internal/interface/swagger/api.2.go @@ -4,14 +4,12 @@ import ( "fmt" "github.com/gofiber/fiber/v2" "math" - "net/http" - "net/url" "os" codeword_rpc "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/codeword" + "strconv" "sync" "time" - "github.com/labstack/echo/v4" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" "google.golang.org/protobuf/types/known/timestamppb" @@ -25,7 +23,6 @@ import ( "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils/transfer" - "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/echotools" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate" ) @@ -92,179 +89,199 @@ func NewAPI2(logger *zap.Logger, db *mongo.Database, config *models.Config, cons } } -func (api *API2) error(ctx echo.Context, status int, message string, rest ...any) error { +func (api *API2) error(ctx *fiber.Ctx, status int, message string, rest ...any) error { if len(rest) > 0 { message = fmt.Sprintf(message, rest...) } api.logger.Error(message) - return ctx.JSON(status, models.ResponseErrorHTTP{ + return ctx.Status(status).JSON(models.ResponseErrorHTTP{ StatusCode: status, Message: message, }) } -func (api *API2) errorOld(ctx echo.Context, err errors.Error) error { +func (api *API2) errorOld(ctx *fiber.Ctx, err error) error { api.logger.Error("error:", zap.Error(err)) - return errors.HTTP(ctx, err) + return ctx.Status(fiber.StatusInternalServerError).JSON(models.ResponseErrorHTTP{ + StatusCode: fiber.StatusInternalServerError, + Message: err.Error(), + }) } -func (api *API2) noauth(ctx echo.Context) error { - return api.error(ctx, http.StatusUnauthorized, "failed to get jwt payload") +func (api *API2) noauth(ctx *fiber.Ctx) error { + return api.error(ctx, fiber.StatusUnauthorized, "failed to get jwt payload") } // Health -func (api *API2) GetHealth(ctx echo.Context) error { - return ctx.String(http.StatusOK, "OK") +func (api *API2) GetHealth(ctx *fiber.Ctx) error { + return ctx.Status(fiber.StatusOK).SendString("OK") } // Account -func (api *API2) DeleteAccount(ctx echo.Context) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) DeleteAccount(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - account, err := api.account.Remove(ctx.Request().Context(), userID) + account, err := api.account.Remove(ctx.Context(), userID) if err != nil { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, account) + return ctx.Status(fiber.StatusOK).JSON(account) } -func (api *API2) ChangeAccount(ctx echo.Context) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) ChangeAccount(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - request, bindErr := echotools.Bind[models.Name](ctx) - if bindErr != nil { - return api.error(ctx, http.StatusBadRequest, "failed to bind json: %w", bindErr) + var request models.Name + if err := ctx.BodyParser(&request); err != nil { + return api.error(ctx, fiber.StatusBadRequest, "failed to bind json", err) } - account, err := api.account.UpdateName(ctx.Request().Context(), userID, request) + account, err := api.account.UpdateName(ctx.Context(), userID, &request) if err != nil { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, account) + return ctx.Status(fiber.StatusOK).JSON(account) } -func (api *API2) SetAccountVerificationStatus(ctx echo.Context, userID string) error { - request, bindErr := echotools.Bind[models.SetAccountStatus](ctx) - if bindErr != nil { - return api.error(ctx, http.StatusBadRequest, "failed to bind json: %w", bindErr) +func (api *API2) SetAccountVerificationStatus(ctx *fiber.Ctx) error { + userID := ctx.Params("userId") + if userID == "" { + return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") + } + var request models.SetAccountStatus + if err := ctx.BodyParser(&request); err != nil { + return api.error(ctx, fiber.StatusBadRequest, "failed to bind json", err) } - account, err := api.account.SetStatus(ctx.Request().Context(), userID, request.Status) + account, err := api.account.SetStatus(ctx.Context(), userID, request.Status) if err != nil { api.logger.Error("failed to set status on of ", zap.Error(err)) return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, account) + return ctx.Status(fiber.StatusOK).JSON(account) } -func (api *API2) GetAccount(ctx echo.Context) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) GetAccount(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - account, err := api.account.FindByUserID(ctx.Request().Context(), userID) + account, err := api.account.FindByUserID(ctx.Context(), userID) if err != nil { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, account) + return ctx.Status(fiber.StatusOK).JSON(account) } -func (api *API2) AddAccount(ctx echo.Context) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) AddAccount(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - var quizFrom, quizUser string - cookie, er := ctx.Request().Cookie("quizFrom") - if er == nil { - quizFrom = cookie.Value - } + var er error - cookie, er = ctx.Request().Cookie("quizUser") - if er == nil { - quizUser, er = url.QueryUnescape(cookie.Value) - if er == nil { - quizUser, er = api.encrypt.DecryptStr([]byte(quizUser)) + quizFrom := ctx.Cookies("quizFrom") + quizUser := ctx.Cookies("quizUser") + if quizUser != "" { + quizUser, er = api.encrypt.DecryptStr([]byte(quizUser)) + if er != nil { + return api.errorOld(ctx, er) } } - account, err := api.account.FindByUserID(ctx.Request().Context(), userID) + account, err := api.account.FindByUserID(ctx.Context(), userID) if err != nil && err.Type() != errors.ErrNotFound { return api.errorOld(ctx, err) } if account != nil { - return api.error(ctx, http.StatusBadRequest, "account exists") + return api.error(ctx, fiber.StatusBadRequest, "account exists") } - user, err := api.clients.auth.GetUser(ctx.Request().Context(), userID) + user, err := api.clients.auth.GetUser(ctx.Context(), userID) if err != nil { return api.errorOld(ctx, err) } - account, err = api.account.Insert(ctx.Request().Context(), &models.Account{ + account, err = api.account.Insert(ctx.Context(), &models.Account{ UserID: user.ID, Wallet: models.Wallet{Currency: defaultCurrency}, From: quizFrom, Partner: quizUser}) if err != nil { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, account) + return ctx.Status(fiber.StatusOK).JSON(account) } -func (api *API2) DeleteDirectAccount(ctx echo.Context, userID string) error { - account, err := api.account.Remove(ctx.Request().Context(), userID) +func (api *API2) DeleteDirectAccount(ctx *fiber.Ctx) error { + userID := ctx.Params("userId") + if userID == "" { + return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") + } + + account, err := api.account.Remove(ctx.Context(), userID) if err != nil { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, account) + return ctx.Status(fiber.StatusOK).JSON(account) } -func (api *API2) GetDirectAccount(ctx echo.Context, userID string) error { - account, err := api.account.FindByUserID(ctx.Request().Context(), userID) +func (api *API2) GetDirectAccount(ctx *fiber.Ctx) error { + userID := ctx.Params("userId") + if userID == "" { + return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") + } + + account, err := api.account.FindByUserID(ctx.Context(), userID) if err != nil { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, account) + return ctx.Status(fiber.StatusOK).JSON(account) } -func (api *API2) PaginationAccounts(ctx echo.Context, params PaginationAccountsParams) error { - if params.Page == nil || params.Limit == nil { - return api.error(ctx, http.StatusInternalServerError, "default values missing for PaginationAccounts") +func (api *API2) PaginationAccounts(ctx *fiber.Ctx) error { + pageStr := ctx.Query("page", "1") + limitStr := ctx.Query("limit", "100") + + page, err := strconv.ParseInt(pageStr, 10, 64) + if err != nil || page < 1 { + page = 1 + } + limit, err := strconv.ParseInt(limitStr, 10, 64) + if err != nil || limit < 1 { + limit = models.DefaultLimit + } else { + limit = int64(math.Min(float64(limit), float64(models.DefaultLimit))) } - page := int64(math.Max(float64(*params.Page), 1)) - limit := int64(math.Max(float64(*params.Limit), 1)) - limit = int64(math.Min(float64(limit), float64(models.DefaultLimit))) - - count, err := api.account.CountAll(ctx.Request().Context()) + count, err := api.account.CountAll(ctx.Context()) if err != nil { return api.errorOld(ctx, err) } if count == 0 { response := models.PaginationResponse[models.Account]{TotalPages: 0, Records: []models.Account{}} - return ctx.JSON(http.StatusOK, response) + return ctx.Status(fiber.StatusOK).JSON(response) } totalPages := int64(math.Ceil(float64(count) / float64(limit))) - accounts, err := api.account.FindMany(ctx.Request().Context(), page, limit) + accounts, err := api.account.FindMany(ctx.Context(), page, limit) if err != nil { return api.errorOld(ctx, err) } @@ -274,82 +291,82 @@ func (api *API2) PaginationAccounts(ctx echo.Context, params PaginationAccountsP Records: accounts, } - return ctx.JSON(http.StatusOK, response) + return ctx.Status(fiber.StatusOK).JSON(response) } // Cart -func (api *API2) RemoveFromCart(ctx echo.Context, params RemoveFromCartParams) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) RemoveFromCart(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - if validate.IsStringEmpty(params.Id) { - return api.error(ctx, http.StatusBadRequest, "empty item id") + id := ctx.Query("id") + if id == "" { + return api.error(ctx, fiber.StatusBadRequest, "empty item id") } - cartItems, err := api.account.RemoveItemFromCart(ctx.Request().Context(), userID, params.Id) + cartItems, err := api.account.RemoveItemFromCart(ctx.Context(), userID, id) if err != nil { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, cartItems) + return ctx.Status(fiber.StatusOK).JSON(cartItems) } -func (api *API2) Add2cart(ctx echo.Context, params Add2cartParams) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) Add2cart(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - token, ok := ctx.Get(models.AuthJWTDecodedAccessTokenKey).(string) - if !ok { + token := ctx.Get(models.AuthJWTDecodedAccessTokenKey) + if token == "" { return api.noauth(ctx) } - if validate.IsStringEmpty(params.Id) { - return api.error(ctx, http.StatusBadRequest, "empty item id") + tariffID := ctx.Query("id") + if tariffID == "" { + return api.error(ctx, fiber.StatusBadRequest, "empty item id") } - tariffID := params.Id - - tariff, err := api.clients.hubadmin.GetTariff(ctx.Request().Context(), token, tariffID) + tariff, err := api.clients.hubadmin.GetTariff(ctx.Context(), token, tariffID) if err != nil { return api.errorOld(ctx, err) } if tariff == nil { - return api.error(ctx, http.StatusNotFound, "tariff not found") + return api.error(ctx, fiber.StatusNotFound, "tariff not found") } - cartItems, err := api.account.AddItemToCart(ctx.Request().Context(), userID, tariffID) + cartItems, err := api.account.AddItemToCart(ctx.Context(), userID, tariffID) if err != nil { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, cartItems) + return ctx.Status(fiber.StatusOK).JSON(cartItems) } -func (api *API2) PayCart(ctx echo.Context) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) PayCart(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - accessToken, ok := ctx.Get(models.AuthJWTDecodedAccessTokenKey).(string) - if !ok { + accessToken := ctx.Get(models.AuthJWTDecodedAccessTokenKey) + if accessToken == "" { return api.noauth(ctx) } - account, err := api.account.FindByUserID(ctx.Request().Context(), userID) + account, err := api.account.FindByUserID(ctx.Context(), userID) if err != nil { return api.errorOld(ctx, err) } api.logger.Info("account for pay", zap.Any("acc", account)) - tariffs, err := api.clients.hubadmin.GetTariffs(ctx.Request().Context(), accessToken, account.Cart) + tariffs, err := api.clients.hubadmin.GetTariffs(ctx.Context(), accessToken, account.Cart) if err != nil { return api.errorOld(ctx, err) } @@ -358,7 +375,7 @@ func (api *API2) PayCart(ctx echo.Context) error { tariffsAmount := utils.CalculateCartPurchasesAmount(tariffs) - discountResponse, err := api.clients.discount.Apply(ctx.Request().Context(), &discount.ApplyDiscountRequest{ + discountResponse, err := api.clients.discount.Apply(ctx.Context(), &discount.ApplyDiscountRequest{ UserInformation: &discount.UserInformation{ ID: account.UserID, Type: string(account.Status), @@ -384,17 +401,17 @@ func (api *API2) PayCart(ctx echo.Context) error { })) if account.Wallet.Money < int64(discountResponse.Price) { - return api.error(ctx, http.StatusPaymentRequired, "insufficient funds: %d", int64(discountResponse.Price)-account.Wallet.Money) + return api.error(ctx, fiber.StatusPaymentRequired, "insufficient funds: %d", int64(discountResponse.Price)-account.Wallet.Money) } for _, applied := range discountResponse.AppliedDiscounts { if applied.Condition.User != nil && *applied.Condition.User != "" { - _, err := api.clients.discount.DeleteDiscount(ctx.Request().Context(), &discount.GetDiscountByIDRequest{ + _, err := api.clients.discount.DeleteDiscount(ctx.Context(), &discount.GetDiscountByIDRequest{ ID: applied.ID, }) if err != nil { - return api.error(ctx, http.StatusInternalServerError, "failed delete discount by id:%s", applied.ID) + return api.error(ctx, fiber.StatusInternalServerError, "failed delete discount by id:%s", applied.ID) } } } @@ -413,7 +430,7 @@ func (api *API2) PayCart(ctx echo.Context) error { var updatedAccount *models.Account if request.Account.Wallet.Currency == models.InternalCurrencyKey { - accountx, err := api.account.ChangeWallet(ctx.Request().Context(), request.Account.UserID, &models.Wallet{ + accountx, err := api.account.ChangeWallet(ctx.Context(), request.Account.UserID, &models.Wallet{ Cash: request.Account.Wallet.Cash - request.Money, Money: request.Account.Wallet.Money - request.Money, Spent: request.Account.Wallet.Spent + request.Money, @@ -425,7 +442,7 @@ func (api *API2) PayCart(ctx echo.Context) error { } updatedAccount = accountx } else { - cash, err := api.clients.currency.Translate(ctx.Request().Context(), &models.TranslateCurrency{ + cash, err := api.clients.currency.Translate(ctx.Context(), &models.TranslateCurrency{ Money: request.Money, From: models.InternalCurrencyKey, To: request.Account.Wallet.Currency, @@ -434,7 +451,7 @@ func (api *API2) PayCart(ctx echo.Context) error { return api.errorOld(ctx, err) } - accountx, err := api.account.ChangeWallet(ctx.Request().Context(), request.Account.UserID, &models.Wallet{ + accountx, err := api.account.ChangeWallet(ctx.Context(), request.Account.UserID, &models.Wallet{ Cash: request.Account.Wallet.Cash - cash, Money: request.Account.Wallet.Money - request.Money, Spent: request.Account.Wallet.Spent + request.Money, @@ -448,7 +465,7 @@ func (api *API2) PayCart(ctx echo.Context) error { updatedAccount = accountx } - if _, err := api.history.Insert(ctx.Request().Context(), &models.History{ + if _, err := api.history.Insert(ctx.Context(), &models.History{ Key: models.CustomerHistoryKeyPayCart, UserID: account.UserID, Comment: "Успешная оплата корзины", @@ -472,7 +489,7 @@ func (api *API2) PayCart(ctx echo.Context) error { go func(currentTariff models.Tariff) { defer waitGroup.Done() - if err := api.producer.Send(ctx.Request().Context(), userID, ¤tTariff); err != nil { + if err := api.producer.Send(ctx.Context(), userID, ¤tTariff); err != nil { mutex.Lock() defer mutex.Unlock() sendErrors = append(sendErrors, err) @@ -486,42 +503,44 @@ func (api *API2) PayCart(ctx echo.Context) error { for _, err := range sendErrors { api.logger.Error("failed to send tariffs to broker on of ", zap.Error(err)) } - return api.error(ctx, http.StatusInternalServerError, "failed to send tariffs to broker") + return api.error(ctx, fiber.StatusInternalServerError, "failed to send tariffs to broker") } - if _, err := api.account.ClearCart(ctx.Request().Context(), account.UserID); err != nil { + if _, err := api.account.ClearCart(ctx.Context(), account.UserID); err != nil { return api.errorOld(ctx, err) } updatedAccount.Cart = []string{} - return ctx.JSON(http.StatusOK, updatedAccount) + return ctx.Status(fiber.StatusOK).JSON(updatedAccount) } // Currency -func (api *API2) GetCurrencies(ctx echo.Context) error { - currencyList, err := api.currency.FindCurrenciesList(ctx.Request().Context(), models.DefaultCurrencyListName) +func (api *API2) GetCurrencies(ctx *fiber.Ctx) error { + currencyList, err := api.currency.FindCurrenciesList(ctx.Context(), models.DefaultCurrencyListName) if err != nil && err.Type() != errors.ErrNotFound { return api.errorOld(ctx, err) } if err != nil && err.Type() == errors.ErrNotFound { - return ctx.JSON(http.StatusOK, []string{}) + return ctx.Status(fiber.StatusOK).JSON([]string{}) } - return ctx.JSON(http.StatusOK, currencyList) + return ctx.Status(fiber.StatusOK).JSON(currencyList) } -func (api *API2) UpdateCurrencies(ctx echo.Context) error { - currenciesPtr, bindErr := echotools.Bind[[]string](ctx) - if bindErr != nil { - return api.error(ctx, http.StatusBadRequest, "faild to bind currencies") +func (api *API2) UpdateCurrencies(ctx *fiber.Ctx) error { + var req struct { + items []string + } + if err := ctx.BodyParser(&req); err != nil { + return api.error(ctx, fiber.StatusBadRequest, "failed to bind currencies") } - currencies := *currenciesPtr + currencies := req.items - currencyList, err := api.currency.ReplaceCurrencies(ctx.Request().Context(), &models.CurrencyList{ + currencyList, err := api.currency.ReplaceCurrencies(ctx.Context(), &models.CurrencyList{ Name: models.DefaultCurrencyListName, Currencies: currencies, }) @@ -530,52 +549,67 @@ func (api *API2) UpdateCurrencies(ctx echo.Context) error { } if err != nil && err.Type() == errors.ErrNotFound { - newCurrencyList, err := api.currency.Insert(ctx.Request().Context(), &models.CurrencyList{ + newCurrencyList, err := api.currency.Insert(ctx.Context(), &models.CurrencyList{ Name: models.DefaultCurrencyListName, Currencies: currencies, }) if err != nil && err.Type() != errors.ErrNotFound { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, newCurrencyList.Currencies) + return ctx.Status(fiber.StatusOK).JSON(newCurrencyList.Currencies) } - return ctx.JSON(http.StatusOK, currencyList.Currencies) + return ctx.Status(fiber.StatusOK).JSON(currencyList.Currencies) } // History -func (api *API2) GetHistory(ctx echo.Context, params GetHistoryParams) error { +func (api *API2) GetHistory(ctx *fiber.Ctx) error { var userID string - if params.AccountID != nil && *params.AccountID != "" { - userID = *params.AccountID + pageStr := ctx.Query("page") + limitStr := ctx.Query("limit") + tipe := ctx.Query("type") + accountID := ctx.Query("accountID") + + if accountID != "" { + userID = accountID } else { - userID, _ = ctx.Get(models.AuthJWTDecodedUserIDKey).(string) + userID = ctx.Get(models.AuthJWTDecodedUserIDKey) + } + + limit, err := strconv.ParseInt(limitStr, 10, 64) + if err != nil { + return api.error(ctx, fiber.StatusBadRequest, "invalid limit format") + } + + page, err := strconv.ParseInt(pageStr, 10, 64) + if err != nil { + return api.error(ctx, fiber.StatusBadRequest, "invalid page format") } dto := &history.GetHistories{ UserID: userID, - Type: params.Type, + Type: &tipe, Pagination: &models.Pagination{ - Page: int64(*params.Page), - Limit: int64(*params.Limit), + Page: page, + Limit: limit, }, } - count, err := api.history.CountAll(ctx.Request().Context(), dto) + count, err := api.history.CountAll(ctx.Context(), dto) if err != nil { return api.errorOld(ctx, err) } if count == 0 { returnHistories := models.PaginationResponse[models.History]{TotalPages: 0, Records: []models.History{}} - return ctx.JSON(http.StatusOK, returnHistories) + return ctx.Status(fiber.StatusOK).JSON(returnHistories) } totalPages := int64(math.Ceil(float64(count) / float64(dto.Pagination.Limit))) - histories, err := api.history.FindMany(ctx.Request().Context(), dto) + histories, err := api.history.FindMany(ctx.Context(), dto) if err != nil { return api.errorOld(ctx, err) } @@ -585,60 +619,60 @@ func (api *API2) GetHistory(ctx echo.Context, params GetHistoryParams) error { Records: histories, } - return ctx.JSON(http.StatusOK, returnHistories) + return ctx.Status(fiber.StatusOK).JSON(returnHistories) } // Wallet -func (api *API2) RequestMoney(ctx echo.Context) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) RequestMoney(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - request, bindErr := echotools.Bind[models.GetPaymentLinkBody](ctx) - if bindErr != nil { - return api.error(ctx, http.StatusBadRequest, "faild to bind payment link") + var request models.GetPaymentLinkBody + if err := ctx.BodyParser(&request); err != nil { + return api.error(ctx, fiber.StatusBadRequest, "failed to bind payment link") } - if err := utils.ValidateGetPaymentLinkBody(request); err != nil { + if err := utils.ValidateGetPaymentLinkBody(&request); err != nil { return api.errorOld(ctx, err) } - link, err := api.GetPaymentLink(ctx.Request().Context(), &models.GetPaymentLinkRequest{ - Body: request, + link, err := api.GetPaymentLink(ctx.Context(), &models.GetPaymentLinkRequest{ + Body: &request, UserID: userID, - ClientIP: ctx.RealIP(), + ClientIP: ctx.IP(), }) if err != nil { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, &models.GetPaymentLinkResponse{Link: link}) + return ctx.Status(fiber.StatusOK).JSON(&models.GetPaymentLinkResponse{Link: link}) } -func (api *API2) ChangeCurrency(ctx echo.Context) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) ChangeCurrency(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - request, bindErr := echotools.Bind[models.ChangeCurrency](ctx) - if bindErr != nil { - return api.error(ctx, http.StatusBadRequest, "faild to bind currency") + var request models.ChangeCurrency + if err := ctx.BodyParser(&request); err != nil { + return api.error(ctx, fiber.StatusBadRequest, "failed to bind currency") } if validate.IsStringEmpty(request.Currency) { - return api.error(ctx, http.StatusBadRequest, "empty currency") + return api.error(ctx, fiber.StatusBadRequest, "empty currency") } currency := request.Currency - account, err := api.account.FindByUserID(ctx.Request().Context(), userID) + account, err := api.account.FindByUserID(ctx.Context(), userID) if err != nil { return api.errorOld(ctx, err) } - cash, err := api.clients.currency.Translate(ctx.Request().Context(), &models.TranslateCurrency{ + cash, err := api.clients.currency.Translate(ctx.Context(), &models.TranslateCurrency{ Money: account.Wallet.Cash, From: account.Wallet.Currency, To: currency, @@ -647,7 +681,7 @@ func (api *API2) ChangeCurrency(ctx echo.Context) error { return api.errorOld(ctx, err) } - updatedAccount, err := api.account.ChangeWallet(ctx.Request().Context(), account.UserID, &models.Wallet{ + updatedAccount, err := api.account.ChangeWallet(ctx.Context(), account.UserID, &models.Wallet{ Cash: cash, Currency: currency, Money: account.Wallet.Money, @@ -656,23 +690,26 @@ func (api *API2) ChangeCurrency(ctx echo.Context) error { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, updatedAccount) + return ctx.Status(fiber.StatusOK).JSON(updatedAccount) } -func (api *API2) CalculateLTV(ctx echo.Context) error { - var req CalculateLTVJSONBody +func (api *API2) CalculateLTV(ctx *fiber.Ctx) error { + var req struct { + From int64 `json:"from"` + To int64 `json:"to"` + } - if err := ctx.Bind(&req); err != nil { + if err := ctx.BodyParser(&req); err != nil { api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, http.StatusBadRequest, "failed to bind request") + return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") } if req.From > req.To && req.To != 0 { api.logger.Error("From timestamp must be less than To timestamp unless To is 0") - return api.error(ctx, http.StatusBadRequest, "From timestamp must be less than To timestamp unless To is 0") + return api.error(ctx, fiber.StatusBadRequest, "From timestamp must be less than To timestamp unless To is 0") } - ltv, err := api.history.CalculateCustomerLTV(ctx.Request().Context(), req.From, req.To) + ltv, err := api.history.CalculateCustomerLTV(ctx.Context(), req.From, req.To) if err != nil { api.logger.Error("failed to calculate LTV", zap.Error(err)) return api.errorOld(ctx, err) @@ -684,22 +721,16 @@ func (api *API2) CalculateLTV(ctx echo.Context) error { LTV: ltv, } - return ctx.JSON(http.StatusOK, response) + return ctx.Status(fiber.StatusOK).JSON(response) } -func (api *API2) GetRecentTariffs(ctx echo.Context) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { - api.logger.Error("failed to convert jwt payload to string on of ") - return api.error(ctx, http.StatusBadRequest, "failed to convert jwt payload to string") - } - +func (api *API2) GetRecentTariffs(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) if userID == "" { - api.logger.Error("user id is missing in of ") - return api.error(ctx, http.StatusBadRequest, "user id is missing") + return api.noauth(ctx) } - tariffs, err := api.history.GetRecentTariffs(ctx.Request().Context(), userID) + tariffs, err := api.history.GetRecentTariffs(ctx.Context(), userID) if err != nil { api.logger.Error("failed to get recent tariffs on of ", zap.String("userId", userID), @@ -708,22 +739,24 @@ func (api *API2) GetRecentTariffs(ctx echo.Context) error { return api.errorOld(ctx, err) } - return ctx.JSON(http.StatusOK, tariffs) + return ctx.Status(fiber.StatusOK).JSON(tariffs) } -func (api *API2) SendReport(ctx echo.Context) error { - var req SendReportJSONBody - if err := ctx.Bind(&req); err != nil { +func (api *API2) SendReport(ctx *fiber.Ctx) error { + var req struct { + Id string `json:"id"` + } + if err := ctx.BodyParser(&req); err != nil { api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, http.StatusBadRequest, "failed to bind request") + return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") } if req.Id == "" { api.logger.Error("history id is missing in of ") - return api.error(ctx, http.StatusBadRequest, "history id is missing") + return api.error(ctx, fiber.StatusBadRequest, "history id is missing") } - tariffs, err := api.history.GetHistoryByID(ctx.Request().Context(), req.Id) + tariffs, err := api.history.GetHistoryByID(ctx.Context(), req.Id) if err != nil { api.logger.Error( "failed to get history by id in of ", @@ -739,10 +772,10 @@ func (api *API2) SendReport(ctx echo.Context) error { zap.String("historyID", req.Id), zap.Error(err), ) - return api.error(ctx, http.StatusBadRequest, "invalid history record key") + return api.error(ctx, fiber.StatusBadRequest, "invalid history record key") } - historyMap, err := api.history.GetDocNumber(ctx.Request().Context(), tariffs.UserID) + historyMap, err := api.history.GetDocNumber(ctx.Context(), tariffs.UserID) if err != nil { api.logger.Error( "failed to get history of sorting by date created in of ", @@ -751,10 +784,10 @@ func (api *API2) SendReport(ctx echo.Context) error { ) return api.errorOld(ctx, err) } - token := ctx.Request().Header.Get("Authorization") + token := ctx.Get("Authorization") fmt.Println("HEADERS", ctx.Request().Header) - verifuser, err := api.clients.verify.GetVerification(ctx.Request().Context(), token, tariffs.UserID) + verifuser, err := api.clients.verify.GetVerification(ctx.Context(), token, tariffs.UserID) if err != nil { api.logger.Error("failed to get user verification on of ", zap.Error(err), @@ -768,15 +801,14 @@ func (api *API2) SendReport(ctx echo.Context) error { zap.String("userID", tariffs.UserID), zap.Error(err), ) - return api.error(ctx, http.StatusBadRequest, "verification not accepted") + return api.error(ctx, fiber.StatusBadRequest, "verification not accepted") } - account, err := api.account.FindByUserID(ctx.Request().Context(), tariffs.UserID) + account, err := api.account.FindByUserID(ctx.Context(), tariffs.UserID) if err != nil { return api.errorOld(ctx, err) } - - authuser, err := api.clients.auth.GetUser(ctx.Request().Context(), tariffs.UserID) + authuser, err := api.clients.auth.GetUser(ctx.Context(), tariffs.UserID) if err != nil { api.logger.Error("failed to get user on of ", zap.Error(err), @@ -787,7 +819,7 @@ func (api *API2) SendReport(ctx echo.Context) error { fileContents, readerr := os.ReadFile("./report.docx") if readerr != nil { - return api.error(ctx, http.StatusInternalServerError, "failed to read file") + return api.error(ctx, fiber.StatusInternalServerError, "failed to read file") } if account.Name.Orgname == "" { @@ -802,7 +834,7 @@ func (api *API2) SendReport(ctx echo.Context) error { for _, privilege := range tariff.Privileges { totalAmount += privilege.Amount privilegeMeasurement = string(privilege.Type) - piecePrice = fmt.Sprintf("%.2f",float64(privilege.Price)/100) + piecePrice = fmt.Sprintf("%.2f", float64(privilege.Price)/100) privilegeName = privilege.Name } data := models.RespGeneratorService{ @@ -812,11 +844,11 @@ func (api *API2) SendReport(ctx echo.Context) error { OrgName: account.Name.Orgname, Name: tariff.Name + " " + privilegeName, Amount: fmt.Sprint(totalAmount), - Unit: piecePrice, - Price: fmt.Sprintf("%.2f",float64(tariffs.RawDetails.Price)/100), + Unit: piecePrice, + Price: fmt.Sprintf("%.2f", float64(tariffs.RawDetails.Price)/100), Sum: privilegeMeasurement, } - err = api.clients.template.SendData(ctx.Request().Context(), data, fileContents, authuser.Login) + err = api.clients.template.SendData(ctx.Context(), data, fileContents, authuser.Login) if err != nil { api.logger.Error("failed to send report to user on of ", zap.Error(err), @@ -826,43 +858,46 @@ func (api *API2) SendReport(ctx echo.Context) error { } } - return ctx.NoContent(http.StatusOK) + return ctx.SendStatus(fiber.StatusOK) } -func (api *API2) PostWalletRspay(ctx echo.Context) error { - userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string) - if !ok { +func (api *API2) PostWalletRspay(ctx *fiber.Ctx) error { + userID := ctx.Get(models.AuthJWTDecodedUserIDKey) + if userID == "" { return api.noauth(ctx) } - var req PostWalletRspayJSONBody - if err := ctx.Bind(&req); err != nil { - api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, http.StatusBadRequest, "failed to bind request") + var req struct { + Money *float32 `json:"money,omitempty"` } - user, err := api.account.FindByUserID(ctx.Request().Context(), userID) + if err := ctx.BodyParser(&req); err != nil { + api.logger.Error("failed to bind request", zap.Error(err)) + return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") + } + + user, err := api.account.FindByUserID(ctx.Context(), userID) if err != nil { return api.errorOld(ctx, err) } if user.Status != models.AccountStatusNko && user.Status != models.AccountStatusOrg { - return api.error(ctx, http.StatusForbidden, "not allowed for non organizations") + return api.error(ctx, fiber.StatusForbidden, "not allowed for non organizations") } - token := ctx.Request().Header.Get("Authorization") + token := ctx.Get("Authorization") fmt.Println("HEADERS", ctx.Request().Header) - verification, err := api.clients.verify.GetVerification(ctx.Request().Context(), token, userID) + verification, err := api.clients.verify.GetVerification(ctx.Context(), token, userID) if err == errors.ErrNotFound { - return api.error(ctx, http.StatusForbidden, "no verification data found") + return api.error(ctx, fiber.StatusForbidden, "no verification data found") } if (user.Status == models.AccountStatusOrg && len(verification.Files) != 3) || (user.Status == models.AccountStatusNko && len(verification.Files) != 4) { - return api.error(ctx, http.StatusForbidden, "not enough verification files") + return api.error(ctx, fiber.StatusForbidden, "not enough verification files") } - authData, err := api.clients.auth.GetUser(ctx.Request().Context(), userID) + authData, err := api.clients.auth.GetUser(ctx.Context(), userID) if err != nil { return api.errorOld(ctx, err) } @@ -872,7 +907,7 @@ func (api *API2) PostWalletRspay(ctx echo.Context) error { return api.errorOld(ctx, err) } - return ctx.NoContent(http.StatusOK) + return ctx.SendStatus(fiber.StatusOK) } type QuizLogoStat2 struct { @@ -886,49 +921,59 @@ type Item struct { Regs int `json:"regs,omitempty"` } -func (api *API2) QuizLogoStat(ctx echo.Context) error { - var req QuizLogoStatJSONRequestBody - if err := ctx.Bind(&req); err != nil { - api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, http.StatusBadRequest, "failed to bind request") +func (api *API2) QuizLogoStat(ctx *fiber.Ctx) error { + var req struct { + From *int `json:"from,omitempty"` + Limit *int `json:"limit,omitempty"` + Page *int `json:"page,omitempty"` + To *int `json:"to,omitempty"` } - result, err := api.account.QuizLogoStat(ctx.Request().Context(), repository.QuizLogoStatDeps{ + if err := ctx.BodyParser(&req); err != nil { + api.logger.Error("failed to bind request", zap.Error(err)) + return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") + } + + result, err := api.account.QuizLogoStat(ctx.Context(), repository.QuizLogoStatDeps{ Page: req.Page, Limit: req.Limit, From: req.From, To: req.To, }) if err != nil { - return api.error(ctx, http.StatusInternalServerError, fmt.Sprint("failed getting quiz logo stat", err.Error())) + return api.error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting quiz logo stat", err.Error())) } - return ctx.JSON(http.StatusOK, result) + return ctx.Status(fiber.StatusOK).JSON(result) } -func (api *API2) PromocodeLTV(ctx echo.Context) error { - var req PromocodeLTVJSONRequestBody - if err := ctx.Bind(&req); err != nil { +func (api *API2) PromocodeLTV(ctx *fiber.Ctx) error { + var req struct { + From int `json:"from"` + To int `json:"to"` + } + + if err := ctx.BodyParser(&req); err != nil { api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, http.StatusBadRequest, "failed to bind request") + return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") } // получаем мапу вида [promoID] = []{userid,timeActivate} // отдаются только первые использованые на аккаунте промокоды, соответсвенно подсчет идет сугубо по ним // если в запросе время различается с временем активации - если меньше, то учитывается только после применения // если больше, то учитывается только с начала переданного from - codewordData, err := api.clients.codeword.GetAllPromoActivations(ctx.Request().Context(), &codeword_rpc.Time{ + codewordData, err := api.clients.codeword.GetAllPromoActivations(ctx.Context(), &codeword_rpc.Time{ To: int64(req.To), From: int64(req.From), }) if err != nil { - return api.error(ctx, http.StatusInternalServerError, fmt.Sprint("failed getting codeword data", err.Error())) + return api.error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting codeword data", err.Error())) } - userSumMap, er := api.history.GetPayUsersPromoHistory(ctx.Request().Context(), codewordData, int64(req.From), int64(req.To)) + userSumMap, er := api.history.GetPayUsersPromoHistory(ctx.Context(), codewordData, int64(req.From), int64(req.To)) if er != nil { - return api.error(ctx, http.StatusInternalServerError, fmt.Sprint("failed clculate promo users paid sum", er.Error())) + return api.error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed calculate promo users paid sum", er.Error())) } resp := make(map[string]struct { @@ -937,14 +982,14 @@ func (api *API2) PromocodeLTV(ctx echo.Context) error { }) for promoID, data := range codewordData { - fmt.Println("PROTOMOTO", promoID,data) + fmt.Println("PROTOMOTO", promoID, data) for _, value := range data { paids, ok := userSumMap[value.UserID] if !ok { paids = 0 } - fmt.Println("PROTOMOTO1", paids, value) + fmt.Println("PROTOMOTO1", paids, value) if value.Time >= int64(req.From) && value.Time <= int64(req.To) { if _, ok := resp[promoID]; !ok { @@ -962,5 +1007,5 @@ func (api *API2) PromocodeLTV(ctx echo.Context) error { } } - return ctx.JSON(http.StatusOK, resp) + return ctx.Status(fiber.StatusOK).JSON(resp) } diff --git a/internal/interface/swagger/models.gen.go b/internal/interface/swagger/models.gen.go deleted file mode 100644 index 11218aa..0000000 --- a/internal/interface/swagger/models.gen.go +++ /dev/null @@ -1,299 +0,0 @@ -// Package swagger provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT. -package swagger - -import ( - "time" -) - -const ( - BearerScopes = "Bearer.Scopes" -) - -// Defines values for AccountStatus. -const ( - Nko AccountStatus = "nko" - No AccountStatus = "no" - Org AccountStatus = "org" -) - -// Defines values for PaymentType. -const ( - PaymentTypeAlfabank PaymentType = "alfabank" - PaymentTypeB2bSberbank PaymentType = "b2bSberbank" - PaymentTypeBankCard PaymentType = "bankCard" - PaymentTypeCash PaymentType = "cash" - PaymentTypeInstallments PaymentType = "installments" - PaymentTypeMobile PaymentType = "mobile" - PaymentTypeQiwi PaymentType = "qiwi" - PaymentTypeSberbank PaymentType = "sberbank" - PaymentTypeSbp PaymentType = "sbp" - PaymentTypeTinkoffBank PaymentType = "tinkoffBank" - PaymentTypeYoomoney PaymentType = "yoomoney" -) - -// Account defines model for Account. -type Account struct { - Id string `json:"_id"` - Cart []string `json:"cart"` - CreatedAt time.Time `json:"createdAt"` - DeletedAt *time.Time `json:"deletedAt,omitempty"` - IsDeleted *bool `json:"isDeleted,omitempty"` - Name Name `json:"name"` - Status AccountStatus `json:"status"` - UpdatedAt time.Time `json:"updatedAt"` - UserId string `json:"userId"` - Wallet Wallet `json:"wallet"` -} - -// AccountStatus defines model for AccountStatus. -type AccountStatus string - -// BankCard defines model for BankCard. -type BankCard struct { - // Cardholder Имя владельца карты - Cardholder *string `json:"cardholder,omitempty"` - - // Csc Код CVC2 или CVV2, 3 или 4 символа, печатается на обратной стороне карты - Csc *string `json:"csc,omitempty"` - - // ExpiryMonth Месяц истечения срока карты (MM) - ExpiryMonth string `json:"expiryMonth"` - - // ExpiryYear Год истечения срока карты (YYYY) - ExpiryYear string `json:"expiryYear"` - - // Number Номер карты - Number string `json:"number"` -} - -// Error defines model for Error. -type Error struct { - Message string `json:"message"` - StatusCode *int64 `json:"statusCode,omitempty"` -} - -// History defines model for History. -type History struct { - Comment string `json:"comment"` - CreatedAt time.Time `json:"createdAt"` - DeletedAt *time.Time `json:"deletedAt,omitempty"` - Id string `json:"id"` - IsDeleted *bool `json:"isDeleted,omitempty"` - - // RawDetails Я пока не могу предположить, какие будут фильтры по истории, поэтому предлагаю в это поле просто класть строку с json. Ибо для каждого типа записи она своя. - RawDetails *string `json:"rawDetails,omitempty"` - Type string `json:"type"` - UpdatedAt time.Time `json:"updatedAt"` - UserId string `json:"userId"` -} - -// Name defines model for Name. -type Name struct { - Firstname *string `json:"firstname,omitempty"` - Middlename *string `json:"middlename,omitempty"` - Orgname *string `json:"orgname,omitempty"` - Secondname *string `json:"secondname,omitempty"` -} - -// PaymentType defines model for PaymentType. -type PaymentType string - -// PromoLtvStat defines model for PromoLtvStat. -type PromoLtvStat struct { - // Stats мапа ключ id промо, знчение количество регистраций и количество денег - Stats *map[string]struct { - // Money количество денег - Money *int `json:"money,omitempty"` - - // Regs количество регистраций - Regs *int `json:"regs,omitempty"` - } `json:"stats,omitempty"` -} - -// QuizLogoStat defines model for QuizLogoStat. -type QuizLogoStat = []struct { - // Id user id - Id *string `json:"id,omitempty"` - - // Money Количество денег - Money *int `json:"money,omitempty"` - Quizes *[]struct { - // Money Количество денег - Money *int `json:"money,omitempty"` - - // Quiz qid quiz - Quiz *string `json:"quiz,omitempty"` - - // Regs Количество регистраций - Regs *int `json:"regs,omitempty"` - } `json:"quizes,omitempty"` - - // Regs Количество регистраций - Regs *int `json:"regs,omitempty"` -} - -// TariffID defines model for TariffID. -type TariffID struct { - ID *string `json:"ID,omitempty"` -} - -// Wallet defines model for Wallet. -type Wallet struct { - // Cash Сумма money переведённая на текущий курс - Cash int64 `json:"cash"` - - // Currency Текущий курс валюты - Currency string `json:"currency"` - - // Money Деньги на счету в копейках. Чтобы при перессчётах не возникало денег изниоткуда. фиксируемся к одной валюте, она будет внутренней, никому её не покажем - Money int64 `json:"money"` - - // PurchasesAmount Общая сумма денег, которые внёс пользователь - PurchasesAmount int64 `json:"purchasesAmount"` - - // Spent Общая сумма потраченных денег за всё время существования аккаунта - Spent int64 `json:"spent"` -} - -// SetAccountVerificationStatusJSONBody defines parameters for SetAccountVerificationStatus. -type SetAccountVerificationStatusJSONBody struct { - Status *AccountStatus `json:"status,omitempty"` -} - -// PaginationAccountsParams defines parameters for PaginationAccounts. -type PaginationAccountsParams struct { - // Page Номер страницы, начиная с 1 - Page *int `form:"page,omitempty" json:"page,omitempty"` - - // Limit размер страницы - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` -} - -// RemoveFromCartParams defines parameters for RemoveFromCart. -type RemoveFromCartParams struct { - Id string `form:"id" json:"id"` -} - -// Add2cartParams defines parameters for Add2cart. -type Add2cartParams struct { - Id string `form:"id" json:"id"` -} - -// UpdateCurrenciesJSONBody defines parameters for UpdateCurrencies. -type UpdateCurrenciesJSONBody = []string - -// GetHistoryParams defines parameters for GetHistory. -type GetHistoryParams struct { - // Page Номер страницы, начиная с 1 - Page *int `form:"page,omitempty" json:"page,omitempty"` - - // Limit Размер страницы - Limit *int `form:"limit,omitempty" json:"limit,omitempty"` - - // Type Тип события - Type *string `form:"type,omitempty" json:"type,omitempty"` - - // AccountID Идентификатор аккаунта. Если не указан, будет использоваться идентификатор из токена. - AccountID *string `form:"accountID,omitempty" json:"accountID,omitempty"` -} - -// CalculateLTVJSONBody defines parameters for CalculateLTV. -type CalculateLTVJSONBody struct { - // From Начальная дата в формате Unix timestamp. Если 0, устанавливает начало истории. - From int64 `json:"from"` - - // To Конечная дата в формате Unix timestamp. Если 0, устанавливает текущее время. - To int64 `json:"to"` -} - -// PromocodeLTVJSONBody defines parameters for PromocodeLTV. -type PromocodeLTVJSONBody struct { - // From таймштамп времени, после которого выбирать статистику - From int `json:"from"` - - // To таймштамп времени, до которого выбирать статистику - To int `json:"to"` -} - -// QuizLogoStatJSONBody defines parameters for QuizLogoStat. -type QuizLogoStatJSONBody struct { - // From таймштамп времени, после которого выбирать статистику. если 0 или не передано - этого ограничения нет. нижняя граница времени - From *int `json:"from,omitempty"` - - // Limit лимит выборки - Limit *int `json:"limit,omitempty"` - - // Page страница выборки - Page *int `json:"page,omitempty"` - - // To таймштамп времени, до которого выбирать статистику. если 0 или не передано - этого ограничения нет. верхняя граница времени - To *int `json:"to,omitempty"` -} - -// GetRecentTariffsJSONBody defines parameters for GetRecentTariffs. -type GetRecentTariffsJSONBody struct { - Id string `json:"id"` -} - -// SendReportJSONBody defines parameters for SendReport. -type SendReportJSONBody struct { - Id string `json:"id"` -} - -// ChangeCurrencyJSONBody defines parameters for ChangeCurrency. -type ChangeCurrencyJSONBody struct { - Currency string `json:"currency"` -} - -// RequestMoneyJSONBody defines parameters for RequestMoney. -type RequestMoneyJSONBody struct { - Amount int `json:"amount"` - BankCard *BankCard `json:"bankCard,omitempty"` - - // Currency ISO-4217 формат - Currency string `json:"currency"` - Login *string `json:"login,omitempty"` - PhoneNumber *string `json:"phoneNumber,omitempty"` - ReturnUrl *string `json:"returnUrl,omitempty"` - Type PaymentType `json:"type"` -} - -// PostWalletRspayJSONBody defines parameters for PostWalletRspay. -type PostWalletRspayJSONBody struct { - Money *float32 `json:"money,omitempty"` -} - -// ChangeAccountJSONRequestBody defines body for ChangeAccount for application/json ContentType. -type ChangeAccountJSONRequestBody = Name - -// SetAccountVerificationStatusJSONRequestBody defines body for SetAccountVerificationStatus for application/json ContentType. -type SetAccountVerificationStatusJSONRequestBody SetAccountVerificationStatusJSONBody - -// UpdateCurrenciesJSONRequestBody defines body for UpdateCurrencies for application/json ContentType. -type UpdateCurrenciesJSONRequestBody = UpdateCurrenciesJSONBody - -// CalculateLTVJSONRequestBody defines body for CalculateLTV for application/json ContentType. -type CalculateLTVJSONRequestBody CalculateLTVJSONBody - -// PromocodeLTVJSONRequestBody defines body for PromocodeLTV for application/json ContentType. -type PromocodeLTVJSONRequestBody PromocodeLTVJSONBody - -// QuizLogoStatJSONRequestBody defines body for QuizLogoStat for application/json ContentType. -type QuizLogoStatJSONRequestBody QuizLogoStatJSONBody - -// GetRecentTariffsJSONRequestBody defines body for GetRecentTariffs for application/json ContentType. -type GetRecentTariffsJSONRequestBody GetRecentTariffsJSONBody - -// SendReportJSONRequestBody defines body for SendReport for application/json ContentType. -type SendReportJSONRequestBody SendReportJSONBody - -// ChangeCurrencyJSONRequestBody defines body for ChangeCurrency for application/json ContentType. -type ChangeCurrencyJSONRequestBody ChangeCurrencyJSONBody - -// RequestMoneyJSONRequestBody defines body for RequestMoney for application/json ContentType. -type RequestMoneyJSONRequestBody RequestMoneyJSONBody - -// PostWalletRspayJSONRequestBody defines body for PostWalletRspay for application/json ContentType. -type PostWalletRspayJSONRequestBody PostWalletRspayJSONBody From 15087a0f993574023ed9e1b177c50f89de1c031c Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 20 May 2024 15:32:59 +0300 Subject: [PATCH 2/8] update init rest api --- go.mod | 17 +- go.sum | 41 +- internal/app/app.go | 36 +- .../http/controllers.go} | 8 +- .../{swagger => controller/http}/money.go | 6 +- internal/interface/controller/http/route.go | 32 + internal/interface/swagger/api.gen.go | 631 ------------------ internal/interface/swagger/middleware.go | 20 - internal/server/http.go | 119 ++-- internal/utils/authenticator.go | 45 +- tests/e2e/calculateLTV_test.go | 11 +- tests/e2e/getAccount_test.go | 10 +- tests/integration/history_report_test.go | 3 +- tests/integration/logostat_test.go | 34 +- 14 files changed, 158 insertions(+), 855 deletions(-) rename internal/interface/{swagger/api.2.go => controller/http/controllers.go} (99%) rename internal/interface/{swagger => controller/http}/money.go (97%) create mode 100644 internal/interface/controller/http/route.go delete mode 100644 internal/interface/swagger/api.gen.go delete mode 100644 internal/interface/swagger/middleware.go diff --git a/go.mod b/go.mod index 3ddbfea..21f83d5 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,12 @@ module penahub.gitlab.yandexcloud.net/pena-services/customer go 1.22.0 require ( - github.com/deepmap/oapi-codegen v1.16.2 - github.com/getkin/kin-openapi v0.123.0 github.com/go-resty/resty/v2 v2.11.0 github.com/gofiber/fiber/v2 v2.52.1 github.com/golang-jwt/jwt/v5 v5.2.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/joho/godotenv v1.5.1 github.com/labstack/echo/v4 v4.11.4 - github.com/oapi-codegen/runtime v1.1.1 github.com/pioz/faker v1.7.3 github.com/sethvargo/go-envconfig v1.0.0 github.com/stretchr/testify v1.8.4 @@ -28,29 +25,21 @@ require ( require ( github.com/andybalholm/brotli v1.1.0 // indirect - github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-openapi/jsonpointer v0.20.2 // indirect - github.com/go-openapi/swag v0.22.9 // indirect - github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/mux v1.8.1 // indirect - github.com/invopop/yaml v0.2.0 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.17.7 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/labstack/gommon v0.4.2 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.15 // indirect - github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/montanaflynn/stats v0.7.1 // indirect - github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/tealeg/xlsx v1.0.5 // indirect github.com/twmb/franz-go/pkg/kmsg v1.7.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect @@ -67,8 +56,8 @@ require ( golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.5.0 // indirect google.golang.org/genproto v0.0.0-20240221002015-b0ce06bbee7c // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 4bbf46a..99fd635 100644 --- a/go.sum +++ b/go.sum @@ -1,43 +1,28 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= -github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/deepmap/oapi-codegen v1.16.2 h1:xGHx0dNqYfy9gE8a7AVgVM8Sd5oF9SEgePzP+UPAUXI= -github.com/deepmap/oapi-codegen v1.16.2/go.mod h1:rdYoEA2GE+riuZ91DvpmBX9hJbQpuY9wchXpfQ3n+ho= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/getkin/kin-openapi v0.123.0 h1:zIik0mRwFNLyvtXK274Q6ut+dPh6nlxBp0x7mNrPhs8= -github.com/getkin/kin-openapi v0.123.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= -github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= -github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= -github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8= github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= -github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gofiber/fiber/v2 v2.52.1 h1:1RoU2NS+b98o1L77sdl5mboGPiW+0Ypsi5oLmcYlgHI= github.com/gofiber/fiber/v2 v2.52.1/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= -github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -56,23 +41,17 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= -github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -83,8 +62,6 @@ github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zG github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -92,21 +69,14 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= -github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= -github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= -github.com/oapi-codegen/testutil v1.0.0 h1:1GI2IiMMLh2vDHr1OkNacaYU/VaApKdcmfgl4aeXAa8= -github.com/oapi-codegen/testutil v1.0.0/go.mod h1:ttCaYbHvJtHuiyeBF0tPIX+4uhEPTeizXKx28okijLw= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= -github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pioz/faker v1.7.3 h1:Tez8Emuq0UN+/d6mo3a9m/9ZZ/zdfJk0c5RtRatrceM= github.com/pioz/faker v1.7.3/go.mod h1:xSpay5w/oz1a6+ww0M3vfpe40pSIykeUPeWEc3TvVlc= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -114,12 +84,12 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/sethvargo/go-envconfig v1.0.0 h1:1C66wzy4QrROf5ew4KdVw942CQDa55qmlYmw9FZxZdU= github.com/sethvargo/go-envconfig v1.0.0/go.mod h1:Lzc75ghUn5ucmcRGIdGQ33DKJrcjk4kihFYgSTBmjIc= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -137,8 +107,6 @@ github.com/twmb/franz-go/pkg/kadm v1.11.0 h1:FfeWJ0qadntFpAcQt8JzNXW4dijjytZNLrz github.com/twmb/franz-go/pkg/kadm v1.11.0/go.mod h1:qrhkdH+SWS3ivmbqOgHbpgVHamhaKcjH0UM+uOp0M1A= github.com/twmb/franz-go/pkg/kmsg v1.7.0 h1:a457IbvezYfA5UkiBvyV3zj0Is3y1i8EJgqjJYoij2E= github.com/twmb/franz-go/pkg/kmsg v1.7.0/go.mod h1:se9Mjdt0Nwzc9lnjJ0HyDtLyBnaBDAd7pCje47OhSyw= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0= @@ -292,7 +260,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/app/app.go b/internal/app/app.go index cb665fd..ca27f53 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -6,19 +6,18 @@ import ( "fmt" "os/signal" "penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http" "syscall" "time" "github.com/twmb/franz-go/pkg/kgo" "go.uber.org/zap" + qutils "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/utils" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/initialize" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/server" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/closer" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/kafka" - qutils "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/utils" ) const ( @@ -102,37 +101,34 @@ func Run(config *models.Config, logger *zap.Logger) (appErr error) { Services: services, }) - openapi, err := swagger.GetSwagger() - if err != nil { - return fmt.Errorf("failed to loading openapi spec: %w", err) - } - encrypt := qutils.NewEncrypt(config.Service.PubKey, config.Service.PrivKey) - api := swagger.NewAPI2(logger, mongoDB, config, brokers.TariffConsumer, brokers.TariffProducer, encrypt) + api := http.NewAPI2(logger, mongoDB, config, brokers.TariffConsumer, brokers.TariffProducer, encrypt) - serverHTTP, httpErr := server.NewHTTP(server.DepsHTTP{ - Logger: logger, - Swagger: openapi, - AuthenticationFunc: utils.NewAuthenticator(utils.NewJWT(&config.Service.JWT)), + serverHTTP := server.NewServer(server.ServerConfig{ + Logger: logger, + Controllers: []server.Controller{api}, + JWTConfig: &config.Service.JWT, }) - if httpErr != nil { - return httpErr.Wrap("failed to init http server") - } serverGRPC, grpcErr := server.NewGRPC(server.DepsGRPC{Logger: logger}) if grpcErr != nil { - return httpErr.Wrap("failed to init grpc server") + return grpcErr.Wrap("failed to init grpc server") } - serverHTTP.Register(&api) serverGRPC.Register(controllers) - go serverHTTP.Run(&config.HTTP) + go func() { + if err := serverHTTP.Start(config.HTTP.Host + ":" + config.HTTP.Port); err != nil { + logger.Error("Server startup error", zap.Error(err)) + cancel() + } + }() + go serverGRPC.Run(&config.GRPC) closer.Add(mongoDB.Client().Disconnect) - closer.Add(serverHTTP.Stop) + closer.Add(serverHTTP.Shutdown) closer.Add(serverGRPC.Stop) closer.Add(closer.Wrap(kafkaTariffClient.Close)) diff --git a/internal/interface/swagger/api.2.go b/internal/interface/controller/http/controllers.go similarity index 99% rename from internal/interface/swagger/api.2.go rename to internal/interface/controller/http/controllers.go index d23e780..ab181bb 100644 --- a/internal/interface/swagger/api.2.go +++ b/internal/interface/controller/http/controllers.go @@ -1,4 +1,4 @@ -package swagger +package http import ( "fmt" @@ -52,10 +52,8 @@ type clients struct { codeword *client.CodewordClient } -var _ ServerInterface = (*API2)(nil) - -func NewAPI2(logger *zap.Logger, db *mongo.Database, config *models.Config, consumer *tariff.Consumer, producer *tariff.Producer, encrypt *qutils.Encrypt) API2 { - return API2{ +func NewAPI2(logger *zap.Logger, db *mongo.Database, config *models.Config, consumer *tariff.Consumer, producer *tariff.Producer, encrypt *qutils.Encrypt) *API2 { + return &API2{ logger: logger, history: repository.NewHistoryRepository2(logger, db.Collection("histories")), currency: repository.NewCurrencyRepository2(logger, db.Collection("currency_lists")), diff --git a/internal/interface/swagger/money.go b/internal/interface/controller/http/money.go similarity index 97% rename from internal/interface/swagger/money.go rename to internal/interface/controller/http/money.go index 4b91385..9beea2d 100644 --- a/internal/interface/swagger/money.go +++ b/internal/interface/controller/http/money.go @@ -1,4 +1,4 @@ -package swagger +package http import ( "context" @@ -30,7 +30,7 @@ func (api *API2) GetPaymentLink(ctx context.Context, request *models.GetPaymentL return api.GetPaymentLinkTinkoff(ctx, request) case models.PaymentTypeSBP: return api.GetPaymentLinkSBP(ctx, request) - case models.PaymentTypeSberB2B: + case models.PaymentTypeSberB2B: return api.GetPaymentLinkB2B(ctx, request) } @@ -114,7 +114,7 @@ func (api *API2) GetPaymentLinkTinkoff(ctx context.Context, request *models.GetP } func (api *API2) GetPaymentLinkSBP(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { - link, err := api.clients.payment.GetPaymentLinkSBP(ctx, &treasurer.GetPaymentLinkBody{ + link, err := api.clients.payment.GetPaymentLinkSBP(ctx, &treasurer.GetPaymentLinkBody{ MainSettings: &treasurer.MainPaymentSettings{ Currency: request.Body.Currency, Amount: request.Body.Amount, diff --git a/internal/interface/controller/http/route.go b/internal/interface/controller/http/route.go new file mode 100644 index 0000000..ae876cb --- /dev/null +++ b/internal/interface/controller/http/route.go @@ -0,0 +1,32 @@ +package http + +import "github.com/gofiber/fiber/v2" + +func (api *API2) Register(router fiber.Router) { + router.Delete("/account", api.DeleteAccount) + router.Get("/account", api.GetAccount) + router.Patch("/account", api.ChangeAccount) + router.Post("/account", api.AddAccount) + router.Delete("/account/:userId", api.DeleteDirectAccount) + router.Get("/account/:userId", api.GetDirectAccount) + router.Patch("/account/:userId", api.SetAccountVerificationStatus) + router.Get("/accounts", api.PaginationAccounts) + router.Delete("/cart", api.RemoveFromCart) + router.Patch("/cart", api.Add2cart) + router.Post("/cart/pay", api.PayCart) + router.Get("/currencies", api.GetCurrencies) + router.Put("/currencies", api.UpdateCurrencies) + router.Get("/history", api.GetHistory) + router.Post("/history/ltv", api.CalculateLTV) + router.Post("/promocode/ltv", api.PromocodeLTV) + router.Post("/quizlogo/stat", api.QuizLogoStat) + router.Get("/recent", api.GetRecentTariffs) + router.Post("/sendReport", api.SendReport) + router.Patch("/wallet", api.ChangeCurrency) + router.Post("/wallet", api.RequestMoney) + router.Post("/wallet/rspay", api.PostWalletRspay) +} + +func (api *API2) Name() string { + return "" +} diff --git a/internal/interface/swagger/api.gen.go b/internal/interface/swagger/api.gen.go deleted file mode 100644 index c40c584..0000000 --- a/internal/interface/swagger/api.gen.go +++ /dev/null @@ -1,631 +0,0 @@ -// Package swagger provides primitives to interact with the openapi HTTP API. -// -// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT. -package swagger - -import ( - "bytes" - "compress/gzip" - "encoding/base64" - "fmt" - "net/http" - "net/url" - "path" - "strings" - - "github.com/getkin/kin-openapi/openapi3" - "github.com/labstack/echo/v4" - "github.com/oapi-codegen/runtime" -) - -// ServerInterface represents all server handlers. -type ServerInterface interface { - // удалить собственный аккаунт - // (DELETE /account) - DeleteAccount(ctx echo.Context) error - // Получение текущего аккаунта юзера - // (GET /account) - GetAccount(ctx echo.Context) error - // Отредактировать аккаунт - // (PATCH /account) - ChangeAccount(ctx echo.Context) error - // Создать новый аккаунт - // (POST /account) - AddAccount(ctx echo.Context) error - // Удалить аккаунт по айди - // (DELETE /account/{userId}) - DeleteDirectAccount(ctx echo.Context, userId string) error - // Получить аккаунт по ID пользователя системы единой авторизации - // (GET /account/{userId}) - GetDirectAccount(ctx echo.Context, userId string) error - // Выставление статуса верификации - // (PATCH /account/{userId}) - SetAccountVerificationStatus(ctx echo.Context, userId string) error - // списко аккаунтов с пагинацией - // (GET /accounts) - PaginationAccounts(ctx echo.Context, params PaginationAccountsParams) error - // Удаляем из корзины тариф - // (DELETE /cart) - RemoveFromCart(ctx echo.Context, params RemoveFromCartParams) error - // Добавляем в корзину тариф - // (PATCH /cart) - Add2cart(ctx echo.Context, params Add2cartParams) error - // оплатить козину - // (POST /cart/pay) - PayCart(ctx echo.Context) error - // получить список одобренных валют - // (GET /currencies) - GetCurrencies(ctx echo.Context) error - // обновляет список одобренных валют - // (PUT /currencies) - UpdateCurrencies(ctx echo.Context) error - // Получение лога событий связанных с аккаунтом - // (GET /history) - GetHistory(ctx echo.Context, params GetHistoryParams) error - // Расчет среднего времени жизни платящего клиента (LTV) - // (POST /history/ltv) - CalculateLTV(ctx echo.Context) error - // статистика по промокодам в разрезе регистраций и оплат - // (POST /promocode/ltv) - PromocodeLTV(ctx echo.Context) error - // статистика пользователей, перешедших по логотипу в опросах - // (POST /quizlogo/stat) - QuizLogoStat(ctx echo.Context) error - // Получение недавних тарифов - // (GET /recent) - GetRecentTariffs(ctx echo.Context) error - // отправить акт проделанных работ на почту - // (POST /sendReport) - SendReport(ctx echo.Context) error - // Изменить валюту кошелька - // (PATCH /wallet) - ChangeCurrency(ctx echo.Context) error - // Запрос на получение ссылки на оплату - // (POST /wallet) - RequestMoney(ctx echo.Context) error - // Обработка запроса RSPay - // (POST /wallet/rspay) - PostWalletRspay(ctx echo.Context) error -} - -// ServerInterfaceWrapper converts echo contexts to parameters. -type ServerInterfaceWrapper struct { - Handler ServerInterface -} - -// DeleteAccount converts echo context to params. -func (w *ServerInterfaceWrapper) DeleteAccount(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.DeleteAccount(ctx) - return err -} - -// GetAccount converts echo context to params. -func (w *ServerInterfaceWrapper) GetAccount(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.GetAccount(ctx) - return err -} - -// ChangeAccount converts echo context to params. -func (w *ServerInterfaceWrapper) ChangeAccount(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.ChangeAccount(ctx) - return err -} - -// AddAccount converts echo context to params. -func (w *ServerInterfaceWrapper) AddAccount(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.AddAccount(ctx) - return err -} - -// DeleteDirectAccount converts echo context to params. -func (w *ServerInterfaceWrapper) DeleteDirectAccount(ctx echo.Context) error { - var err error - // ------------- Path parameter "userId" ------------- - var userId string - - err = runtime.BindStyledParameterWithOptions("simple", "userId", ctx.Param("userId"), &userId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter userId: %s", err)) - } - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.DeleteDirectAccount(ctx, userId) - return err -} - -// GetDirectAccount converts echo context to params. -func (w *ServerInterfaceWrapper) GetDirectAccount(ctx echo.Context) error { - var err error - // ------------- Path parameter "userId" ------------- - var userId string - - err = runtime.BindStyledParameterWithOptions("simple", "userId", ctx.Param("userId"), &userId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter userId: %s", err)) - } - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.GetDirectAccount(ctx, userId) - return err -} - -// SetAccountVerificationStatus converts echo context to params. -func (w *ServerInterfaceWrapper) SetAccountVerificationStatus(ctx echo.Context) error { - var err error - // ------------- Path parameter "userId" ------------- - var userId string - - err = runtime.BindStyledParameterWithOptions("simple", "userId", ctx.Param("userId"), &userId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter userId: %s", err)) - } - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.SetAccountVerificationStatus(ctx, userId) - return err -} - -// PaginationAccounts converts echo context to params. -func (w *ServerInterfaceWrapper) PaginationAccounts(ctx echo.Context) error { - var err error - - // Parameter object where we will unmarshal all parameters from the context - var params PaginationAccountsParams - // ------------- Optional query parameter "page" ------------- - - err = runtime.BindQueryParameter("form", false, false, "page", ctx.QueryParams(), ¶ms.Page) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter page: %s", err)) - } - - // ------------- Optional query parameter "limit" ------------- - - err = runtime.BindQueryParameter("form", false, false, "limit", ctx.QueryParams(), ¶ms.Limit) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err)) - } - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.PaginationAccounts(ctx, params) - return err -} - -// RemoveFromCart converts echo context to params. -func (w *ServerInterfaceWrapper) RemoveFromCart(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Parameter object where we will unmarshal all parameters from the context - var params RemoveFromCartParams - // ------------- Required query parameter "id" ------------- - - err = runtime.BindQueryParameter("form", true, true, "id", ctx.QueryParams(), ¶ms.Id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.RemoveFromCart(ctx, params) - return err -} - -// Add2cart converts echo context to params. -func (w *ServerInterfaceWrapper) Add2cart(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Parameter object where we will unmarshal all parameters from the context - var params Add2cartParams - // ------------- Required query parameter "id" ------------- - - err = runtime.BindQueryParameter("form", true, true, "id", ctx.QueryParams(), ¶ms.Id) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) - } - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.Add2cart(ctx, params) - return err -} - -// PayCart converts echo context to params. -func (w *ServerInterfaceWrapper) PayCart(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.PayCart(ctx) - return err -} - -// GetCurrencies converts echo context to params. -func (w *ServerInterfaceWrapper) GetCurrencies(ctx echo.Context) error { - var err error - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.GetCurrencies(ctx) - return err -} - -// UpdateCurrencies converts echo context to params. -func (w *ServerInterfaceWrapper) UpdateCurrencies(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.UpdateCurrencies(ctx) - return err -} - -// GetHistory converts echo context to params. -func (w *ServerInterfaceWrapper) GetHistory(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Parameter object where we will unmarshal all parameters from the context - var params GetHistoryParams - // ------------- Optional query parameter "page" ------------- - - err = runtime.BindQueryParameter("form", false, false, "page", ctx.QueryParams(), ¶ms.Page) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter page: %s", err)) - } - - // ------------- Optional query parameter "limit" ------------- - - err = runtime.BindQueryParameter("form", false, false, "limit", ctx.QueryParams(), ¶ms.Limit) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err)) - } - - // ------------- Optional query parameter "type" ------------- - - err = runtime.BindQueryParameter("form", false, false, "type", ctx.QueryParams(), ¶ms.Type) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter type: %s", err)) - } - - // ------------- Optional query parameter "accountID" ------------- - - err = runtime.BindQueryParameter("form", false, false, "accountID", ctx.QueryParams(), ¶ms.AccountID) - if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter accountID: %s", err)) - } - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.GetHistory(ctx, params) - return err -} - -// CalculateLTV converts echo context to params. -func (w *ServerInterfaceWrapper) CalculateLTV(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.CalculateLTV(ctx) - return err -} - -// PromocodeLTV converts echo context to params. -func (w *ServerInterfaceWrapper) PromocodeLTV(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.PromocodeLTV(ctx) - return err -} - -// QuizLogoStat converts echo context to params. -func (w *ServerInterfaceWrapper) QuizLogoStat(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.QuizLogoStat(ctx) - return err -} - -// GetRecentTariffs converts echo context to params. -func (w *ServerInterfaceWrapper) GetRecentTariffs(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.GetRecentTariffs(ctx) - return err -} - -// SendReport converts echo context to params. -func (w *ServerInterfaceWrapper) SendReport(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.SendReport(ctx) - return err -} - -// ChangeCurrency converts echo context to params. -func (w *ServerInterfaceWrapper) ChangeCurrency(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.ChangeCurrency(ctx) - return err -} - -// RequestMoney converts echo context to params. -func (w *ServerInterfaceWrapper) RequestMoney(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.RequestMoney(ctx) - return err -} - -// PostWalletRspay converts echo context to params. -func (w *ServerInterfaceWrapper) PostWalletRspay(ctx echo.Context) error { - var err error - - ctx.Set(BearerScopes, []string{}) - - // Invoke the callback with all the unmarshaled arguments - err = w.Handler.PostWalletRspay(ctx) - return err -} - -// This is a simple interface which specifies echo.Route addition functions which -// are present on both echo.Echo and echo.Group, since we want to allow using -// either of them for path registration -type EchoRouter interface { - CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route - TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route -} - -// RegisterHandlers adds each server route to the EchoRouter. -func RegisterHandlers(router EchoRouter, si ServerInterface) { - RegisterHandlersWithBaseURL(router, si, "") -} - -// Registers handlers, and prepends BaseURL to the paths, so that the paths -// can be served under a prefix. -func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) { - - wrapper := ServerInterfaceWrapper{ - Handler: si, - } - - router.DELETE(baseURL+"/account", wrapper.DeleteAccount) - router.GET(baseURL+"/account", wrapper.GetAccount) - router.PATCH(baseURL+"/account", wrapper.ChangeAccount) - router.POST(baseURL+"/account", wrapper.AddAccount) - router.DELETE(baseURL+"/account/:userId", wrapper.DeleteDirectAccount) - router.GET(baseURL+"/account/:userId", wrapper.GetDirectAccount) - router.PATCH(baseURL+"/account/:userId", wrapper.SetAccountVerificationStatus) - router.GET(baseURL+"/accounts", wrapper.PaginationAccounts) - router.DELETE(baseURL+"/cart", wrapper.RemoveFromCart) - router.PATCH(baseURL+"/cart", wrapper.Add2cart) - router.POST(baseURL+"/cart/pay", wrapper.PayCart) - router.GET(baseURL+"/currencies", wrapper.GetCurrencies) - router.PUT(baseURL+"/currencies", wrapper.UpdateCurrencies) - router.GET(baseURL+"/history", wrapper.GetHistory) - router.POST(baseURL+"/history/ltv", wrapper.CalculateLTV) - router.POST(baseURL+"/promocode/ltv", wrapper.PromocodeLTV) - router.POST(baseURL+"/quizlogo/stat", wrapper.QuizLogoStat) - router.GET(baseURL+"/recent", wrapper.GetRecentTariffs) - router.POST(baseURL+"/sendReport", wrapper.SendReport) - router.PATCH(baseURL+"/wallet", wrapper.ChangeCurrency) - router.POST(baseURL+"/wallet", wrapper.RequestMoney) - router.POST(baseURL+"/wallet/rspay", wrapper.PostWalletRspay) - -} - -// Base64 encoded, gzipped, json marshaled Swagger object -var swaggerSpec = []string{ - - "H4sIAAAAAAAC/+xce3MbR3L/KlOb/GFXViBI0dGZ/8mUL1HK9il6uVQi624JDMg9AbvQ7sIy7WIVH9ar", - "KEuRc6m4FEs++1yV/xIQJESQBMCv0PONUt0z+56lQIqixNh3VTIIzO70zPTj14/pr42K22i6DncC35j6", - "2vArC7xh0cfzlYrbcgL82PTcJvcCm9MPf7Sr+B/+pdVo1rkxZfyufK42Xjt3bq5S+914pXruww8nz35Y", - "Hh83TCNYbOIIP/BsZ95YMo2K5QWpp28e9HjBTxPGrGnYAW8QPbk51BeW51mLNKfHrYBXz9PENddrWIEx", - "ZVStgJ8J7AbXkVnldX7IR2z/gnwotbyaVfd5NHrOdevccnC4YzU4jvx7j9eMKePvxuKDGFOnMPYZjlky", - "DT+wgpb/qtHqwK7IwUum0WpWD7vuls+9i69xvHesep0Hr6L0czlqack0PH67ZXu4aTeJsSISFKtEr1Q7", - "Fm1GdEZG8oCTi56N6HPn/swrAdKX3iNcptNq4NyOizPcwn9dbz7xbLy2jyzn1rTlVfMSUbG86oJbr3IP", - "/6pyv+LZzcB2HWPKgO+hL54w6MAetGELurAnHol70GawC22xLFbFumEmtvvi9fOfMfznD9e1AuRXNJM8", - "gyFssenr0xMMerAHPTZ9/fqEyc6Gf04ysQI96EMHhkiJyWAfuuI+tMUqtKErVsUKkjlAwoawIZbplwEM", - "YYeJFbEKQ7EMQxhAt4jw8gc6evmXTdtb/NR1ggUN3T9AF+cV9xj0aBYkqQsD6IknOC1OuZvaK/bep5++", - "P/K8N7ilO5N/p+0afcobN27cSE86UZ7QCoDTasxp2eA5DKEPXbFctH2Xr32Uf2FGQtTbU6tLb7GO6T/2", - "PNfLc22D+741z9PCjtLHHDdgNbflVHUrlPI37VbTT06WJ81YydhO8I+T8dO2E/B57uXWU8G3mBElOuL/", - "2fYD11vUCJ3baHAnbUwMPMJvkVmR3UnYoA17yOtD/Bb6Yo2J+zRgckIrXidjK15DxR7SznjWnQs8sOy6", - "r2HK/6WdkexOkt2HIWyKNQb7Yhm6sEU/78EQXkJPrIpHJnEv7EIPR2+INdgSa2KViW9Qz4hHYlUsi3V6", - "ayheqDd60DPlIXwbHUM0BR7RJrTFYwad8PSYmrgrhw3lm3DyPWjjH+IRaSUprXioK+zPvuuUGIPvYQOH", - "bsEeKjQk9yVs4bqQK1ahB/u43G1owz6SCD1Geq2NLNOBoXhSSsnl1zNGYHl2rebPGFM3ZwrPasYwD/px", - "dkl3mPKLJCtUWn7gNrhXkpN+7FS5VgxP3LhnRDdtq2nsq02yGUmtafgtKeM6of9MgaO0xNdszw9C3BQv", - "Ab6HDrRhoFtyw65W67z4GRhCB3rivu5Z15vXPPgC/89mZmbQeA2Rw14gvynj2MYftFqTV1ynejAh2j3P", - "7c0laxF38GrIOQrAzIXoxDQC27nl1mqIVwzTuG3fsXG757g3J79ZdN2G6/BF1LzunF3Hk7MdP7Dq9QY5", - "Aoi9/AV6qGmYxtzE3JX4aates+ijDiNd8tyG+0nwBQKs/AGi6aAPVrVqow6y6pdSAzIGiojMa61dUg09", - "NNukFzpS3NGGd2FTY3WQc+f9Ed9EWmlTKi9CQfegBzt6W5Y7nMz7+6RkCEvsicfiPrOrSqGhpjVRCw1C", - "9CGB1aj0MFRbo25ESJ+O4n9t2V994s674YlFblX6LKTFSi+PsIKt1U5FR/fs8Ed3u2V/pWjQk3bMc+Xf", - "dNuuMvpFs9ACxnp23IyV9Wnf1rxXySpdvJA/BvndES1Lbt7PI0cy62r5Oj/iJ7EGfRQ3RtwgnRtcdwch", - "hngKA1TOoYODoB9Rg3goRQk/LouVpNkfL58rj48AaE2j0vI87lR0HPizdhpGGh/1wUguQLEw/QV5WTzC", - "s1XrWqGDX0V01ZHqYR+6sEMex90Sg/8m9LVBCA1hWbRPYgWfFU/RGRR3FRhEV3GbVBOCqL2U+KBfKX9D", - "YL2LQBDaJYkDdxFUiWWxBl3oS7dyFzHWlnIn4/VD1wzBlwSTSD3+PkBUSQc4oPl2TKYIUeCxK54qKhWA", - "hZc429GOsNnyKguWz/3zjTDkldnqF7AhHhIDiZWI1eLdIFg8lGBXrMu9G4ineNaEY8Uj2Cao0SbW2xOP", - "jJEI85v8EOSQk0MSLk3KQKzjWSbObBuHdcQKbl6Htrev3iEexhpDIRL0hwnrI/eswQB5wziCjxfKR4Qq", - "QvCR3fZwvbM6w+XzSsuzg8UrlQXekLrgI2550teeo0+/Dyn7l8+vGllb/LETcI8FC5wF7i3usDt2sEB/", - "/km+Zor9iTU9XrO/NBkvzZfYjHo/s+YqVT4+cXbygxkDXQOKYpGXJeePqF0IgqaxhMTaTs3VH1vCfyGG", - "6ajQC30iZpe+Tg+9ERTNDvkobXYmdpjkiDaFlCLooOezx0x8g2cHu6T1SdSQBMmvy7ANPWSTEE2IB5I7", - "8chLhCQDUkzTyilhZ1JkhU6WWCPaEhRJz2sPSZOMA33oGabxBfd8uRnjpXKpTDC7yR2raRtTxtlSuYTm", - "oWkFC3TAY1Ycg5auhWZT91Vg5b4MY2VYlknNBHvSBoh10hFoUSx8AbpDhvSnw3g3cq/fdB1fMtlEuSyj", - "DU6gZNFqNut2hR4fQ58zjpuPGKGVPJJehlgTK6SMH5CS7EZ0xyecFcUl05gsjx8bcTJKpCENnkMXzzby", - "5bdDFZESTGPqZiySN2eXZtHFazQsb5GWp1bTU647maEE24t1NAypJSL/WYhybhohH8wumcY812nE72n7", - "lAig5QkDmsrObaNdIxvUZeIxbBMTtynisBLGAdGylBj8G+zAFvToJHqwmxoup1iLma0H24yM6i6to52x", - "BDsxEtmCNtpXSVVHBiA2VXSlg48zqxUsuJ79FZ1ejkv/iQfvGIsmdkMx6TvBk0jC5AmQ8DOxq4wrFahf", - "wptdsTq6oMCP2T1NotWunCyjCRIcWiAzTSuoLGhzE9uoO2EgnoTsTMkKiSdhO0QCeNi4z5vqz23lRfQK", - "F55j3+kFy5lPKdnbLe4HH7nVxWM7K5kv0xzVD1LykVBao9xb6Ue9C7p+hZD2VrzZp1nXwwsF3XE9u4hl", - "KOBBzIH7P4qSb7q+Tsv/FO4TalImo2YayxHhkkguTPQYVigTRmgkktuueBh5EhtiHbVxjnXPV6vvGjj4", - "/8Uw8bESgxQdq5ZXlswIJo59LePRSwfixR9Q08n8H3pFiEMkMEDdR5N2UNmtqOAw/tuXJl4C4yFT+gMZ", - "/KVkL+ibCSycwG05HFwAPi/YHq8k7HvT8qwGD7jn086ll3Dxgs4vs/EnhM5hqnwqDs/H/ljgtbiZOPRs", - "KGb27XA4/O1Uwt+TghrPyTqnNVeR4R1d7P6WwuRZFbovkQZh4UNB8TcsYFnUiV9JRajiHcO0yHV1SPo3", - "eXsllv9N4o5f4mJwXyxzyG1F3kTKV11nJCG9MKqa3jEF0A/rEBS40algFMorBa6WoScDvrE7oGS0I9az", - "QSoZaFwlI79GIS39O0wmnuBT0iWR7jLhNgXmGDyHZ/DCZPA/+Md/QU/ckyTJSif4hZzy+Iec/F+JPOnr", - "3LNrinWuhHVlb1cXHM0ryudZD10vmM/CLC0tvSvaScNPBIOT/HTalcN3I6yxQGZehYzp8PTWOhvRop2X", - "Ur6bZfUhWm5KNK1RymVbmt2oRpAs9YDkrsv+gclCwofQLUpt51+fk9VL1rzt0J/nw6W8QkITlXZpmsQ6", - "JZHaqH1VNlCssHFZQFenejZVRUXifLvFvcVYnpvWPDeS0lvlNatVD4ypcV0KJEsVkbFdQNeIJNTthh0U", - "0FAua6h4XXCR1ipJXopS8SNJeD6NHLiBVb9kzcs3xym78VGy0kcKTeY2Xcd9JKxx0DoUhV0trzKZ3mvD", - "puKne4Q5dwqFMax9j13TNK9f5g33C/57z21My9LnDJ/reMI+2MQcKR3/1jBpwuUbytB6Ok31a0OgMgq7", - "IzO4sb3ZoY/SChze3UNcJdFSdnuTr415mLj2IMz4POvkkTlUMT9prKhyVNXdapeRyUFL5KkLxE1UfpWi", - "8Rfc4QQyGIYFHtHprf0mHK8jHIkNDgUku8EHikeo38ealqxV1wew/xPaYUGzumsRCYqq05C5FtinQoFV", - "NFNpFZgHSIvKWrz1yDTVV0Wk54oMTldMOl6HctV3KUgtRU1//LLQRaElhbZzkafpeNRrHlniCp0sHLt2", - "5YJhGtPnLxzmetxRwVQEjdqJeq4MgEo8GOX9E87FkMryN8IyLxm9i9+V2OSwhIjMUEuzsdeoxDyzt0dz", - "pY9rW5dOzfGi5pOx2L1XH/AJyfA1y1HVELx6KKmNlqJS2q/PcijbC/EtpCLBDi8qnUr3FP76FtxTU1Mw", - "24P9sDponXTvkxFnVzdQiqNrpqb6YUvlCOJwCpmMXIivxOA/VPqYUsXJ+IeZKl3tJQOocdZbhjF7xRNm", - "64hKIy5beZgXLxhvMsuQDgR4vOJ61dHjAKFkvPk4wChpjSR3wc7pAiX54iAqH9uUl9cSy6K7bOJJGKEj", - "PYeQMxvE6CdUXqjjUhpvrB58kcSzmaIeq15p1a2Af3L1unFc0eua5za0bmabgpQoWQprboU4s8PEN7St", - "fRl5Zdcc+0sW2A3uB1ajmRDfssnQAJK7MFAOVY/OoSsrStQkufuLpdEqtgO34FbGgEpU3xThqRqxbqK4", - "u3SEim06AFrK7Cgy96N08mXGVxVBLFOVM11GgDaLuSN2xZeOVSUpLs3dCpFlSIMDQtDy1x2Zc34JW3Qz", - "VSa7xDrFSWRh/QqBoy0Suz6LnAN8RorRKLt8KAVGufLkTtI+kr4qn5C+kvEbVZy7HfuuiXIqZBYGG9Lk", - "iQfQNRmppz4L3HckJPHBiezXd+lLK+IJecPiAfRgg1B0lEOVlZqja/2/JliAGhSEPE2JJyXq0iIweBle", - "zIl4VDyJK0dTtUjsvU+uXn+/0AI0PbfhVtwqP9gGXAqHvXkbQMpvB/rigbpSsJ9ZvpmQ1UQhdpijQ4ne", - "oHLEdnSDXLn4dOcCNejIWn0UYrbknh8PGYfU0serbg+SidSl31GUWnzzhclLJO3wbgbde8nuhqzUPeVS", - "rFlWWxVZRReCyULhblD0UaYMiZJtxK3F94CjWFVClv3ACmw/sCtKmm+37K/q7rw75odXs7XSnLoOfPql", - "uRQbqnJUIKKuDUbXMiiefka1npDvHsJm5AEn6syomL8kryK+DLljM5H2bmeWoNUm0lHOw5U9Sp706AYk", - "rQ0Xu1vwkqZq3ZLZ03QWvj3Km05eub2hUyGZFHePeC4nXf+SkrTftOYhtWa+1kbdEg4vND+gi98PoCfu", - "KjUrPeWhbAGjrkgPQ0QLbXH3AO3p8YraPn0VzXeUHOgQ1z/UVdLQJUx1kRodWOmRRwklWVpDKdm01xld", - "R8vf+smW7oQxpu383TIKJ+UilpdpUfJGv39syt4+xg4zs29AJkcKWUVtDkYIqOcFNeEpvRv+2oleipMc", - "LdaVSk9kaWUO8LS7Y5og3ECZrA6Zm6xgF3pYPneql3nT9YJDpYxRhYX3rXdRkclrVlEyOex7FgX+cChi", - "gFVNKWxEwSmX/1fmpZObdtouSCWJjyvHqWL8FSceVhnAUNwXq6nUdZoX486dRXU+P0Y3qSOj2dVc8YDh", - "1IxzhsELQit0v4SuUyfuAGZrgdqyQWbYFKSdzdO16YW54vkYAXVVAiXdMqEy59XYe4RIlVO1TS042+I+", - "Ss1Adb2TjeHuk7Z4JK3qdhg0fF/NHDWTUc0ZEi1c1nKdE5gskx1CR6xRV7t4bInBs2jwU9iVEWfczPuE", - "d8U9OskhLXJF5WNJn4d7Jru3JO8rqsYQhIIGVKKwwxBxrIZvjRpKqJAQHcNjCgrthMOodCbbo08mJOUV", - "+rB55RbBij1JtbqmF/aOkQ1oeumOoh25qIFsLVNwL3g6bhJyPFoo2ZUn1kUyhX6w2okzv+9oQbzMDCtP", - "pp3qJpRjxZODHz8XSPJAVhikxPlXVar2o74BUB4dHcIeRPf2Q1V4kDpKqHyl5ItvWJ9h8IvKR0UdnFIq", - "nzRLQs3ifIlqNZNJlJK/9tePEiliFTbEt+QK9aGXUe1tOWPs6pIRyyj2VH2cWGHUvQp1oSwADJsYh2PW", - "Uk05SCUPyBAM0905IvWv6aOT01uXpZr6VPUyOh6tZUX9p+JU+AflibIubDOXaEd9EGdGbasP7FV28cof", - "zkxOjJ9L5SNHaU5Wd+dtJ61l6as/BtwPdA80F1yHfxa1SY4fO/dhOfyfvtNe0PKca149/dRCEDT9qbEx", - "3w54yWuNqfrgwk6rBwayE601s2ZB1Zckulmpw3oTZiKT3LSdW/pFz7vufB2XPUpTvUN6rsleiSfmtf2U", - "bC6VqoINXds12Ev4cWLtEFpTU3yruyUSqpJeXpHoVGkMnsc8P1P9m8mUuX4g+xpepoHHpTWi/oCJ1nfl", - "ciIjXau7VkIoVBfxAhYZKW9UwEd3pVk9O8JiIloTjcgNxw2YVa+7d3iV1VyPOa7DXG/eclRTJF/LNOG5", - "dgnSDmCY4NcTiwq8kD3zpdclvYCkp9Rml69cCuNHiody1GW7XaRrvAxNCZtqBifWYD90hNLNJdUrIrWl", - "eUeiSJvAQvgIKtKC4ZH/Eg9X8qB5IBHQpGo+9cBCVBWmS2Jkg77xc3Fodml26f8CAAD//9ED7UTAZAAA", -} - -// GetSwagger returns the content of the embedded swagger specification file -// or error if failed to decode -func decodeSpec() ([]byte, error) { - zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) - if err != nil { - return nil, fmt.Errorf("error base64 decoding spec: %w", err) - } - zr, err := gzip.NewReader(bytes.NewReader(zipped)) - if err != nil { - return nil, fmt.Errorf("error decompressing spec: %w", err) - } - var buf bytes.Buffer - _, err = buf.ReadFrom(zr) - if err != nil { - return nil, fmt.Errorf("error decompressing spec: %w", err) - } - - return buf.Bytes(), nil -} - -var rawSpec = decodeSpecCached() - -// a naive cached of a decoded swagger spec -func decodeSpecCached() func() ([]byte, error) { - data, err := decodeSpec() - return func() ([]byte, error) { - return data, err - } -} - -// Constructs a synthetic filesystem for resolving external references when loading openapi specifications. -func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { - res := make(map[string]func() ([]byte, error)) - if len(pathToFile) > 0 { - res[pathToFile] = rawSpec - } - - return res -} - -// GetSwagger returns the Swagger specification corresponding to the generated code -// in this file. The external references of Swagger specification are resolved. -// The logic of resolving external references is tightly connected to "import-mapping" feature. -// Externally referenced files must be embedded in the corresponding golang packages. -// Urls can be supported but this task was out of the scope. -func GetSwagger() (swagger *openapi3.T, err error) { - resolvePath := PathToRawSpec("") - - loader := openapi3.NewLoader() - loader.IsExternalRefsAllowed = true - loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) { - pathToFile := url.String() - pathToFile = path.Clean(pathToFile) - getSpec, ok := resolvePath[pathToFile] - if !ok { - err1 := fmt.Errorf("path not found: %s", pathToFile) - return nil, err1 - } - return getSpec() - } - var specData []byte - specData, err = rawSpec() - if err != nil { - return - } - swagger, err = loader.LoadFromData(specData) - if err != nil { - return - } - return -} diff --git a/internal/interface/swagger/middleware.go b/internal/interface/swagger/middleware.go deleted file mode 100644 index b049a4c..0000000 --- a/internal/interface/swagger/middleware.go +++ /dev/null @@ -1,20 +0,0 @@ -package swagger - -import ( - "github.com/deepmap/oapi-codegen/pkg/middleware" - "github.com/getkin/kin-openapi/openapi3" - "github.com/getkin/kin-openapi/openapi3filter" - "github.com/labstack/echo/v4" -) - -func CreateMiddleware(swagger *openapi3.T, authenticationFunc openapi3filter.AuthenticationFunc) echo.MiddlewareFunc { - validator := middleware.OapiRequestValidatorWithOptions(swagger, - &middleware.Options{ - Options: openapi3filter.Options{ - AuthenticationFunc: authenticationFunc, - }, - }, - ) - - return validator -} diff --git a/internal/server/http.go b/internal/server/http.go index 5e80b6a..3cbe6ce 100644 --- a/internal/server/http.go +++ b/internal/server/http.go @@ -3,91 +3,70 @@ package server import ( "context" "fmt" - "net/http" - "time" - - "github.com/getkin/kin-openapi/openapi3" - "github.com/getkin/kin-openapi/openapi3filter" - "github.com/labstack/echo/v4" - "github.com/labstack/echo/v4/middleware" + "github.com/gofiber/fiber/v2" "go.uber.org/zap" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils" ) -type DepsHTTP struct { - Logger *zap.Logger - Swagger *openapi3.T - AuthenticationFunc openapi3filter.AuthenticationFunc +type ServerConfig struct { + Logger *zap.Logger + Controllers []Controller + JWTConfig *models.JWTConfiguration } -type HTTP struct { - logger *zap.Logger - server *http.Server - echo *echo.Echo +type Server struct { + Logger *zap.Logger + Controllers []Controller + app *fiber.App } -func NewHTTP(deps DepsHTTP) (*HTTP, errors.Error) { - if deps.Logger == nil { - return nil, errors.NewWithMessage("failed to init http server: logger is nil ", errors.ErrInvalidArgs) +func NewServer(config ServerConfig) *Server { + app := fiber.New() + + jwtUtil := utils.NewJWT(config.JWTConfig) + app.Use(utils.NewAuthenticator(jwtUtil)) + + s := &Server{ + Logger: config.Logger, + Controllers: config.Controllers, + app: app, } - if deps.Swagger == nil { - return nil, errors.NewWithMessage("failed to init http server: swagger is nil ", errors.ErrInvalidArgs) - } + s.registerRoutes() - if deps.AuthenticationFunc == nil { - return nil, errors.NewWithMessage("failed to init http server: AuthenticationFunc is nil ", errors.ErrInvalidArgs) - } - - echo := echo.New() - - echo.Use(middleware.Recover()) - echo.Use(swagger.CreateMiddleware(deps.Swagger, deps.AuthenticationFunc)) - - return &HTTP{ - echo: echo, - logger: deps.Logger, - server: &http.Server{ - Handler: echo, - MaxHeaderBytes: 1 << 20, - ReadTimeout: 20 * time.Second, - WriteTimeout: 20 * time.Second, - IdleTimeout: 20 * time.Second, - }, - }, nil + return s } -func (receiver *HTTP) Listen(address string) error { - receiver.server.Addr = address - - return receiver.server.ListenAndServe() -} - -func (receiver *HTTP) Run(config *models.ConfigurationHTTP) { - connectionString := fmt.Sprintf("%s:%s", config.Host, config.Port) - startServerMessage := fmt.Sprintf("starting http server on %s", connectionString) - - receiver.logger.Info(startServerMessage) - - if err := receiver.Listen(connectionString); err != nil && err != http.ErrServerClosed { - receiver.logger.Error("http listen error: ", zap.Error(err)) +func (s *Server) Start(addr string) error { + if err := s.app.Listen(addr); err != nil { + s.Logger.Error("Failed to start server", zap.Error(err)) + return err } -} - -func (receiver *HTTP) Stop(ctx context.Context) error { - receiver.logger.Info("shutting down server...") - - if err := receiver.server.Shutdown(ctx); err != nil { - return fmt.Errorf("failed to shutdown server: %w", err) - } - return nil } -func (receiver *HTTP) Register(api swagger.ServerInterface) *HTTP { - swagger.RegisterHandlers(receiver.echo, api) - - return receiver +func (s *Server) Shutdown(ctx context.Context) error { + return s.app.Shutdown() +} + +func (s *Server) registerRoutes() { + for _, c := range s.Controllers { + router := s.app.Group(c.Name()) + c.Register(router) + } +} + +type Controller interface { + Register(router fiber.Router) + Name() string +} + +func (s *Server) ListRoutes() { + fmt.Println("Registered routes:") + for _, stack := range s.app.Stack() { + for _, route := range stack { + fmt.Printf("%s %s\n", route.Method, route.Path) + } + } } diff --git a/internal/utils/authenticator.go b/internal/utils/authenticator.go index ce10d9a..03daaf7 100644 --- a/internal/utils/authenticator.go +++ b/internal/utils/authenticator.go @@ -1,13 +1,10 @@ package utils import ( - "context" "fmt" - "net/http" + "github.com/gofiber/fiber/v2" "strings" - "github.com/deepmap/oapi-codegen/pkg/middleware" - "github.com/getkin/kin-openapi/openapi3filter" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" ) @@ -16,50 +13,40 @@ const ( prefix = "Bearer " ) -func NewAuthenticator(jwtUtil *JWT) openapi3filter.AuthenticationFunc { - return func(ctx context.Context, input *openapi3filter.AuthenticationInput) error { +func NewAuthenticator(jwtUtil *JWT) fiber.Handler { + return func(c *fiber.Ctx) error { if jwtUtil == nil { - return errors.New( - fmt.Errorf("jwt util is nil: %w", errors.ErrInvalidArgs), - errors.ErrInvalidArgs, - ) + return fiber.NewError(fiber.StatusInternalServerError, errors.ErrInvalidArgs.Error()) } - return authenticate(ctx, jwtUtil, input) + err := authenticate(jwtUtil, c) + if err != nil { + return fiber.NewError(fiber.StatusUnauthorized, err.Error()) + } + + return c.Next() } } -func authenticate(ctx context.Context, jwtUtil *JWT, input *openapi3filter.AuthenticationInput) error { - if input.SecuritySchemeName != "Bearer" { - return fmt.Errorf("security scheme %s != 'Bearer'", input.SecuritySchemeName) - } - - // Now, we need to get the JWS from the request, to match the request expectations - // against request contents. - jws, err := parseJWSFromRequest(input.RequestValidationInput.Request) +func authenticate(jwtUtil *JWT, c *fiber.Ctx) error { + jws, err := parseJWSFromRequest(c) if err != nil { return err } - // if the JWS is valid, we have a JWT, which will contain a bunch of claims. userID, validateErr := jwtUtil.Validate(jws) if validateErr != nil { return validateErr } - // Set the property on the echo context so the handler is able to - // access the claims data we generate in here. - echoCtx := middleware.GetEchoContext(ctx) - - echoCtx.Set(models.AuthJWTDecodedUserIDKey, userID) - echoCtx.Set(models.AuthJWTDecodedAccessTokenKey, jws) + c.Locals(models.AuthJWTDecodedUserIDKey, userID) + c.Locals(models.AuthJWTDecodedAccessTokenKey, jws) return nil } -// extracts a JWS string from an Authorization: Bearer header. -func parseJWSFromRequest(request *http.Request) (string, errors.Error) { - header := request.Header.Get("Authorization") +func parseJWSFromRequest(c *fiber.Ctx) (string, error) { + header := c.Get("Authorization") if header == "" || !strings.HasPrefix(header, prefix) { return "", errors.New( diff --git a/tests/e2e/calculateLTV_test.go b/tests/e2e/calculateLTV_test.go index cf7eb26..4f4e103 100644 --- a/tests/e2e/calculateLTV_test.go +++ b/tests/e2e/calculateLTV_test.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "github.com/stretchr/testify/assert" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client" "penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers" @@ -37,8 +36,14 @@ func TestCalculateLTV(t *testing.T) { fmt.Println(from, to) response, err := client.Post[interface{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{ - URL: "http://localhost:8082/history/ltv", - Body: swagger.CalculateLTVJSONBody{From: from, To: to}, + URL: "http://localhost:8082/history/ltv", + Body: struct { + From int64 + To int64 + }{ + From: from, + To: to, + }, Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)}, }) if ok := assert.NoError(t, err); !ok { diff --git a/tests/e2e/getAccount_test.go b/tests/e2e/getAccount_test.go index 20ff6ad..20b6a3f 100644 --- a/tests/e2e/getAccount_test.go +++ b/tests/e2e/getAccount_test.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "github.com/stretchr/testify/assert" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client" "penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers" @@ -69,9 +68,12 @@ func TestGetAccount(t *testing.T) { page := 0 limit := 3 - params := swagger.PaginationAccountsParams{ - Page: &page, - Limit: &limit, + params := struct { + Page int + Limit int + }{ + Page: page, + Limit: limit, } responseGetAccount, errGetAccount := client.Get[models.PaginationResponse[models.Account], models.ResponseErrorHTTP](ctx, &client.RequestSettings{ diff --git a/tests/integration/history_report_test.go b/tests/integration/history_report_test.go index 4f0e2d3..7d7ca95 100644 --- a/tests/integration/history_report_test.go +++ b/tests/integration/history_report_test.go @@ -6,7 +6,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client" "penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers" @@ -23,7 +22,7 @@ func TestHistoryReport(t *testing.T) { response, err := client.Post[struct{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{ URL: "http://" + "localhost:8082" + "/sendReport", - Body: swagger.SendReportJSONBody{Id: "10002"}, + Body: struct{ Id string }{Id: "10002"}, Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)}, }) if ok := assert.NoError(t, err); !ok { diff --git a/tests/integration/logostat_test.go b/tests/integration/logostat_test.go index 97c45c3..7f81ef5 100644 --- a/tests/integration/logostat_test.go +++ b/tests/integration/logostat_test.go @@ -2,15 +2,15 @@ package integration import ( "context" - "github.com/labstack/echo/v4" + "github.com/gofiber/fiber/v2" "github.com/pioz/faker" "go.uber.org/zap" "log" "net/http" "net/http/httptest" "penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo" + http2 "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" "strconv" "testing" @@ -39,27 +39,27 @@ func TestLogostat(t *testing.T) { repoHi := repository.NewHistoryRepository2(logger, mongoDB.Collection("histories")) InsertToDB(ctx, repoAc, repoHi) - api := swagger.NewAPI2(logger, mongoDB, nil, nil, nil, nil) + api := http2.NewAPI2(logger, mongoDB, nil, nil, nil, nil) - e := echo.New() + app := fiber.New() req := httptest.NewRequest(http.MethodGet, "/", nil) - rec := httptest.NewRecorder() - c := e.NewContext(req, rec) + req.Header.Set("Content-Type", "application/json") - requestBody := swagger.QuizLogoStatJSONRequestBody{ - From: new(int), - Limit: new(int), - Page: new(int), - To: new(int), + requestBody := struct { + From int + Limit int + Page int + To int + }{ + From: 1713087258, + Limit: 10, + Page: 1, + To: 1713260058, } - *requestBody.From = 1713087258 - *requestBody.Limit = 10 - *requestBody.Page = 1 - *requestBody.To = 1713260058 - c.SetRequest(c.Request().WithContext(context.WithValue(c.Request().Context(), "requestBody", requestBody))) + req = req.WithContext(context.WithValue(req.Context(), "requestBody", requestBody)) + resp := httptest.NewRecorder() - err = api.QuizLogoStat(c) } func InsertToDB(ctx context.Context, acc repository.AccountRepository, history repository.HistoryRepository) { From e7db450e8c596fbf65614980232aad2d300dc8c7 Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 20 May 2024 17:29:45 +0300 Subject: [PATCH 3/8] add extractors for userid and token --- deployments/local/.env.test | 10 +- go.mod | 2 +- go.sum | 4 +- .../interface/controller/http/controllers.go | 69 +++++++------ tests/e2e/rspay_test.go | 9 +- tests/e2e/сurrencies_test.go | 9 +- tests/integration/logostat_test.go | 96 +++++++++---------- 7 files changed, 111 insertions(+), 88 deletions(-) diff --git a/deployments/local/.env.test b/deployments/local/.env.test index 99cfd19..40d82e8 100644 --- a/deployments/local/.env.test +++ b/deployments/local/.env.test @@ -4,21 +4,21 @@ JWT_AUDIENCE="pena" JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm69\n80fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6B\ndA4TS2kB9Kf0wn0+7wSlyikHoKhbtzwXHZl17GsyEi6wHnsqNBSauyIWhpha8i+Y\n+3GyaOY536H47qyXAgMBAAE=\n-----END PUBLIC KEY-----" HTTP_HOST=0.0.0.0 -HTTP_PORT=8003 +HTTP_PORT=8082 GRPC_HOST=0.0.0.0 GRPC_PORT=9000 GRPC_DOMEN=customer-service:9000 MONGO_HOST=localhost -MONGO_PORT=27024 +MONGO_PORT=27020 MONGO_USER=test MONGO_PASSWORD=test MONGO_DB_NAME=admin MONGO_AUTH=admin KAFKA_BROKERS=localhost:9092 -KAFKA_TOPIC_TARIFF=tariffs +KAFKA_TOPIC_TARIFF=test-topic AUTH_MICROSERVICE_USER_URL=http://localhost:8000/user HUBADMIN_MICROSERVICE_TARIFF_URL=http://localhost:8001/tariff @@ -27,9 +27,11 @@ DISCOUNT_MICROSERVICE_GRPC_HOST=localhost:9040 PAYMENT_MICROSERVICE_GRPC_HOST=treasurer-service:9085 VERIFICATION_MICROSERVICE_USER_URL=http://10.8.0.8:7035/verification TEMPLATEGEN_MICROSERVICE_URL=10.6.0.17 +CODEWORD_MICROSERVICE_GRPC_HOST = http://localhost:8000/user API_URL=https://api.smtp.bz/v1/smtp/send MAIL_SENDER=noreply@mailing.pena.digital MAIL_API_KEY=P0YsjUB137upXrr1NiJefHmXVKW1hmBWlpev MAIL_AUTH_USERNAME=kotilion.95@gmail.com -MAIL_AUTH_PASSWORD=vWwbCSg4bf0p \ No newline at end of file +MAIL_AUTH_PASSWORD=vWwbCSg4bf0p +MAIL_ADDRESS = mail@mail.com \ No newline at end of file diff --git a/go.mod b/go.mod index 21f83d5..fef5863 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c google.golang.org/grpc v1.62.0 google.golang.org/protobuf v1.32.0 - penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240220080149-ae9c991d3ece + penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6 penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240412164014-6ce70d76fedc ) diff --git a/go.sum b/go.sum index 99fd635..46e61ab 100644 --- a/go.sum +++ b/go.sum @@ -264,7 +264,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240220080149-ae9c991d3ece h1:CsjgNNqssfa05B7iDNMyK2wWR7SZ/kglLTMAVrhGLtY= -penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240220080149-ae9c991d3ece/go.mod h1:lTmpjry+8evVkXWbEC+WMOELcFkRD1lFMc7J09mOndM= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6 h1:oV+/HNX+JPoQ3/GUx08hio7d45WpY0AMGrFs7j70QlA= +penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6/go.mod h1:lTmpjry+8evVkXWbEC+WMOELcFkRD1lFMc7J09mOndM= penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240412164014-6ce70d76fedc h1:B9X8pOrqWPGbWZNXSJEUk/8GWeBDGQmMKgQ0F+PSliQ= penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240412164014-6ce70d76fedc/go.mod h1:/DcyAjBh41IbomuDu5QzhL9flZW6lWO3ZAEbUXKobk0= diff --git a/internal/interface/controller/http/controllers.go b/internal/interface/controller/http/controllers.go index ab181bb..ea3443f 100644 --- a/internal/interface/controller/http/controllers.go +++ b/internal/interface/controller/http/controllers.go @@ -110,6 +110,16 @@ func (api *API2) noauth(ctx *fiber.Ctx) error { return api.error(ctx, fiber.StatusUnauthorized, "failed to get jwt payload") } +func (api *API2) extractUserID(ctx *fiber.Ctx) (string, bool) { + id, ok := ctx.Context().UserValue(models.AuthJWTDecodedUserIDKey).(string) + return id, ok +} + +func (api *API2) extractToken(ctx *fiber.Ctx) (string, bool) { + token, ok := ctx.Context().UserValue(models.AuthJWTDecodedAccessTokenKey).(string) + return token, ok +} + // Health func (api *API2) GetHealth(ctx *fiber.Ctx) error { @@ -119,8 +129,8 @@ func (api *API2) GetHealth(ctx *fiber.Ctx) error { // Account func (api *API2) DeleteAccount(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } @@ -133,8 +143,8 @@ func (api *API2) DeleteAccount(ctx *fiber.Ctx) error { } func (api *API2) ChangeAccount(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } @@ -156,6 +166,7 @@ func (api *API2) SetAccountVerificationStatus(ctx *fiber.Ctx) error { if userID == "" { return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") } + var request models.SetAccountStatus if err := ctx.BodyParser(&request); err != nil { return api.error(ctx, fiber.StatusBadRequest, "failed to bind json", err) @@ -171,8 +182,8 @@ func (api *API2) SetAccountVerificationStatus(ctx *fiber.Ctx) error { } func (api *API2) GetAccount(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } @@ -185,8 +196,8 @@ func (api *API2) GetAccount(ctx *fiber.Ctx) error { } func (api *API2) AddAccount(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } @@ -295,8 +306,8 @@ func (api *API2) PaginationAccounts(ctx *fiber.Ctx) error { // Cart func (api *API2) RemoveFromCart(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } @@ -314,13 +325,13 @@ func (api *API2) RemoveFromCart(ctx *fiber.Ctx) error { } func (api *API2) Add2cart(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } - token := ctx.Get(models.AuthJWTDecodedAccessTokenKey) - if token == "" { + token, ok := api.extractToken(ctx) + if !ok || token == "" { return api.noauth(ctx) } @@ -347,13 +358,13 @@ func (api *API2) Add2cart(ctx *fiber.Ctx) error { } func (api *API2) PayCart(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } - accessToken := ctx.Get(models.AuthJWTDecodedAccessTokenKey) - if accessToken == "" { + accessToken, ok := api.extractToken(ctx) + if !ok || accessToken == "" { return api.noauth(ctx) } @@ -573,7 +584,11 @@ func (api *API2) GetHistory(ctx *fiber.Ctx) error { if accountID != "" { userID = accountID } else { - userID = ctx.Get(models.AuthJWTDecodedUserIDKey) + id, ok := api.extractUserID(ctx) + if !ok || id == "" { + return api.noauth(ctx) + } + } limit, err := strconv.ParseInt(limitStr, 10, 64) @@ -623,8 +638,8 @@ func (api *API2) GetHistory(ctx *fiber.Ctx) error { // Wallet func (api *API2) RequestMoney(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } @@ -650,8 +665,8 @@ func (api *API2) RequestMoney(ctx *fiber.Ctx) error { } func (api *API2) ChangeCurrency(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } @@ -723,8 +738,8 @@ func (api *API2) CalculateLTV(ctx *fiber.Ctx) error { } func (api *API2) GetRecentTariffs(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } @@ -860,8 +875,8 @@ func (api *API2) SendReport(ctx *fiber.Ctx) error { } func (api *API2) PostWalletRspay(ctx *fiber.Ctx) error { - userID := ctx.Get(models.AuthJWTDecodedUserIDKey) - if userID == "" { + userID, ok := api.extractUserID(ctx) + if !ok || userID == "" { return api.noauth(ctx) } diff --git a/tests/e2e/rspay_test.go b/tests/e2e/rspay_test.go index c2af109..d39ae7b 100644 --- a/tests/e2e/rspay_test.go +++ b/tests/e2e/rspay_test.go @@ -10,13 +10,19 @@ import ( "testing" ) -func TestGetAccount(t *testing.T) { +func TestPostWalletRspay(t *testing.T) { jwtUtil := helpers.InitializeJWT() t.Run("rspay", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + req := struct { + Money float32 + }{ + Money: 100, + } + assert.NotPanics(t, func() { token, tokenErr := jwtUtil.Create("6597babdd1ba7e2dbd32d7e3") if isNoError := assert.NoError(t, tokenErr); !isNoError { @@ -26,6 +32,7 @@ func TestGetAccount(t *testing.T) { response, err := client.Post[interface{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{ URL: "http://localhost:8082/wallet/rspay", Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)}, + Body: req, }) if isNoError := assert.NoError(t, err); !isNoError { return diff --git a/tests/e2e/сurrencies_test.go b/tests/e2e/сurrencies_test.go index 3e1e83b..840849c 100644 --- a/tests/e2e/сurrencies_test.go +++ b/tests/e2e/сurrencies_test.go @@ -7,17 +7,24 @@ import ( "net/http" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client" + "penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers" "testing" ) func TestCurrencies(t *testing.T) { + jwtUtil := helpers.InitializeJWT() t.Run("Получение текущих доступных курсов", func(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() assert.NotPanics(t, func() { + token, tokenErr := jwtUtil.Create("6597babdd1ba7e2dbd32d7e3") + if isNoError := assert.NoError(t, tokenErr); !isNoError { + return + } responseGetCurrencies, errCurrencies := client.Get[[]models.CurrencyList, models.ResponseErrorHTTP](ctx, &client.RequestSettings{ - URL: "http://localhost:8082/currencies", + URL: "http://localhost:8082/currencies", + Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)}, }) if isNoError := assert.NoError(t, errCurrencies); !isNoError { return diff --git a/tests/integration/logostat_test.go b/tests/integration/logostat_test.go index 7f81ef5..5884dd8 100644 --- a/tests/integration/logostat_test.go +++ b/tests/integration/logostat_test.go @@ -2,65 +2,57 @@ package integration import ( "context" - "github.com/gofiber/fiber/v2" "github.com/pioz/faker" - "go.uber.org/zap" - "log" - "net/http" - "net/http/httptest" - "penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo" - http2 "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" "strconv" - "testing" "time" ) -func TestLogostat(t *testing.T) { - logger, err := zap.NewProduction(zap.AddStacktrace(zap.DPanicLevel)) - if err != nil { - log.Fatalf("failed to init zap logger: %v", err) - } - ctx := context.Background() - mongoDB, err := mongo.Connect(ctx, &mongo.ConnectDeps{ - Configuration: &mongo.Configuration{ - Host: "localhost", - Port: "27020", - User: "test", - Password: "test", - Auth: "admin", - DatabaseName: "admin", - }, - Timeout: 10 * time.Second, - }) - - repoAc := repository.NewAccountRepository2(logger, mongoDB.Collection("accounts")) - repoHi := repository.NewHistoryRepository2(logger, mongoDB.Collection("histories")) - InsertToDB(ctx, repoAc, repoHi) - - api := http2.NewAPI2(logger, mongoDB, nil, nil, nil, nil) - - app := fiber.New() - req := httptest.NewRequest(http.MethodGet, "/", nil) - req.Header.Set("Content-Type", "application/json") - - requestBody := struct { - From int - Limit int - Page int - To int - }{ - From: 1713087258, - Limit: 10, - Page: 1, - To: 1713260058, - } - - req = req.WithContext(context.WithValue(req.Context(), "requestBody", requestBody)) - resp := httptest.NewRecorder() - -} +//func TestLogostat(t *testing.T) { +// logger, err := zap.NewProduction(zap.AddStacktrace(zap.DPanicLevel)) +// if err != nil { +// log.Fatalf("failed to init zap logger: %v", err) +// } +// ctx := context.Background() +// mongoDB, err := mongo.Connect(ctx, &mongo.ConnectDeps{ +// Configuration: &mongo.Configuration{ +// Host: "localhost", +// Port: "27020", +// User: "test", +// Password: "test", +// Auth: "admin", +// DatabaseName: "admin", +// }, +// Timeout: 10 * time.Second, +// }) +// +// repoAc := repository.NewAccountRepository2(logger, mongoDB.Collection("accounts")) +// repoHi := repository.NewHistoryRepository2(logger, mongoDB.Collection("histories")) +// InsertToDB(ctx, repoAc, repoHi) +// +// api := http2.NewAPI2(logger, mongoDB, nil, nil, nil, nil) +// +// app := fiber.New() +// req := httptest.NewRequest(http.MethodGet, "/", nil) +// req.Header.Set("Content-Type", "application/json") +// +// requestBody := struct { +// From int +// Limit int +// Page int +// To int +// }{ +// From: 1713087258, +// Limit: 10, +// Page: 1, +// To: 1713260058, +// } +// +// req = req.WithContext(context.WithValue(req.Context(), "requestBody", requestBody)) +// resp := httptest.NewRecorder() +// +//} func InsertToDB(ctx context.Context, acc repository.AccountRepository, history repository.HistoryRepository) { partner1 := "partner1" From 8d233d94eb27aeb00b6b4210ae989138f21b3db1 Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 20 May 2024 17:31:37 +0300 Subject: [PATCH 4/8] add extractors for userid and token --- internal/interface/controller/http/controllers.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/interface/controller/http/controllers.go b/internal/interface/controller/http/controllers.go index ea3443f..a3c9ed4 100644 --- a/internal/interface/controller/http/controllers.go +++ b/internal/interface/controller/http/controllers.go @@ -589,6 +589,7 @@ func (api *API2) GetHistory(ctx *fiber.Ctx) error { return api.noauth(ctx) } + userID = id } limit, err := strconv.ParseInt(limitStr, 10, 64) From 4d732f3d85dbb9f6e4de9c4c2fee707d90b42332 Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 20 May 2024 22:43:37 +0300 Subject: [PATCH 5/8] commented makefile oapicodegen --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ee7b40f..651506e 100644 --- a/Makefile +++ b/Makefile @@ -14,8 +14,8 @@ install: ## install all go dependencies generate: ## generate grpc proto for golang buf generate - oapi-codegen --config ./api/openapi/v1/api.yaml ./api/openapi/v1/openapi.yaml - oapi-codegen --config ./api/openapi/v1/models.yaml ./api/openapi/v1/openapi.yaml +# oapi-codegen --config ./api/openapi/v1/api.yaml ./api/openapi/v1/openapi.yaml +# oapi-codegen --config ./api/openapi/v1/models.yaml ./api/openapi/v1/openapi.yaml test: ## run all layers tests @make test.unit From c3c9b57f068e433f08919c103357cde498e7fbb2 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 21 May 2024 16:50:26 +0300 Subject: [PATCH 6/8] full reworked< range for type controllers and remove big api2 file, update init htp controllers --- go.mod | 6 +- go.sum | 12 +- internal/app/app.go | 20 +- internal/initialize/clients.go | 6 + internal/initialize/controllers.go | 83 +- .../controller/http/account/controllers.go | 215 ++++ .../controller/http/account/route.go | 18 + .../controller/http/cart/controllers.go | 273 +++++ .../interface/controller/http/cart/route.go | 13 + .../interface/controller/http/controllers.go | 1025 ----------------- .../controller/http/currency/controllers.go | 75 ++ .../controller/http/currency/route.go | 12 + .../controller/http/history/controllers.go | 383 ++++++ .../controller/http/history/route.go | 16 + .../interface/controller/http/middleware.go | 55 + internal/interface/controller/http/money.go | 152 --- internal/interface/controller/http/route.go | 58 +- .../controller/http/wallet/controllers.go | 314 +++++ .../interface/controller/http/wallet/route.go | 13 + internal/interface/repository/account.go | 15 - internal/interface/repository/currency.go | 15 - internal/interface/repository/history.go | 15 - internal/models/payment.go | 15 +- internal/server/grpc.go | 2 +- tests/integration/mail_test.go | 1 + tests/integration/promo_ltv_test.go | 5 +- 26 files changed, 1539 insertions(+), 1278 deletions(-) create mode 100644 internal/interface/controller/http/account/controllers.go create mode 100644 internal/interface/controller/http/account/route.go create mode 100644 internal/interface/controller/http/cart/controllers.go create mode 100644 internal/interface/controller/http/cart/route.go delete mode 100644 internal/interface/controller/http/controllers.go create mode 100644 internal/interface/controller/http/currency/controllers.go create mode 100644 internal/interface/controller/http/currency/route.go create mode 100644 internal/interface/controller/http/history/controllers.go create mode 100644 internal/interface/controller/http/history/route.go create mode 100644 internal/interface/controller/http/middleware.go delete mode 100644 internal/interface/controller/http/money.go create mode 100644 internal/interface/controller/http/wallet/controllers.go create mode 100644 internal/interface/controller/http/wallet/route.go diff --git a/go.mod b/go.mod index fef5863..659bfcd 100644 --- a/go.mod +++ b/go.mod @@ -18,9 +18,9 @@ require ( go.uber.org/zap v1.27.0 google.golang.org/genproto/googleapis/api v0.0.0-20240221002015-b0ce06bbee7c google.golang.org/grpc v1.62.0 - google.golang.org/protobuf v1.32.0 + google.golang.org/protobuf v1.33.0 penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6 - penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240412164014-6ce70d76fedc + penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240520145524-451212248881 ) require ( @@ -51,7 +51,7 @@ require ( github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.20.0 // indirect golang.org/x/net v0.21.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.17.0 // indirect diff --git a/go.sum b/go.sum index 46e61ab..ff9e388 100644 --- a/go.sum +++ b/go.sum @@ -144,8 +144,8 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -249,8 +249,8 @@ google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -266,5 +266,5 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6 h1:oV+/HNX+JPoQ3/GUx08hio7d45WpY0AMGrFs7j70QlA= penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240223054633-6cb3d5ce45b6/go.mod h1:lTmpjry+8evVkXWbEC+WMOELcFkRD1lFMc7J09mOndM= -penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240412164014-6ce70d76fedc h1:B9X8pOrqWPGbWZNXSJEUk/8GWeBDGQmMKgQ0F+PSliQ= -penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240412164014-6ce70d76fedc/go.mod h1:/DcyAjBh41IbomuDu5QzhL9flZW6lWO3ZAEbUXKobk0= +penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240520145524-451212248881 h1:U1/WGQdwZsmrV/ta7Uqm13Dg07IPN/5omS8gzBJYZv4= +penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240520145524-451212248881/go.mod h1:oRyhT55ctjqp/7ZxIzkR7OsQ7T/NLibsfrbb7Ytns64= diff --git a/internal/app/app.go b/internal/app/app.go index ca27f53..cf332e2 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -81,6 +81,7 @@ func Run(config *models.Config, logger *zap.Logger) (appErr error) { VerificationURL: &config.Service.VerificationMicroservice.URL, TemplategenURL: &config.Service.TemplategenMicroserviceURL.URL, MailClient: &config.Service.Mail, + CodewordServiceHost: &config.Service.CodewordMicroservice, }) repositories := initialize.NewRepositories(initialize.RepositoriesDeps{ @@ -96,27 +97,38 @@ func Run(config *models.Config, logger *zap.Logger) (appErr error) { Brokers: brokers, }) - controllers := initialize.NewControllers(initialize.ControllersDeps{ + rpcControllers := initialize.NewRpcControllers(initialize.RpcControllersDeps{ Logger: logger, Services: services, }) encrypt := qutils.NewEncrypt(config.Service.PubKey, config.Service.PrivKey) + middleWare := http.NewMiddleWare(logger) - api := http.NewAPI2(logger, mongoDB, config, brokers.TariffConsumer, brokers.TariffProducer, encrypt) + httpControllers := initialize.NewHttpControllers(initialize.HttpControllersDeps{ + Logger: logger, + Encrypt: encrypt, + Producer: brokers.TariffProducer, + GRPC: &config.GRPC, + Repositories: repositories, + Clients: clients, + MiddleWare: middleWare, + }) serverHTTP := server.NewServer(server.ServerConfig{ Logger: logger, - Controllers: []server.Controller{api}, + Controllers: []server.Controller{httpControllers.CurrencyController, httpControllers.HistoryController, httpControllers.CartController, httpControllers.WalletController, httpControllers.AccountController}, JWTConfig: &config.Service.JWT, }) + serverHTTP.ListRoutes() + serverGRPC, grpcErr := server.NewGRPC(server.DepsGRPC{Logger: logger}) if grpcErr != nil { return grpcErr.Wrap("failed to init grpc server") } - serverGRPC.Register(controllers) + serverGRPC.Register(rpcControllers) go func() { if err := serverHTTP.Start(config.HTTP.Host + ":" + config.HTTP.Port); err != nil { diff --git a/internal/initialize/clients.go b/internal/initialize/clients.go index 42b6e35..b3de905 100644 --- a/internal/initialize/clients.go +++ b/internal/initialize/clients.go @@ -17,6 +17,7 @@ type ClientsDeps struct { VerificationURL *models.VerificationMicroserviceURL TemplategenURL *models.TemplategenMicroserviceURL MailClient *models.MailConfiguration + CodewordServiceHost *models.CodewordMicroserviceConfiguration } type Clients struct { @@ -28,6 +29,7 @@ type Clients struct { VerificationClient *client.VerificationClient TemplateClient *client.TemplateClient MailClient *client.MailClient + CodewordClient *client.CodewordClient } func NewClients(deps ClientsDeps) *Clients { @@ -73,5 +75,9 @@ func NewClients(deps ClientsDeps) *Clients { FiberClient: fiber.AcquireClient(), MailAddress: deps.MailClient.MailAddress, }), + CodewordClient: client.NewCodewordClient(client.CodewordClientDeps{ + Logger: deps.Logger, + CodewordServiceHost: deps.CodewordServiceHost.HostGRPC, + }), } } diff --git a/internal/initialize/controllers.go b/internal/initialize/controllers.go index 7d538cc..ec40739 100644 --- a/internal/initialize/controllers.go +++ b/internal/initialize/controllers.go @@ -2,22 +2,31 @@ package initialize import ( "go.uber.org/zap" + qutils "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/utils" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/broker/tariff" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/grpc/customer" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/grpc/payment" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http/account" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http/cart" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http/currency" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http/history" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http/wallet" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" ) -type ControllersDeps struct { +type RpcControllersDeps struct { Logger *zap.Logger Services *Services } -type Controllers struct { +type RpcControllers struct { PaymentController *payment.Controller CustomerController *customer.Controller } -func NewControllers(deps ControllersDeps) *Controllers { - return &Controllers{ +func NewRpcControllers(deps RpcControllersDeps) *RpcControllers { + return &RpcControllers{ PaymentController: payment.New(payment.Deps{ Logger: deps.Logger, PaymentCallbackService: deps.Services.PaymentCallbackService, @@ -28,3 +37,69 @@ func NewControllers(deps ControllersDeps) *Controllers { }), } } + +type HttpControllersDeps struct { + Encrypt *qutils.Encrypt + Producer *tariff.Producer + GRPC *models.ConfigurationGRPC + MiddleWare *http.MiddleWare + Logger *zap.Logger + Repositories *Repositories + Clients *Clients +} + +type HttpController struct { + AccountController *account.AccountController + CartController *cart.CartController + HistoryController *history.HistoryController + WalletController *wallet.WalletController + CurrencyController *currency.CurrencyController +} + +func NewHttpControllers(deps HttpControllersDeps) *HttpController { + return &HttpController{ + AccountController: account.NewAccountController(account.Deps{ + MiddleWare: deps.MiddleWare, + AccountRepo: deps.Repositories.AccountRepository, + Logger: deps.Logger, + Encrypt: deps.Encrypt, + AuthClient: deps.Clients.AuthClient, + }), + CartController: cart.NewCartController(cart.Deps{ + MiddleWare: deps.MiddleWare, + Logger: deps.Logger, + AccountRepo: deps.Repositories.AccountRepository, + HistoryRepo: deps.Repositories.HistoryRepository, + HubAdminClient: deps.Clients.HubadminClient, + DiscountClient: deps.Clients.DiscountClient, + CurrencyClient: deps.Clients.CurrencyClient, + Producer: deps.Producer, + }), + HistoryController: history.NewHistoryController(history.Deps{ + MiddleWare: deps.MiddleWare, + HistoryRepo: deps.Repositories.HistoryRepository, + AccountRepo: deps.Repositories.AccountRepository, + VerifyClient: deps.Clients.VerificationClient, + AuthClient: deps.Clients.AuthClient, + TemplateClient: deps.Clients.TemplateClient, + CodewordClient: deps.Clients.CodewordClient, + Logger: deps.Logger, + }), + WalletController: wallet.NewWalletController(wallet.Deps{ + MiddleWare: deps.MiddleWare, + AuthClient: deps.Clients.AuthClient, + PaymentClient: deps.Clients.PaymentClient, + GRPC: deps.GRPC, + AccountRepo: deps.Repositories.AccountRepository, + CurrencyClient: deps.Clients.CurrencyClient, + VerifyClient: deps.Clients.VerificationClient, + MailClient: deps.Clients.MailClient, + Logger: deps.Logger, + }), + CurrencyController: currency.NewCurrencyController(currency.Deps{ + CurrencyRepo: deps.Repositories.CurrencyRepository, + MiddleWare: deps.MiddleWare, + Logger: deps.Logger, + }), + } +} diff --git a/internal/interface/controller/http/account/controllers.go b/internal/interface/controller/http/account/controllers.go new file mode 100644 index 0000000..3453764 --- /dev/null +++ b/internal/interface/controller/http/account/controllers.go @@ -0,0 +1,215 @@ +package account + +import ( + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" + "math" + qutils "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/utils" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" + "strconv" +) + +type Deps struct { + MiddleWare *http.MiddleWare + AccountRepo *repository.AccountRepository + Logger *zap.Logger + Encrypt *qutils.Encrypt + AuthClient *client.AuthClient +} + +type AccountController struct { + middleWare *http.MiddleWare + accountRepo *repository.AccountRepository + logger *zap.Logger + encrypt *qutils.Encrypt + authClient *client.AuthClient +} + +func NewAccountController(deps Deps) *AccountController { + return &AccountController{ + middleWare: deps.MiddleWare, + accountRepo: deps.AccountRepo, + logger: deps.Logger, + encrypt: deps.Encrypt, + authClient: deps.AuthClient, + } +} + +func (receiver *AccountController) DeleteAccount(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + account, err := receiver.accountRepo.Remove(ctx.Context(), userID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(account) +} + +func (receiver *AccountController) ChangeAccount(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + var request models.Name + if err := ctx.BodyParser(&request); err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind json", err) + } + + account, err := receiver.accountRepo.UpdateName(ctx.Context(), userID, &request) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(account) +} + +func (receiver *AccountController) SetAccountVerificationStatus(ctx *fiber.Ctx) error { + userID := ctx.Params("userId") + if userID == "" { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") + } + + var request models.SetAccountStatus + if err := ctx.BodyParser(&request); err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind json", err) + } + + account, err := receiver.accountRepo.SetStatus(ctx.Context(), userID, request.Status) + if err != nil { + receiver.logger.Error("failed to set status on of ", zap.Error(err)) + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(account) +} + +func (receiver *AccountController) GetAccount(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + account, err := receiver.accountRepo.FindByUserID(ctx.Context(), userID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(account) +} + +func (receiver *AccountController) AddAccount(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + var er error + + quizFrom := ctx.Cookies("quizFrom") + quizUser := ctx.Cookies("quizUser") + if quizUser != "" { + quizUser, er = receiver.encrypt.DecryptStr([]byte(quizUser)) + if er != nil { + return receiver.middleWare.ErrorOld(ctx, er) + } + } + + account, err := receiver.accountRepo.FindByUserID(ctx.Context(), userID) + if err != nil && err.Type() != errors.ErrNotFound { + return receiver.middleWare.ErrorOld(ctx, err) + } + + if account != nil { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "account exists") + } + + user, err := receiver.authClient.GetUser(ctx.Context(), userID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + account, err = receiver.accountRepo.Insert(ctx.Context(), &models.Account{ + UserID: user.ID, Wallet: models.Wallet{Currency: models.DefaultCurrency}, From: quizFrom, Partner: quizUser}) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(account) +} + +func (receiver *AccountController) DeleteDirectAccount(ctx *fiber.Ctx) error { + userID := ctx.Params("userId") + if userID == "" { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") + } + + account, err := receiver.accountRepo.Remove(ctx.Context(), userID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(account) +} + +func (receiver *AccountController) GetDirectAccount(ctx *fiber.Ctx) error { + userID := ctx.Params("userId") + if userID == "" { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") + } + + account, err := receiver.accountRepo.FindByUserID(ctx.Context(), userID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(account) +} + +func (receiver *AccountController) PaginationAccounts(ctx *fiber.Ctx) error { + pageStr := ctx.Query("page", "1") + limitStr := ctx.Query("limit", "100") + + page, err := strconv.ParseInt(pageStr, 10, 64) + if err != nil || page < 1 { + page = 1 + } + limit, err := strconv.ParseInt(limitStr, 10, 64) + if err != nil || limit < 1 { + limit = models.DefaultLimit + } else { + limit = int64(math.Min(float64(limit), float64(models.DefaultLimit))) + } + + count, err := receiver.accountRepo.CountAll(ctx.Context()) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + if count == 0 { + response := models.PaginationResponse[models.Account]{TotalPages: 0, Records: []models.Account{}} + return ctx.Status(fiber.StatusOK).JSON(response) + } + + totalPages := int64(math.Ceil(float64(count) / float64(limit))) + + accounts, err := receiver.accountRepo.FindMany(ctx.Context(), page, limit) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + response := models.PaginationResponse[models.Account]{ + TotalPages: totalPages, + Records: accounts, + } + + return ctx.Status(fiber.StatusOK).JSON(response) +} diff --git a/internal/interface/controller/http/account/route.go b/internal/interface/controller/http/account/route.go new file mode 100644 index 0000000..5a4bfec --- /dev/null +++ b/internal/interface/controller/http/account/route.go @@ -0,0 +1,18 @@ +package account + +import "github.com/gofiber/fiber/v2" + +func (receiver *AccountController) Register(router fiber.Router) { + router.Delete("/account", receiver.DeleteAccount) + router.Get("/account", receiver.GetAccount) + router.Patch("/account", receiver.ChangeAccount) + router.Post("/account", receiver.AddAccount) + router.Delete("/account/:userId", receiver.DeleteDirectAccount) + router.Get("/account/:userId", receiver.GetDirectAccount) + router.Patch("/account/:userId", receiver.SetAccountVerificationStatus) + router.Get("/accounts", receiver.PaginationAccounts) +} + +func (receiver *AccountController) Name() string { + return "" +} diff --git a/internal/interface/controller/http/cart/controllers.go b/internal/interface/controller/http/cart/controllers.go new file mode 100644 index 0000000..018def2 --- /dev/null +++ b/internal/interface/controller/http/cart/controllers.go @@ -0,0 +1,273 @@ +package cart + +import ( + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" + "google.golang.org/protobuf/types/known/timestamppb" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/broker/tariff" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/discount" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils/transfer" + "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate" + "sync" + "time" +) + +type Deps struct { + MiddleWare *http.MiddleWare + Logger *zap.Logger + AccountRepo *repository.AccountRepository + HistoryRepo *repository.HistoryRepository + HubAdminClient *client.HubadminClient + DiscountClient *client.DiscountClient + CurrencyClient *client.CurrencyClient + Producer *tariff.Producer +} + +type CartController struct { + middleWare *http.MiddleWare + logger *zap.Logger + accountRepo *repository.AccountRepository + historyRepo *repository.HistoryRepository + hubAdminClient *client.HubadminClient + discountClient *client.DiscountClient + currencyClient *client.CurrencyClient + producer *tariff.Producer +} + +func NewCartController(deps Deps) *CartController { + return &CartController{ + middleWare: deps.MiddleWare, + logger: deps.Logger, + accountRepo: deps.AccountRepo, + historyRepo: deps.HistoryRepo, + hubAdminClient: deps.HubAdminClient, + discountClient: deps.DiscountClient, + currencyClient: deps.CurrencyClient, + producer: deps.Producer, + } +} + +func (receiver *CartController) RemoveFromCart(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + id := ctx.Query("id") + if id == "" { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "empty item id") + } + + cartItems, err := receiver.accountRepo.RemoveItemFromCart(ctx.Context(), userID, id) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(cartItems) +} + +func (receiver *CartController) Add2cart(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + token, ok := receiver.middleWare.ExtractToken(ctx) + if !ok || token == "" { + return receiver.middleWare.NoAuth(ctx) + } + + tariffID := ctx.Query("id") + if tariffID == "" { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "empty item id") + } + + tariff, err := receiver.hubAdminClient.GetTariff(ctx.Context(), token, tariffID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + if tariff == nil { + return receiver.middleWare.Error(ctx, fiber.StatusNotFound, "tariff not found") + } + + cartItems, err := receiver.accountRepo.AddItemToCart(ctx.Context(), userID, tariffID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(cartItems) +} + +func (receiver *CartController) PayCart(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + accessToken, ok := receiver.middleWare.ExtractToken(ctx) + if !ok || accessToken == "" { + return receiver.middleWare.NoAuth(ctx) + } + + account, err := receiver.accountRepo.FindByUserID(ctx.Context(), userID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + receiver.logger.Info("account for pay", zap.Any("acc", account)) + + tariffs, err := receiver.hubAdminClient.GetTariffs(ctx.Context(), accessToken, account.Cart) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + receiver.logger.Info("tariffs for pay", zap.Any("acc", tariffs)) + + tariffsAmount := utils.CalculateCartPurchasesAmount(tariffs) + + discountResponse, err := receiver.discountClient.Apply(ctx.Context(), &discount.ApplyDiscountRequest{ + UserInformation: &discount.UserInformation{ + ID: account.UserID, + Type: string(account.Status), + PurchasesAmount: uint64(account.Wallet.Spent), + CartPurchasesAmount: tariffsAmount, + }, + Products: transfer.TariffsToProductInformations(tariffs), + Date: timestamppb.New(time.Now()), + }) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + receiver.logger.Info("discountResponse for pay", zap.Any("acc", discount.ApplyDiscountRequest{ + UserInformation: &discount.UserInformation{ + ID: account.UserID, + Type: string(account.Status), + PurchasesAmount: uint64(account.Wallet.Spent), + CartPurchasesAmount: tariffsAmount, + }, + Products: transfer.TariffsToProductInformations(tariffs), + Date: timestamppb.New(time.Now()), + })) + + if account.Wallet.Money < int64(discountResponse.Price) { + return receiver.middleWare.Error(ctx, fiber.StatusPaymentRequired, "insufficient funds: %d", int64(discountResponse.Price)-account.Wallet.Money) + } + + for _, applied := range discountResponse.AppliedDiscounts { + if applied.Condition.User != nil && *applied.Condition.User != "" { + _, err := receiver.discountClient.DeleteDiscount(ctx.Context(), &discount.GetDiscountByIDRequest{ + ID: applied.ID, + }) + + if err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, "failed delete discount by id:%s", applied.ID) + } + } + } + + // WithdrawAccountWalletMoney + + request := models.WithdrawAccountWallet{ + Money: int64(discountResponse.Price), + Account: account, + } + + if validate.IsStringEmpty(request.Account.Wallet.Currency) { + request.Account.Wallet.Currency = models.InternalCurrencyKey + } + + var updatedAccount *models.Account + + if request.Account.Wallet.Currency == models.InternalCurrencyKey { + accountx, err := receiver.accountRepo.ChangeWallet(ctx.Context(), request.Account.UserID, &models.Wallet{ + Cash: request.Account.Wallet.Cash - request.Money, + Money: request.Account.Wallet.Money - request.Money, + Spent: request.Account.Wallet.Spent + request.Money, + PurchasesAmount: request.Account.Wallet.PurchasesAmount, + Currency: request.Account.Wallet.Currency, + }) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + updatedAccount = accountx + } else { + cash, err := receiver.currencyClient.Translate(ctx.Context(), &models.TranslateCurrency{ + Money: request.Money, + From: models.InternalCurrencyKey, + To: request.Account.Wallet.Currency, + }) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + accountx, err := receiver.accountRepo.ChangeWallet(ctx.Context(), request.Account.UserID, &models.Wallet{ + Cash: request.Account.Wallet.Cash - cash, + Money: request.Account.Wallet.Money - request.Money, + Spent: request.Account.Wallet.Spent + request.Money, + PurchasesAmount: request.Account.Wallet.PurchasesAmount, + Currency: request.Account.Wallet.Currency, + }) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + updatedAccount = accountx + } + + if _, err := receiver.historyRepo.Insert(ctx.Context(), &models.History{ + Key: models.CustomerHistoryKeyPayCart, + UserID: account.UserID, + Comment: "Успешная оплата корзины", + RawDetails: models.RawDetails{ + Tariffs: tariffs, + Price: int64(discountResponse.Price), + }, + }); err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + // TODO: обработать ошибки при отправке сообщений + + sendErrors := make([]errors.Error, 0) + waitGroup := sync.WaitGroup{} + mutex := sync.Mutex{} + + for _, tariff := range tariffs { + waitGroup.Add(1) + + go func(currentTariff models.Tariff) { + defer waitGroup.Done() + + if err := receiver.producer.Send(ctx.Context(), userID, ¤tTariff); err != nil { + mutex.Lock() + defer mutex.Unlock() + sendErrors = append(sendErrors, err) + } + }(tariff) + } + + waitGroup.Wait() + + if len(sendErrors) > 0 { + for _, err := range sendErrors { + receiver.logger.Error("failed to send tariffs to broker on of ", zap.Error(err)) + } + return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, "failed to send tariffs to broker") + } + + if _, err := receiver.accountRepo.ClearCart(ctx.Context(), account.UserID); err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + updatedAccount.Cart = []string{} + + return ctx.Status(fiber.StatusOK).JSON(updatedAccount) +} diff --git a/internal/interface/controller/http/cart/route.go b/internal/interface/controller/http/cart/route.go new file mode 100644 index 0000000..cd893bc --- /dev/null +++ b/internal/interface/controller/http/cart/route.go @@ -0,0 +1,13 @@ +package cart + +import "github.com/gofiber/fiber/v2" + +func (receiver *CartController) Register(router fiber.Router) { + router.Delete("/cart", receiver.RemoveFromCart) + router.Patch("/cart", receiver.Add2cart) + router.Post("/cart/pay", receiver.PayCart) +} + +func (receiver *CartController) Name() string { + return "" +} diff --git a/internal/interface/controller/http/controllers.go b/internal/interface/controller/http/controllers.go deleted file mode 100644 index a3c9ed4..0000000 --- a/internal/interface/controller/http/controllers.go +++ /dev/null @@ -1,1025 +0,0 @@ -package http - -import ( - "fmt" - "github.com/gofiber/fiber/v2" - "math" - "os" - codeword_rpc "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/codeword" - "strconv" - "sync" - "time" - - "go.mongodb.org/mongo-driver/mongo" - "go.uber.org/zap" - "google.golang.org/protobuf/types/known/timestamppb" - qutils "penahub.gitlab.yandexcloud.net/backend/quiz/common.git/utils" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/broker/tariff" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/discount" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils/transfer" - "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate" -) - -const defaultCurrency = "RUB" // TODO move - -type API2 struct { - logger *zap.Logger - history repository.HistoryRepository - account repository.AccountRepository - currency repository.CurrencyRepository - producer *tariff.Producer - consumer *tariff.Consumer - clients clients - grpc models.ConfigurationGRPC - encrypt *qutils.Encrypt -} - -type clients struct { - auth *client.AuthClient - hubadmin *client.HubadminClient - currency *client.CurrencyClient - discount *client.DiscountClient - payment *client.PaymentClient - verify *client.VerificationClient - template *client.TemplateClient - mail *client.MailClient - codeword *client.CodewordClient -} - -func NewAPI2(logger *zap.Logger, db *mongo.Database, config *models.Config, consumer *tariff.Consumer, producer *tariff.Producer, encrypt *qutils.Encrypt) *API2 { - return &API2{ - logger: logger, - history: repository.NewHistoryRepository2(logger, db.Collection("histories")), - currency: repository.NewCurrencyRepository2(logger, db.Collection("currency_lists")), - account: repository.NewAccountRepository2(logger, db.Collection("accounts")), - consumer: consumer, - producer: producer, - encrypt: encrypt, - grpc: config.GRPC, - clients: clients{ - auth: client.NewAuthClient(client.AuthClientDeps{Logger: logger, URLs: &config.Service.AuthMicroservice.URL}), - hubadmin: client.NewHubadminClient(client.HubadminClientDeps{Logger: logger, URLs: &config.Service.HubadminMicroservice.URL}), - currency: client.NewCurrencyClient(client.CurrencyClientDeps{Logger: logger, URLs: &config.Service.CurrencyMicroservice.URL}), - discount: client.NewDiscountClient(client.DiscountClientDeps{Logger: logger, DiscountServiceHost: config.Service.DiscountMicroservice.HostGRPC}), - payment: client.NewPaymentClient(client.PaymentClientDeps{Logger: logger, PaymentServiceHost: config.Service.PaymentMicroservice.HostGRPC}), - verify: client.NewVerificationClient(client.VerificationClientDeps{Logger: logger, URLs: &config.Service.VerificationMicroservice.URL}), - template: client.NewTemplateClient(client.TemplateClientDeps{Logger: logger, URLs: &config.Service.TemplategenMicroserviceURL.URL}), - mail: client.NewMailClient(client.MailClientDeps{Logger: logger, - ApiUrl: config.Service.Mail.ApiUrl, - Sender: config.Service.Mail.Sender, - Auth: &models.PlainAuth{ - Identity: config.Service.Mail.Auth.Identity, - Username: config.Service.Mail.Auth.Username, - Password: config.Service.Mail.Auth.Password, - }, - ApiKey: config.Service.Mail.ApiKey, - FiberClient: fiber.AcquireClient(), - MailAddress: config.Service.Mail.MailAddress, - }), - codeword: client.NewCodewordClient(client.CodewordClientDeps{Logger: logger, CodewordServiceHost: config.Service.CodewordMicroservice.HostGRPC}), - }, - } -} - -func (api *API2) error(ctx *fiber.Ctx, status int, message string, rest ...any) error { - if len(rest) > 0 { - message = fmt.Sprintf(message, rest...) - } - api.logger.Error(message) - return ctx.Status(status).JSON(models.ResponseErrorHTTP{ - StatusCode: status, - Message: message, - }) -} - -func (api *API2) errorOld(ctx *fiber.Ctx, err error) error { - api.logger.Error("error:", zap.Error(err)) - return ctx.Status(fiber.StatusInternalServerError).JSON(models.ResponseErrorHTTP{ - StatusCode: fiber.StatusInternalServerError, - Message: err.Error(), - }) -} - -func (api *API2) noauth(ctx *fiber.Ctx) error { - return api.error(ctx, fiber.StatusUnauthorized, "failed to get jwt payload") -} - -func (api *API2) extractUserID(ctx *fiber.Ctx) (string, bool) { - id, ok := ctx.Context().UserValue(models.AuthJWTDecodedUserIDKey).(string) - return id, ok -} - -func (api *API2) extractToken(ctx *fiber.Ctx) (string, bool) { - token, ok := ctx.Context().UserValue(models.AuthJWTDecodedAccessTokenKey).(string) - return token, ok -} - -// Health - -func (api *API2) GetHealth(ctx *fiber.Ctx) error { - return ctx.Status(fiber.StatusOK).SendString("OK") -} - -// Account - -func (api *API2) DeleteAccount(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - account, err := api.account.Remove(ctx.Context(), userID) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(account) -} - -func (api *API2) ChangeAccount(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - var request models.Name - if err := ctx.BodyParser(&request); err != nil { - return api.error(ctx, fiber.StatusBadRequest, "failed to bind json", err) - } - - account, err := api.account.UpdateName(ctx.Context(), userID, &request) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(account) -} - -func (api *API2) SetAccountVerificationStatus(ctx *fiber.Ctx) error { - userID := ctx.Params("userId") - if userID == "" { - return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") - } - - var request models.SetAccountStatus - if err := ctx.BodyParser(&request); err != nil { - return api.error(ctx, fiber.StatusBadRequest, "failed to bind json", err) - } - - account, err := api.account.SetStatus(ctx.Context(), userID, request.Status) - if err != nil { - api.logger.Error("failed to set status on of ", zap.Error(err)) - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(account) -} - -func (api *API2) GetAccount(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - account, err := api.account.FindByUserID(ctx.Context(), userID) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(account) -} - -func (api *API2) AddAccount(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - var er error - - quizFrom := ctx.Cookies("quizFrom") - quizUser := ctx.Cookies("quizUser") - if quizUser != "" { - quizUser, er = api.encrypt.DecryptStr([]byte(quizUser)) - if er != nil { - return api.errorOld(ctx, er) - } - } - - account, err := api.account.FindByUserID(ctx.Context(), userID) - if err != nil && err.Type() != errors.ErrNotFound { - return api.errorOld(ctx, err) - } - - if account != nil { - return api.error(ctx, fiber.StatusBadRequest, "account exists") - } - - user, err := api.clients.auth.GetUser(ctx.Context(), userID) - if err != nil { - return api.errorOld(ctx, err) - } - - account, err = api.account.Insert(ctx.Context(), &models.Account{ - UserID: user.ID, Wallet: models.Wallet{Currency: defaultCurrency}, From: quizFrom, Partner: quizUser}) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(account) -} - -func (api *API2) DeleteDirectAccount(ctx *fiber.Ctx) error { - userID := ctx.Params("userId") - if userID == "" { - return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") - } - - account, err := api.account.Remove(ctx.Context(), userID) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(account) -} - -func (api *API2) GetDirectAccount(ctx *fiber.Ctx) error { - userID := ctx.Params("userId") - if userID == "" { - return api.error(ctx, fiber.StatusBadRequest, "invalid format for parameter userId") - } - - account, err := api.account.FindByUserID(ctx.Context(), userID) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(account) -} - -func (api *API2) PaginationAccounts(ctx *fiber.Ctx) error { - pageStr := ctx.Query("page", "1") - limitStr := ctx.Query("limit", "100") - - page, err := strconv.ParseInt(pageStr, 10, 64) - if err != nil || page < 1 { - page = 1 - } - limit, err := strconv.ParseInt(limitStr, 10, 64) - if err != nil || limit < 1 { - limit = models.DefaultLimit - } else { - limit = int64(math.Min(float64(limit), float64(models.DefaultLimit))) - } - - count, err := api.account.CountAll(ctx.Context()) - if err != nil { - return api.errorOld(ctx, err) - } - - if count == 0 { - response := models.PaginationResponse[models.Account]{TotalPages: 0, Records: []models.Account{}} - return ctx.Status(fiber.StatusOK).JSON(response) - } - - totalPages := int64(math.Ceil(float64(count) / float64(limit))) - - accounts, err := api.account.FindMany(ctx.Context(), page, limit) - if err != nil { - return api.errorOld(ctx, err) - } - - response := models.PaginationResponse[models.Account]{ - TotalPages: totalPages, - Records: accounts, - } - - return ctx.Status(fiber.StatusOK).JSON(response) -} - -// Cart - -func (api *API2) RemoveFromCart(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - id := ctx.Query("id") - if id == "" { - return api.error(ctx, fiber.StatusBadRequest, "empty item id") - } - - cartItems, err := api.account.RemoveItemFromCart(ctx.Context(), userID, id) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(cartItems) -} - -func (api *API2) Add2cart(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - token, ok := api.extractToken(ctx) - if !ok || token == "" { - return api.noauth(ctx) - } - - tariffID := ctx.Query("id") - if tariffID == "" { - return api.error(ctx, fiber.StatusBadRequest, "empty item id") - } - - tariff, err := api.clients.hubadmin.GetTariff(ctx.Context(), token, tariffID) - if err != nil { - return api.errorOld(ctx, err) - } - - if tariff == nil { - return api.error(ctx, fiber.StatusNotFound, "tariff not found") - } - - cartItems, err := api.account.AddItemToCart(ctx.Context(), userID, tariffID) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(cartItems) -} - -func (api *API2) PayCart(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - accessToken, ok := api.extractToken(ctx) - if !ok || accessToken == "" { - return api.noauth(ctx) - } - - account, err := api.account.FindByUserID(ctx.Context(), userID) - if err != nil { - return api.errorOld(ctx, err) - } - - api.logger.Info("account for pay", zap.Any("acc", account)) - - tariffs, err := api.clients.hubadmin.GetTariffs(ctx.Context(), accessToken, account.Cart) - if err != nil { - return api.errorOld(ctx, err) - } - - api.logger.Info("tariffs for pay", zap.Any("acc", tariffs)) - - tariffsAmount := utils.CalculateCartPurchasesAmount(tariffs) - - discountResponse, err := api.clients.discount.Apply(ctx.Context(), &discount.ApplyDiscountRequest{ - UserInformation: &discount.UserInformation{ - ID: account.UserID, - Type: string(account.Status), - PurchasesAmount: uint64(account.Wallet.Spent), - CartPurchasesAmount: tariffsAmount, - }, - Products: transfer.TariffsToProductInformations(tariffs), - Date: timestamppb.New(time.Now()), - }) - if err != nil { - return api.errorOld(ctx, err) - } - - api.logger.Info("discountResponse for pay", zap.Any("acc", discount.ApplyDiscountRequest{ - UserInformation: &discount.UserInformation{ - ID: account.UserID, - Type: string(account.Status), - PurchasesAmount: uint64(account.Wallet.Spent), - CartPurchasesAmount: tariffsAmount, - }, - Products: transfer.TariffsToProductInformations(tariffs), - Date: timestamppb.New(time.Now()), - })) - - if account.Wallet.Money < int64(discountResponse.Price) { - return api.error(ctx, fiber.StatusPaymentRequired, "insufficient funds: %d", int64(discountResponse.Price)-account.Wallet.Money) - } - - for _, applied := range discountResponse.AppliedDiscounts { - if applied.Condition.User != nil && *applied.Condition.User != "" { - _, err := api.clients.discount.DeleteDiscount(ctx.Context(), &discount.GetDiscountByIDRequest{ - ID: applied.ID, - }) - - if err != nil { - return api.error(ctx, fiber.StatusInternalServerError, "failed delete discount by id:%s", applied.ID) - } - } - } - - // WithdrawAccountWalletMoney - - request := models.WithdrawAccountWallet{ - Money: int64(discountResponse.Price), - Account: account, - } - - if validate.IsStringEmpty(request.Account.Wallet.Currency) { - request.Account.Wallet.Currency = models.InternalCurrencyKey - } - - var updatedAccount *models.Account - - if request.Account.Wallet.Currency == models.InternalCurrencyKey { - accountx, err := api.account.ChangeWallet(ctx.Context(), request.Account.UserID, &models.Wallet{ - Cash: request.Account.Wallet.Cash - request.Money, - Money: request.Account.Wallet.Money - request.Money, - Spent: request.Account.Wallet.Spent + request.Money, - PurchasesAmount: request.Account.Wallet.PurchasesAmount, - Currency: request.Account.Wallet.Currency, - }) - if err != nil { - return api.errorOld(ctx, err) - } - updatedAccount = accountx - } else { - cash, err := api.clients.currency.Translate(ctx.Context(), &models.TranslateCurrency{ - Money: request.Money, - From: models.InternalCurrencyKey, - To: request.Account.Wallet.Currency, - }) - if err != nil { - return api.errorOld(ctx, err) - } - - accountx, err := api.account.ChangeWallet(ctx.Context(), request.Account.UserID, &models.Wallet{ - Cash: request.Account.Wallet.Cash - cash, - Money: request.Account.Wallet.Money - request.Money, - Spent: request.Account.Wallet.Spent + request.Money, - PurchasesAmount: request.Account.Wallet.PurchasesAmount, - Currency: request.Account.Wallet.Currency, - }) - if err != nil { - return api.errorOld(ctx, err) - } - - updatedAccount = accountx - } - - if _, err := api.history.Insert(ctx.Context(), &models.History{ - Key: models.CustomerHistoryKeyPayCart, - UserID: account.UserID, - Comment: "Успешная оплата корзины", - RawDetails: models.RawDetails{ - Tariffs: tariffs, - Price: int64(discountResponse.Price), - }, - }); err != nil { - return api.errorOld(ctx, err) - } - - // TODO: обработать ошибки при отправке сообщений - - sendErrors := make([]errors.Error, 0) - waitGroup := sync.WaitGroup{} - mutex := sync.Mutex{} - - for _, tariff := range tariffs { - waitGroup.Add(1) - - go func(currentTariff models.Tariff) { - defer waitGroup.Done() - - if err := api.producer.Send(ctx.Context(), userID, ¤tTariff); err != nil { - mutex.Lock() - defer mutex.Unlock() - sendErrors = append(sendErrors, err) - } - }(tariff) - } - - waitGroup.Wait() - - if len(sendErrors) > 0 { - for _, err := range sendErrors { - api.logger.Error("failed to send tariffs to broker on of ", zap.Error(err)) - } - return api.error(ctx, fiber.StatusInternalServerError, "failed to send tariffs to broker") - } - - if _, err := api.account.ClearCart(ctx.Context(), account.UserID); err != nil { - return api.errorOld(ctx, err) - } - - updatedAccount.Cart = []string{} - - return ctx.Status(fiber.StatusOK).JSON(updatedAccount) -} - -// Currency - -func (api *API2) GetCurrencies(ctx *fiber.Ctx) error { - currencyList, err := api.currency.FindCurrenciesList(ctx.Context(), models.DefaultCurrencyListName) - if err != nil && err.Type() != errors.ErrNotFound { - return api.errorOld(ctx, err) - } - - if err != nil && err.Type() == errors.ErrNotFound { - return ctx.Status(fiber.StatusOK).JSON([]string{}) - } - - return ctx.Status(fiber.StatusOK).JSON(currencyList) -} - -func (api *API2) UpdateCurrencies(ctx *fiber.Ctx) error { - var req struct { - items []string - } - if err := ctx.BodyParser(&req); err != nil { - return api.error(ctx, fiber.StatusBadRequest, "failed to bind currencies") - } - - currencies := req.items - - currencyList, err := api.currency.ReplaceCurrencies(ctx.Context(), &models.CurrencyList{ - Name: models.DefaultCurrencyListName, - Currencies: currencies, - }) - if err != nil && err.Type() != errors.ErrNotFound { - return api.errorOld(ctx, err) - } - - if err != nil && err.Type() == errors.ErrNotFound { - newCurrencyList, err := api.currency.Insert(ctx.Context(), &models.CurrencyList{ - Name: models.DefaultCurrencyListName, - Currencies: currencies, - }) - if err != nil && err.Type() != errors.ErrNotFound { - return api.errorOld(ctx, err) - } - return ctx.Status(fiber.StatusOK).JSON(newCurrencyList.Currencies) - } - - return ctx.Status(fiber.StatusOK).JSON(currencyList.Currencies) -} - -// History - -func (api *API2) GetHistory(ctx *fiber.Ctx) error { - var userID string - - pageStr := ctx.Query("page") - limitStr := ctx.Query("limit") - tipe := ctx.Query("type") - accountID := ctx.Query("accountID") - - if accountID != "" { - userID = accountID - } else { - id, ok := api.extractUserID(ctx) - if !ok || id == "" { - return api.noauth(ctx) - } - - userID = id - } - - limit, err := strconv.ParseInt(limitStr, 10, 64) - if err != nil { - return api.error(ctx, fiber.StatusBadRequest, "invalid limit format") - } - - page, err := strconv.ParseInt(pageStr, 10, 64) - if err != nil { - return api.error(ctx, fiber.StatusBadRequest, "invalid page format") - } - - dto := &history.GetHistories{ - UserID: userID, - Type: &tipe, - Pagination: &models.Pagination{ - Page: page, - Limit: limit, - }, - } - - count, err := api.history.CountAll(ctx.Context(), dto) - if err != nil { - return api.errorOld(ctx, err) - } - - if count == 0 { - returnHistories := models.PaginationResponse[models.History]{TotalPages: 0, Records: []models.History{}} - return ctx.Status(fiber.StatusOK).JSON(returnHistories) - } - - totalPages := int64(math.Ceil(float64(count) / float64(dto.Pagination.Limit))) - - histories, err := api.history.FindMany(ctx.Context(), dto) - if err != nil { - return api.errorOld(ctx, err) - } - - returnHistories := models.PaginationResponse[models.History]{ - TotalPages: totalPages, - Records: histories, - } - - return ctx.Status(fiber.StatusOK).JSON(returnHistories) -} - -// Wallet - -func (api *API2) RequestMoney(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - var request models.GetPaymentLinkBody - if err := ctx.BodyParser(&request); err != nil { - return api.error(ctx, fiber.StatusBadRequest, "failed to bind payment link") - } - - if err := utils.ValidateGetPaymentLinkBody(&request); err != nil { - return api.errorOld(ctx, err) - } - - link, err := api.GetPaymentLink(ctx.Context(), &models.GetPaymentLinkRequest{ - Body: &request, - UserID: userID, - ClientIP: ctx.IP(), - }) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(&models.GetPaymentLinkResponse{Link: link}) -} - -func (api *API2) ChangeCurrency(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - var request models.ChangeCurrency - if err := ctx.BodyParser(&request); err != nil { - return api.error(ctx, fiber.StatusBadRequest, "failed to bind currency") - } - - if validate.IsStringEmpty(request.Currency) { - return api.error(ctx, fiber.StatusBadRequest, "empty currency") - } - - currency := request.Currency - account, err := api.account.FindByUserID(ctx.Context(), userID) - if err != nil { - return api.errorOld(ctx, err) - } - - cash, err := api.clients.currency.Translate(ctx.Context(), &models.TranslateCurrency{ - Money: account.Wallet.Cash, - From: account.Wallet.Currency, - To: currency, - }) - if err != nil { - return api.errorOld(ctx, err) - } - - updatedAccount, err := api.account.ChangeWallet(ctx.Context(), account.UserID, &models.Wallet{ - Cash: cash, - Currency: currency, - Money: account.Wallet.Money, - }) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(updatedAccount) -} - -func (api *API2) CalculateLTV(ctx *fiber.Ctx) error { - var req struct { - From int64 `json:"from"` - To int64 `json:"to"` - } - - if err := ctx.BodyParser(&req); err != nil { - api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") - } - - if req.From > req.To && req.To != 0 { - api.logger.Error("From timestamp must be less than To timestamp unless To is 0") - return api.error(ctx, fiber.StatusBadRequest, "From timestamp must be less than To timestamp unless To is 0") - } - - ltv, err := api.history.CalculateCustomerLTV(ctx.Context(), req.From, req.To) - if err != nil { - api.logger.Error("failed to calculate LTV", zap.Error(err)) - return api.errorOld(ctx, err) - } - - response := struct { - LTV int64 `json:"LTV"` - }{ - LTV: ltv, - } - - return ctx.Status(fiber.StatusOK).JSON(response) -} - -func (api *API2) GetRecentTariffs(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - tariffs, err := api.history.GetRecentTariffs(ctx.Context(), userID) - if err != nil { - api.logger.Error("failed to get recent tariffs on of ", - zap.String("userId", userID), - zap.Error(err), - ) - return api.errorOld(ctx, err) - } - - return ctx.Status(fiber.StatusOK).JSON(tariffs) -} - -func (api *API2) SendReport(ctx *fiber.Ctx) error { - var req struct { - Id string `json:"id"` - } - if err := ctx.BodyParser(&req); err != nil { - api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") - } - - if req.Id == "" { - api.logger.Error("history id is missing in of ") - return api.error(ctx, fiber.StatusBadRequest, "history id is missing") - } - - tariffs, err := api.history.GetHistoryByID(ctx.Context(), req.Id) - if err != nil { - api.logger.Error( - "failed to get history by id in of ", - zap.String("historyID", req.Id), - zap.Error(err), - ) - return api.errorOld(ctx, err) - } - - if tariffs.Key != models.CustomerHistoryKeyPayCart { - api.logger.Error( - "invalid history record key", - zap.String("historyID", req.Id), - zap.Error(err), - ) - return api.error(ctx, fiber.StatusBadRequest, "invalid history record key") - } - - historyMap, err := api.history.GetDocNumber(ctx.Context(), tariffs.UserID) - if err != nil { - api.logger.Error( - "failed to get history of sorting by date created in of ", - zap.String("historyID", req.Id), - zap.Error(err), - ) - return api.errorOld(ctx, err) - } - token := ctx.Get("Authorization") - fmt.Println("HEADERS", ctx.Request().Header) - - verifuser, err := api.clients.verify.GetVerification(ctx.Context(), token, tariffs.UserID) - if err != nil { - api.logger.Error("failed to get user verification on of ", - zap.Error(err), - zap.String("userID", tariffs.UserID), - ) - return api.errorOld(ctx, err) - } - if !verifuser.Accepted { - api.logger.Error( - "verification not accepted", - zap.String("userID", tariffs.UserID), - zap.Error(err), - ) - return api.error(ctx, fiber.StatusBadRequest, "verification not accepted") - } - account, err := api.account.FindByUserID(ctx.Context(), tariffs.UserID) - if err != nil { - return api.errorOld(ctx, err) - } - - authuser, err := api.clients.auth.GetUser(ctx.Context(), tariffs.UserID) - if err != nil { - api.logger.Error("failed to get user on of ", - zap.Error(err), - zap.String("userID", tariffs.UserID), - ) - return api.errorOld(ctx, err) - } - - fileContents, readerr := os.ReadFile("./report.docx") - if readerr != nil { - return api.error(ctx, fiber.StatusInternalServerError, "failed to read file") - } - - if account.Name.Orgname == "" { - account.Name.Orgname = "Безымянное предприятие" - } - - for _, tariff := range tariffs.RawDetails.Tariffs { - totalAmount := uint64(0) - privilegeMeasurement := "" - piecePrice := "" - privilegeName := "" - for _, privilege := range tariff.Privileges { - totalAmount += privilege.Amount - privilegeMeasurement = string(privilege.Type) - piecePrice = fmt.Sprintf("%.2f", float64(privilege.Price)/100) - privilegeName = privilege.Name - } - data := models.RespGeneratorService{ - DocNumber: fmt.Sprint(historyMap[req.Id] + 1), - Date: time.Now().Format("2006-01-02"), - OrgTaxNum: verifuser.TaxNumber, - OrgName: account.Name.Orgname, - Name: tariff.Name + " " + privilegeName, - Amount: fmt.Sprint(totalAmount), - Unit: piecePrice, - Price: fmt.Sprintf("%.2f", float64(tariffs.RawDetails.Price)/100), - Sum: privilegeMeasurement, - } - err = api.clients.template.SendData(ctx.Context(), data, fileContents, authuser.Login) - if err != nil { - api.logger.Error("failed to send report to user on of ", - zap.Error(err), - zap.String("userID", tariffs.UserID), - ) - return api.errorOld(ctx, err) - } - } - - return ctx.SendStatus(fiber.StatusOK) -} - -func (api *API2) PostWalletRspay(ctx *fiber.Ctx) error { - userID, ok := api.extractUserID(ctx) - if !ok || userID == "" { - return api.noauth(ctx) - } - - var req struct { - Money *float32 `json:"money,omitempty"` - } - - if err := ctx.BodyParser(&req); err != nil { - api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") - } - - user, err := api.account.FindByUserID(ctx.Context(), userID) - if err != nil { - return api.errorOld(ctx, err) - } - - if user.Status != models.AccountStatusNko && user.Status != models.AccountStatusOrg { - return api.error(ctx, fiber.StatusForbidden, "not allowed for non organizations") - } - token := ctx.Get("Authorization") - fmt.Println("HEADERS", ctx.Request().Header) - - verification, err := api.clients.verify.GetVerification(ctx.Context(), token, userID) - if err == errors.ErrNotFound { - return api.error(ctx, fiber.StatusForbidden, "no verification data found") - } - - if (user.Status == models.AccountStatusOrg && len(verification.Files) != 3) || - (user.Status == models.AccountStatusNko && len(verification.Files) != 4) { - return api.error(ctx, fiber.StatusForbidden, "not enough verification files") - } - - authData, err := api.clients.auth.GetUser(ctx.Context(), userID) - if err != nil { - return api.errorOld(ctx, err) - } - - err = api.clients.mail.SendMessage(authData.Login, verification, *req.Money) - if err != nil { - return api.errorOld(ctx, err) - } - - return ctx.SendStatus(fiber.StatusOK) -} - -type QuizLogoStat2 struct { - Count int64 `json:"count,omitempty"` - Items map[string]Item `json:"items,omitempty"` -} - -type Item struct { - Money int64 `json:"money,omitempty"` - Quizes map[string][2]int `json:"quizes,omitempty"` - Regs int `json:"regs,omitempty"` -} - -func (api *API2) QuizLogoStat(ctx *fiber.Ctx) error { - var req struct { - From *int `json:"from,omitempty"` - Limit *int `json:"limit,omitempty"` - Page *int `json:"page,omitempty"` - To *int `json:"to,omitempty"` - } - - if err := ctx.BodyParser(&req); err != nil { - api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") - } - - result, err := api.account.QuizLogoStat(ctx.Context(), repository.QuizLogoStatDeps{ - Page: req.Page, - Limit: req.Limit, - From: req.From, - To: req.To, - }) - if err != nil { - return api.error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting quiz logo stat", err.Error())) - } - - return ctx.Status(fiber.StatusOK).JSON(result) -} - -func (api *API2) PromocodeLTV(ctx *fiber.Ctx) error { - var req struct { - From int `json:"from"` - To int `json:"to"` - } - - if err := ctx.BodyParser(&req); err != nil { - api.logger.Error("failed to bind request", zap.Error(err)) - return api.error(ctx, fiber.StatusBadRequest, "failed to bind request") - } - - // получаем мапу вида [promoID] = []{userid,timeActivate} - // отдаются только первые использованые на аккаунте промокоды, соответсвенно подсчет идет сугубо по ним - // если в запросе время различается с временем активации - если меньше, то учитывается только после применения - // если больше, то учитывается только с начала переданного from - codewordData, err := api.clients.codeword.GetAllPromoActivations(ctx.Context(), &codeword_rpc.Time{ - To: int64(req.To), - From: int64(req.From), - }) - - if err != nil { - return api.error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting codeword data", err.Error())) - } - - userSumMap, er := api.history.GetPayUsersPromoHistory(ctx.Context(), codewordData, int64(req.From), int64(req.To)) - if er != nil { - return api.error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed calculate promo users paid sum", er.Error())) - } - - resp := make(map[string]struct { - Regs int - Money int64 - }) - - for promoID, data := range codewordData { - fmt.Println("PROTOMOTO", promoID, data) - for _, value := range data { - - paids, ok := userSumMap[value.UserID] - if !ok { - paids = 0 - } - fmt.Println("PROTOMOTO1", paids, value) - - if value.Time >= int64(req.From) && value.Time <= int64(req.To) { - if _, ok := resp[promoID]; !ok { - resp[promoID] = struct { - Regs int - Money int64 - }{Regs: 1, Money: paids} - continue - } - current := resp[promoID] - current.Regs += 1 - current.Money += paids - resp[promoID] = current - } - } - } - - return ctx.Status(fiber.StatusOK).JSON(resp) -} diff --git a/internal/interface/controller/http/currency/controllers.go b/internal/interface/controller/http/currency/controllers.go new file mode 100644 index 0000000..4290893 --- /dev/null +++ b/internal/interface/controller/http/currency/controllers.go @@ -0,0 +1,75 @@ +package currency + +import ( + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" +) + +type Deps struct { + CurrencyRepo *repository.CurrencyRepository + MiddleWare *http.MiddleWare + Logger *zap.Logger +} + +type CurrencyController struct { + currencyRepo *repository.CurrencyRepository + middleWare *http.MiddleWare + logger *zap.Logger +} + +func NewCurrencyController(deps Deps) *CurrencyController { + return &CurrencyController{ + currencyRepo: deps.CurrencyRepo, + middleWare: deps.MiddleWare, + logger: deps.Logger, + } +} + +func (receiver *CurrencyController) GetCurrencies(ctx *fiber.Ctx) error { + currencyList, err := receiver.currencyRepo.FindCurrenciesList(ctx.Context(), models.DefaultCurrencyListName) + if err != nil && err.Type() != errors.ErrNotFound { + return receiver.middleWare.ErrorOld(ctx, err) + } + + if err != nil && err.Type() == errors.ErrNotFound { + return ctx.Status(fiber.StatusOK).JSON([]string{}) + } + + return ctx.Status(fiber.StatusOK).JSON(currencyList) +} + +func (receiver *CurrencyController) UpdateCurrencies(ctx *fiber.Ctx) error { + var req struct { + items []string + } + if err := ctx.BodyParser(&req); err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind currencies") + } + + currencies := req.items + + currencyList, err := receiver.currencyRepo.ReplaceCurrencies(ctx.Context(), &models.CurrencyList{ + Name: models.DefaultCurrencyListName, + Currencies: currencies, + }) + if err != nil && err.Type() != errors.ErrNotFound { + return receiver.middleWare.ErrorOld(ctx, err) + } + + if err != nil && err.Type() == errors.ErrNotFound { + newCurrencyList, err := receiver.currencyRepo.Insert(ctx.Context(), &models.CurrencyList{ + Name: models.DefaultCurrencyListName, + Currencies: currencies, + }) + if err != nil && err.Type() != errors.ErrNotFound { + return receiver.middleWare.ErrorOld(ctx, err) + } + return ctx.Status(fiber.StatusOK).JSON(newCurrencyList.Currencies) + } + + return ctx.Status(fiber.StatusOK).JSON(currencyList.Currencies) +} diff --git a/internal/interface/controller/http/currency/route.go b/internal/interface/controller/http/currency/route.go new file mode 100644 index 0000000..e096de4 --- /dev/null +++ b/internal/interface/controller/http/currency/route.go @@ -0,0 +1,12 @@ +package currency + +import "github.com/gofiber/fiber/v2" + +func (receiver *CurrencyController) Register(router fiber.Router) { + router.Get("/currencies", receiver.GetCurrencies) + router.Put("/currencies", receiver.UpdateCurrencies) +} + +func (receiver *CurrencyController) Name() string { + return "" +} diff --git a/internal/interface/controller/http/history/controllers.go b/internal/interface/controller/http/history/controllers.go new file mode 100644 index 0000000..566c5cb --- /dev/null +++ b/internal/interface/controller/http/history/controllers.go @@ -0,0 +1,383 @@ +package history + +import ( + "fmt" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" + "math" + "os" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" + codeword_rpc "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/codeword" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history" + "strconv" + "time" +) + +type Deps struct { + MiddleWare *http.MiddleWare + HistoryRepo *repository.HistoryRepository + AccountRepo *repository.AccountRepository + VerifyClient *client.VerificationClient + AuthClient *client.AuthClient + TemplateClient *client.TemplateClient + CodewordClient *client.CodewordClient + Logger *zap.Logger +} + +type HistoryController struct { + middleWare *http.MiddleWare + historyRepo *repository.HistoryRepository + accountRepo *repository.AccountRepository + verifyClient *client.VerificationClient + authClient *client.AuthClient + templateClient *client.TemplateClient + codewordClient *client.CodewordClient + logger *zap.Logger +} + +func NewHistoryController(deps Deps) *HistoryController { + return &HistoryController{ + middleWare: deps.MiddleWare, + historyRepo: deps.HistoryRepo, + authClient: deps.AuthClient, + accountRepo: deps.AccountRepo, + verifyClient: deps.VerifyClient, + templateClient: deps.TemplateClient, + codewordClient: deps.CodewordClient, + logger: deps.Logger, + } +} + +func (receiver *HistoryController) GetHistory(ctx *fiber.Ctx) error { + var userID string + + pageStr := ctx.Query("page") + limitStr := ctx.Query("limit") + tipe := ctx.Query("type") + accountID := ctx.Query("accountID") + + if accountID != "" { + userID = accountID + } else { + id, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || id == "" { + return receiver.middleWare.NoAuth(ctx) + } + + userID = id + } + + limit, err := strconv.ParseInt(limitStr, 10, 64) + if err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "invalid limit format") + } + + page, err := strconv.ParseInt(pageStr, 10, 64) + if err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "invalid page format") + } + + dto := &history.GetHistories{ + UserID: userID, + Type: &tipe, + Pagination: &models.Pagination{ + Page: page, + Limit: limit, + }, + } + + count, err := receiver.historyRepo.CountAll(ctx.Context(), dto) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + if count == 0 { + returnHistories := models.PaginationResponse[models.History]{TotalPages: 0, Records: []models.History{}} + return ctx.Status(fiber.StatusOK).JSON(returnHistories) + } + + totalPages := int64(math.Ceil(float64(count) / float64(dto.Pagination.Limit))) + + histories, err := receiver.historyRepo.FindMany(ctx.Context(), dto) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + returnHistories := models.PaginationResponse[models.History]{ + TotalPages: totalPages, + Records: histories, + } + + return ctx.Status(fiber.StatusOK).JSON(returnHistories) +} + +func (receiver *HistoryController) CalculateLTV(ctx *fiber.Ctx) error { + var req struct { + From int64 `json:"from"` + To int64 `json:"to"` + } + + if err := ctx.BodyParser(&req); err != nil { + receiver.logger.Error("failed to bind request", zap.Error(err)) + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request") + } + + if req.From > req.To && req.To != 0 { + receiver.logger.Error("From timestamp must be less than To timestamp unless To is 0") + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "From timestamp must be less than To timestamp unless To is 0") + } + + ltv, err := receiver.historyRepo.CalculateCustomerLTV(ctx.Context(), req.From, req.To) + if err != nil { + receiver.logger.Error("failed to calculate LTV", zap.Error(err)) + return receiver.middleWare.ErrorOld(ctx, err) + } + + response := struct { + LTV int64 `json:"LTV"` + }{ + LTV: ltv, + } + + return ctx.Status(fiber.StatusOK).JSON(response) +} + +func (receiver *HistoryController) GetRecentTariffs(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + tariffs, err := receiver.historyRepo.GetRecentTariffs(ctx.Context(), userID) + if err != nil { + receiver.logger.Error("failed to get recent tariffs on of ", + zap.String("userId", userID), + zap.Error(err), + ) + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(tariffs) +} + +func (receiver *HistoryController) SendReport(ctx *fiber.Ctx) error { + var req struct { + Id string `json:"id"` + } + if err := ctx.BodyParser(&req); err != nil { + receiver.logger.Error("failed to bind request", zap.Error(err)) + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request") + } + + if req.Id == "" { + receiver.logger.Error("history id is missing in of ") + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "history id is missing") + } + + tariffs, err := receiver.historyRepo.GetHistoryByID(ctx.Context(), req.Id) + if err != nil { + receiver.logger.Error( + "failed to get history by id in of ", + zap.String("historyID", req.Id), + zap.Error(err), + ) + return receiver.middleWare.ErrorOld(ctx, err) + } + + if tariffs.Key != models.CustomerHistoryKeyPayCart { + receiver.logger.Error( + "invalid history record key", + zap.String("historyID", req.Id), + zap.Error(err), + ) + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "invalid history record key") + } + + historyMap, err := receiver.historyRepo.GetDocNumber(ctx.Context(), tariffs.UserID) + if err != nil { + receiver.logger.Error( + "failed to get history of sorting by date created in of ", + zap.String("historyID", req.Id), + zap.Error(err), + ) + return receiver.middleWare.ErrorOld(ctx, err) + } + token := ctx.Get("Authorization") + fmt.Println("HEADERS", ctx.Request().Header) + + verifuser, err := receiver.verifyClient.GetVerification(ctx.Context(), token, tariffs.UserID) + if err != nil { + receiver.logger.Error("failed to get user verification on of ", + zap.Error(err), + zap.String("userID", tariffs.UserID), + ) + return receiver.middleWare.ErrorOld(ctx, err) + } + if !verifuser.Accepted { + receiver.logger.Error( + "verification not accepted", + zap.String("userID", tariffs.UserID), + zap.Error(err), + ) + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "verification not accepted") + } + account, err := receiver.accountRepo.FindByUserID(ctx.Context(), tariffs.UserID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + authuser, err := receiver.authClient.GetUser(ctx.Context(), tariffs.UserID) + if err != nil { + receiver.logger.Error("failed to get user on of ", + zap.Error(err), + zap.String("userID", tariffs.UserID), + ) + return receiver.middleWare.ErrorOld(ctx, err) + } + + fileContents, readerr := os.ReadFile("./report.docx") + if readerr != nil { + return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, "failed to read file") + } + + if account.Name.Orgname == "" { + account.Name.Orgname = "Безымянное предприятие" + } + + for _, tariff := range tariffs.RawDetails.Tariffs { + totalAmount := uint64(0) + privilegeMeasurement := "" + piecePrice := "" + privilegeName := "" + for _, privilege := range tariff.Privileges { + totalAmount += privilege.Amount + privilegeMeasurement = string(privilege.Type) + piecePrice = fmt.Sprintf("%.2f", float64(privilege.Price)/100) + privilegeName = privilege.Name + } + data := models.RespGeneratorService{ + DocNumber: fmt.Sprint(historyMap[req.Id] + 1), + Date: time.Now().Format("2006-01-02"), + OrgTaxNum: verifuser.TaxNumber, + OrgName: account.Name.Orgname, + Name: tariff.Name + " " + privilegeName, + Amount: fmt.Sprint(totalAmount), + Unit: piecePrice, + Price: fmt.Sprintf("%.2f", float64(tariffs.RawDetails.Price)/100), + Sum: privilegeMeasurement, + } + err = receiver.templateClient.SendData(ctx.Context(), data, fileContents, authuser.Login) + if err != nil { + receiver.logger.Error("failed to send report to user on of ", + zap.Error(err), + zap.String("userID", tariffs.UserID), + ) + return receiver.middleWare.ErrorOld(ctx, err) + } + } + + return ctx.SendStatus(fiber.StatusOK) +} + +type QuizLogoStat2 struct { + Count int64 `json:"count,omitempty"` + Items map[string]Item `json:"items,omitempty"` +} + +type Item struct { + Money int64 `json:"money,omitempty"` + Quizes map[string][2]int `json:"quizes,omitempty"` + Regs int `json:"regs,omitempty"` +} + +func (receiver *HistoryController) QuizLogoStat(ctx *fiber.Ctx) error { + var req struct { + From *int `json:"from,omitempty"` + Limit *int `json:"limit,omitempty"` + Page *int `json:"page,omitempty"` + To *int `json:"to,omitempty"` + } + + if err := ctx.BodyParser(&req); err != nil { + receiver.logger.Error("failed to bind request", zap.Error(err)) + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request") + } + + result, err := receiver.accountRepo.QuizLogoStat(ctx.Context(), repository.QuizLogoStatDeps{ + Page: req.Page, + Limit: req.Limit, + From: req.From, + To: req.To, + }) + if err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting quiz logo stat", err.Error())) + } + + return ctx.Status(fiber.StatusOK).JSON(result) +} + +func (receiver *HistoryController) PromocodeLTV(ctx *fiber.Ctx) error { + var req struct { + From int `json:"from"` + To int `json:"to"` + } + + if err := ctx.BodyParser(&req); err != nil { + receiver.logger.Error("failed to bind request", zap.Error(err)) + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request") + } + + // получаем мапу вида [promoID] = []{userid,timeActivate} + // отдаются только первые использованые на аккаунте промокоды, соответсвенно подсчет идет сугубо по ним + // если в запросе время различается с временем активации - если меньше, то учитывается только после применения + // если больше, то учитывается только с начала переданного from + codewordData, err := receiver.codewordClient.GetAllPromoActivations(ctx.Context(), &codeword_rpc.Time{ + To: int64(req.To), + From: int64(req.From), + }) + + if err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed getting codeword data", err.Error())) + } + + userSumMap, er := receiver.historyRepo.GetPayUsersPromoHistory(ctx.Context(), codewordData, int64(req.From), int64(req.To)) + if er != nil { + return receiver.middleWare.Error(ctx, fiber.StatusInternalServerError, fmt.Sprint("failed calculate promo users paid sum", er.Error())) + } + + resp := make(map[string]struct { + Regs int + Money int64 + }) + + for promoID, data := range codewordData { + fmt.Println("PROTOMOTO", promoID, data) + for _, value := range data { + + paids, ok := userSumMap[value.UserID] + if !ok { + paids = 0 + } + fmt.Println("PROTOMOTO1", paids, value) + + if value.Time >= int64(req.From) && value.Time <= int64(req.To) { + if _, ok := resp[promoID]; !ok { + resp[promoID] = struct { + Regs int + Money int64 + }{Regs: 1, Money: paids} + continue + } + current := resp[promoID] + current.Regs += 1 + current.Money += paids + resp[promoID] = current + } + } + } + + return ctx.Status(fiber.StatusOK).JSON(resp) +} diff --git a/internal/interface/controller/http/history/route.go b/internal/interface/controller/http/history/route.go new file mode 100644 index 0000000..0edf71f --- /dev/null +++ b/internal/interface/controller/http/history/route.go @@ -0,0 +1,16 @@ +package history + +import "github.com/gofiber/fiber/v2" + +func (receiver *HistoryController) Register(router fiber.Router) { + router.Get("/history", receiver.GetHistory) + router.Post("/history/ltv", receiver.CalculateLTV) + router.Post("/promocode/ltv", receiver.PromocodeLTV) + router.Post("/quizlogo/stat", receiver.QuizLogoStat) + router.Get("/recent", receiver.GetRecentTariffs) + router.Post("/sendReport", receiver.SendReport) +} + +func (receiver *HistoryController) Name() string { + return "" +} diff --git a/internal/interface/controller/http/middleware.go b/internal/interface/controller/http/middleware.go new file mode 100644 index 0000000..53f686d --- /dev/null +++ b/internal/interface/controller/http/middleware.go @@ -0,0 +1,55 @@ +package http + +import ( + "fmt" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" +) + +type MiddleWare struct { + logger *zap.Logger +} + +func NewMiddleWare(logger *zap.Logger) *MiddleWare { + return &MiddleWare{ + logger: logger, + } +} + +func (mw *MiddleWare) Error(ctx *fiber.Ctx, status int, message string, rest ...any) error { + if len(rest) > 0 { + message = fmt.Sprintf(message, rest...) + } + mw.logger.Error(message) + return ctx.Status(status).JSON(models.ResponseErrorHTTP{ + StatusCode: status, + Message: message, + }) +} + +func (mw *MiddleWare) ErrorOld(ctx *fiber.Ctx, err error) error { + mw.logger.Error("error:", zap.Error(err)) + return ctx.Status(fiber.StatusInternalServerError).JSON(models.ResponseErrorHTTP{ + StatusCode: fiber.StatusInternalServerError, + Message: err.Error(), + }) +} + +func (mw *MiddleWare) NoAuth(ctx *fiber.Ctx) error { + return mw.Error(ctx, fiber.StatusUnauthorized, "failed to get jwt payload") +} + +func (mw *MiddleWare) ExtractUserID(ctx *fiber.Ctx) (string, bool) { + id, ok := ctx.Context().UserValue(models.AuthJWTDecodedUserIDKey).(string) + return id, ok +} + +func (mw *MiddleWare) ExtractToken(ctx *fiber.Ctx) (string, bool) { + token, ok := ctx.Context().UserValue(models.AuthJWTDecodedAccessTokenKey).(string) + return token, ok +} + +func (mw *MiddleWare) GetHealth(ctx *fiber.Ctx) error { + return ctx.Status(fiber.StatusOK).SendString("OK") +} diff --git a/internal/interface/controller/http/money.go b/internal/interface/controller/http/money.go deleted file mode 100644 index 9beea2d..0000000 --- a/internal/interface/controller/http/money.go +++ /dev/null @@ -1,152 +0,0 @@ -package http - -import ( - "context" - - "go.uber.org/zap" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" - "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/treasurer" -) - -func (api *API2) GetPaymentLink(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { - if _, userErr := api.clients.auth.GetUser(ctx, request.UserID); userErr != nil { - api.logger.Error("failed to get user on on ", - zap.Error(userErr), - zap.String("userID", request.UserID), - ) - - return "", userErr - } - - switch request.Body.Type { - case models.PaymentTypeBankCard: - return api.GetPaymentLinkBankCard(ctx, request) - case models.PaymentTypeYoomoney: - return api.GetPaymentLinkYooMoney(ctx, request) - case models.PaymentTypeSberPay: - return api.GetPaymentLinkSberPay(ctx, request) - case models.PaymentTypeTinkoff: - return api.GetPaymentLinkTinkoff(ctx, request) - case models.PaymentTypeSBP: - return api.GetPaymentLinkSBP(ctx, request) - case models.PaymentTypeSberB2B: - return api.GetPaymentLinkB2B(ctx, request) - } - - return "", errors.NewWithMessage("invalid payment method type", errors.ErrInvalidArgs) -} - -func (api *API2) GetPaymentLinkBankCard(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { - link, err := api.clients.payment.GetPaymentLinkBankCard(ctx, &treasurer.GetBankCardPaymentLinkRequest{ - MainSettings: &treasurer.MainPaymentSettings{ - Currency: request.Body.Currency, - Amount: request.Body.Amount, - UserID: request.UserID, - ClientIP: request.ClientIP, - CallbackHostGRPC: []string{api.grpc.Domen}, - ReturnURL: request.Body.ReturnURL, - }, - }) - if err != nil { - api.logger.Error("failed to get bankcard payment link on of ", zap.Error(err)) - return "", err - } - - return link, nil -} - -func (api *API2) GetPaymentLinkYooMoney(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { - link, err := api.clients.payment.GetPaymentLinkYooMoney(ctx, &treasurer.GetPaymentLinkBody{ - MainSettings: &treasurer.MainPaymentSettings{ - Currency: request.Body.Currency, - Amount: request.Body.Amount, - UserID: request.UserID, - ClientIP: request.ClientIP, - CallbackHostGRPC: []string{api.grpc.Domen}, - ReturnURL: request.Body.ReturnURL, - }, - }) - if err != nil { - api.logger.Error("failed to get yoomoney payment link on of ", zap.Error(err)) - return "", err - } - - return link, nil -} - -func (api *API2) GetPaymentLinkSberPay(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { - link, err := api.clients.payment.GetPaymentLinkSberPay(ctx, &treasurer.GetPaymentLinkBody{ - MainSettings: &treasurer.MainPaymentSettings{ - Currency: request.Body.Currency, - Amount: request.Body.Amount, - UserID: request.UserID, - ClientIP: request.ClientIP, - CallbackHostGRPC: []string{api.grpc.Domen}, - ReturnURL: request.Body.ReturnURL, - }, - }) - if err != nil { - api.logger.Error("failed to get sberpay payment link on of ", zap.Error(err)) - return "", err - } - - return link, nil -} - -func (api *API2) GetPaymentLinkTinkoff(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { - link, err := api.clients.payment.GetPaymentLinkTinkoff(ctx, &treasurer.GetPaymentLinkBody{ - MainSettings: &treasurer.MainPaymentSettings{ - Currency: request.Body.Currency, - Amount: request.Body.Amount, - UserID: request.UserID, - ClientIP: request.ClientIP, - CallbackHostGRPC: []string{api.grpc.Domen}, - ReturnURL: request.Body.ReturnURL, - }, - }) - if err != nil { - api.logger.Error("failed to get tinkoff payment link on of ", zap.Error(err)) - return "", err - } - - return link, nil -} - -func (api *API2) GetPaymentLinkSBP(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { - link, err := api.clients.payment.GetPaymentLinkSBP(ctx, &treasurer.GetPaymentLinkBody{ - MainSettings: &treasurer.MainPaymentSettings{ - Currency: request.Body.Currency, - Amount: request.Body.Amount, - UserID: request.UserID, - ClientIP: request.ClientIP, - CallbackHostGRPC: []string{api.grpc.Domen}, - ReturnURL: request.Body.ReturnURL, - }, - }) - if err != nil { - api.logger.Error("failed to get sbp payment link on of ", zap.Error(err)) - return "", err - } - - return link, nil -} - -func (api *API2) GetPaymentLinkB2B(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { - link, err := api.clients.payment.GetPaymentLinkSberbankB2B(ctx, &treasurer.GetPaymentLinkBody{ - MainSettings: &treasurer.MainPaymentSettings{ - Currency: request.Body.Currency, - Amount: request.Body.Amount, - UserID: request.UserID, - ClientIP: request.ClientIP, - CallbackHostGRPC: []string{api.grpc.Domen}, - ReturnURL: request.Body.ReturnURL, - }, - }) - if err != nil { - api.logger.Error("failed to get sberbankb2b payment link on of ", zap.Error(err)) - return "", err - } - - return link, nil -} diff --git a/internal/interface/controller/http/route.go b/internal/interface/controller/http/route.go index ae876cb..36b7167 100644 --- a/internal/interface/controller/http/route.go +++ b/internal/interface/controller/http/route.go @@ -1,32 +1,30 @@ package http -import "github.com/gofiber/fiber/v2" - -func (api *API2) Register(router fiber.Router) { - router.Delete("/account", api.DeleteAccount) - router.Get("/account", api.GetAccount) - router.Patch("/account", api.ChangeAccount) - router.Post("/account", api.AddAccount) - router.Delete("/account/:userId", api.DeleteDirectAccount) - router.Get("/account/:userId", api.GetDirectAccount) - router.Patch("/account/:userId", api.SetAccountVerificationStatus) - router.Get("/accounts", api.PaginationAccounts) - router.Delete("/cart", api.RemoveFromCart) - router.Patch("/cart", api.Add2cart) - router.Post("/cart/pay", api.PayCart) - router.Get("/currencies", api.GetCurrencies) - router.Put("/currencies", api.UpdateCurrencies) - router.Get("/history", api.GetHistory) - router.Post("/history/ltv", api.CalculateLTV) - router.Post("/promocode/ltv", api.PromocodeLTV) - router.Post("/quizlogo/stat", api.QuizLogoStat) - router.Get("/recent", api.GetRecentTariffs) - router.Post("/sendReport", api.SendReport) - router.Patch("/wallet", api.ChangeCurrency) - router.Post("/wallet", api.RequestMoney) - router.Post("/wallet/rspay", api.PostWalletRspay) -} - -func (api *API2) Name() string { - return "" -} +//func (api *API2) Register(router fiber.Router) { +// router.Delete("/account", api.DeleteAccount) +// router.Get("/account", api.GetAccount) +// router.Patch("/account", api.ChangeAccount) +// router.Post("/account", api.AddAccount) +// router.Delete("/account/:userId", api.DeleteDirectAccount) +// router.Get("/account/:userId", api.GetDirectAccount) +// router.Patch("/account/:userId", api.SetAccountVerificationStatus) +// router.Get("/accounts", api.PaginationAccounts) +// router.Delete("/cart", api.RemoveFromCart) +// router.Patch("/cart", api.Add2cart) +// router.Post("/cart/pay", api.PayCart) +// router.Get("/currencies", api.GetCurrencies) +// router.Put("/currencies", api.UpdateCurrencies) +// router.Get("/history", api.GetHistory) +// router.Post("/history/ltv", api.CalculateLTV) +// router.Post("/promocode/ltv", api.PromocodeLTV) +// router.Post("/quizlogo/stat", api.QuizLogoStat) +// router.Get("/recent", api.GetRecentTariffs) +// router.Post("/sendReport", api.SendReport) +// router.Patch("/wallet", api.ChangeCurrency) +// router.Post("/wallet", api.RequestMoney) +// router.Post("/wallet/rspay", api.PostWalletRspay) +//} +// +//func (api *API2) Name() string { +// return "" +//} diff --git a/internal/interface/controller/http/wallet/controllers.go b/internal/interface/controller/http/wallet/controllers.go new file mode 100644 index 0000000..32896e9 --- /dev/null +++ b/internal/interface/controller/http/wallet/controllers.go @@ -0,0 +1,314 @@ +package wallet + +import ( + "context" + "fmt" + "github.com/gofiber/fiber/v2" + "go.uber.org/zap" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/controller/http" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/treasurer" + "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils" + "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate" +) + +type Deps struct { + MiddleWare *http.MiddleWare + AuthClient *client.AuthClient + PaymentClient *client.PaymentClient + GRPC *models.ConfigurationGRPC + AccountRepo *repository.AccountRepository + CurrencyClient *client.CurrencyClient + VerifyClient *client.VerificationClient + MailClient *client.MailClient + Logger *zap.Logger +} + +type WalletController struct { + middleWare *http.MiddleWare + authClient *client.AuthClient + paymentClient *client.PaymentClient + grpc *models.ConfigurationGRPC + accountRepo *repository.AccountRepository + currencyClient *client.CurrencyClient + verifyClient *client.VerificationClient + mailClient *client.MailClient + logger *zap.Logger +} + +func NewWalletController(deps Deps) *WalletController { + return &WalletController{ + middleWare: deps.MiddleWare, + authClient: deps.AuthClient, + paymentClient: deps.PaymentClient, + grpc: deps.GRPC, + accountRepo: deps.AccountRepo, + currencyClient: deps.CurrencyClient, + verifyClient: deps.VerifyClient, + mailClient: deps.MailClient, + logger: deps.Logger, + } +} + +func (receiver *WalletController) RequestMoney(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + var request models.GetPaymentLinkBody + if err := ctx.BodyParser(&request); err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind payment link") + } + + if err := utils.ValidateGetPaymentLinkBody(&request); err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + link, err := receiver.GetPaymentLink(ctx.Context(), &models.GetPaymentLinkRequest{ + Body: &request, + UserID: userID, + ClientIP: ctx.IP(), + }) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(&models.GetPaymentLinkResponse{Link: link}) +} + +func (receiver *WalletController) GetPaymentLink(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { + if _, userErr := receiver.authClient.GetUser(ctx, request.UserID); userErr != nil { + receiver.logger.Error("failed to get user on on ", + zap.Error(userErr), + zap.String("userID", request.UserID), + ) + + return "", userErr + } + + switch request.Body.Type { + case models.PaymentTypeBankCard: + return receiver.GetPaymentLinkBankCard(ctx, request) + case models.PaymentTypeYoomoney: + return receiver.GetPaymentLinkYooMoney(ctx, request) + case models.PaymentTypeSberPay: + return receiver.GetPaymentLinkSberPay(ctx, request) + case models.PaymentTypeTinkoff: + return receiver.GetPaymentLinkTinkoff(ctx, request) + case models.PaymentTypeSBP: + return receiver.GetPaymentLinkSBP(ctx, request) + case models.PaymentTypeSberB2B: + return receiver.GetPaymentLinkB2B(ctx, request) + } + + return "", errors.NewWithMessage("invalid payment method type", errors.ErrInvalidArgs) +} + +func (receiver *WalletController) GetPaymentLinkBankCard(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { + link, err := receiver.paymentClient.GetPaymentLinkBankCard(ctx, &treasurer.GetBankCardPaymentLinkRequest{ + MainSettings: &treasurer.MainPaymentSettings{ + Currency: request.Body.Currency, + Amount: request.Body.Amount, + UserID: request.UserID, + ClientIP: request.ClientIP, + CallbackHostGRPC: []string{receiver.grpc.Domen}, + ReturnURL: request.Body.ReturnURL, + }, + }) + if err != nil { + receiver.logger.Error("failed to get bankcard payment link on of ", zap.Error(err)) + return "", err + } + + return link, nil +} + +func (receiver *WalletController) GetPaymentLinkYooMoney(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { + link, err := receiver.paymentClient.GetPaymentLinkYooMoney(ctx, &treasurer.GetPaymentLinkBody{ + MainSettings: &treasurer.MainPaymentSettings{ + Currency: request.Body.Currency, + Amount: request.Body.Amount, + UserID: request.UserID, + ClientIP: request.ClientIP, + CallbackHostGRPC: []string{receiver.grpc.Domen}, + ReturnURL: request.Body.ReturnURL, + }, + }) + if err != nil { + receiver.logger.Error("failed to get yoomoney payment link on of ", zap.Error(err)) + return "", err + } + + return link, nil +} + +func (receiver *WalletController) GetPaymentLinkSberPay(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { + link, err := receiver.paymentClient.GetPaymentLinkSberPay(ctx, &treasurer.GetPaymentLinkBody{ + MainSettings: &treasurer.MainPaymentSettings{ + Currency: request.Body.Currency, + Amount: request.Body.Amount, + UserID: request.UserID, + ClientIP: request.ClientIP, + CallbackHostGRPC: []string{receiver.grpc.Domen}, + ReturnURL: request.Body.ReturnURL, + }, + }) + if err != nil { + receiver.logger.Error("failed to get sberpay payment link on of ", zap.Error(err)) + return "", err + } + + return link, nil +} + +func (receiver *WalletController) GetPaymentLinkTinkoff(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { + link, err := receiver.paymentClient.GetPaymentLinkTinkoff(ctx, &treasurer.GetPaymentLinkBody{ + MainSettings: &treasurer.MainPaymentSettings{ + Currency: request.Body.Currency, + Amount: request.Body.Amount, + UserID: request.UserID, + ClientIP: request.ClientIP, + CallbackHostGRPC: []string{receiver.grpc.Domen}, + ReturnURL: request.Body.ReturnURL, + }, + }) + if err != nil { + receiver.logger.Error("failed to get tinkoff payment link on of ", zap.Error(err)) + return "", err + } + + return link, nil +} + +func (receiver *WalletController) GetPaymentLinkSBP(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { + link, err := receiver.paymentClient.GetPaymentLinkSBP(ctx, &treasurer.GetPaymentLinkBody{ + MainSettings: &treasurer.MainPaymentSettings{ + Currency: request.Body.Currency, + Amount: request.Body.Amount, + UserID: request.UserID, + ClientIP: request.ClientIP, + CallbackHostGRPC: []string{receiver.grpc.Domen}, + ReturnURL: request.Body.ReturnURL, + }, + }) + if err != nil { + receiver.logger.Error("failed to get sbp payment link on of ", zap.Error(err)) + return "", err + } + + return link, nil +} + +func (receiver *WalletController) GetPaymentLinkB2B(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) { + link, err := receiver.paymentClient.GetPaymentLinkSberbankB2B(ctx, &treasurer.GetPaymentLinkBody{ + MainSettings: &treasurer.MainPaymentSettings{ + Currency: request.Body.Currency, + Amount: request.Body.Amount, + UserID: request.UserID, + ClientIP: request.ClientIP, + CallbackHostGRPC: []string{receiver.grpc.Domen}, + ReturnURL: request.Body.ReturnURL, + }, + }) + if err != nil { + receiver.logger.Error("failed to get sberbankb2b payment link on of ", zap.Error(err)) + return "", err + } + + return link, nil +} + +func (receiver *WalletController) ChangeCurrency(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + var request models.ChangeCurrency + if err := ctx.BodyParser(&request); err != nil { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind currency") + } + + if validate.IsStringEmpty(request.Currency) { + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "empty currency") + } + + currency := request.Currency + account, err := receiver.accountRepo.FindByUserID(ctx.Context(), userID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + cash, err := receiver.currencyClient.Translate(ctx.Context(), &models.TranslateCurrency{ + Money: account.Wallet.Cash, + From: account.Wallet.Currency, + To: currency, + }) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + updatedAccount, err := receiver.accountRepo.ChangeWallet(ctx.Context(), account.UserID, &models.Wallet{ + Cash: cash, + Currency: currency, + Money: account.Wallet.Money, + }) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.Status(fiber.StatusOK).JSON(updatedAccount) +} + +func (receiver *WalletController) PostWalletRspay(ctx *fiber.Ctx) error { + userID, ok := receiver.middleWare.ExtractUserID(ctx) + if !ok || userID == "" { + return receiver.middleWare.NoAuth(ctx) + } + + var req struct { + Money *float32 `json:"money,omitempty"` + } + + if err := ctx.BodyParser(&req); err != nil { + receiver.logger.Error("failed to bind request", zap.Error(err)) + return receiver.middleWare.Error(ctx, fiber.StatusBadRequest, "failed to bind request") + } + + user, err := receiver.accountRepo.FindByUserID(ctx.Context(), userID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + if user.Status != models.AccountStatusNko && user.Status != models.AccountStatusOrg { + return receiver.middleWare.Error(ctx, fiber.StatusForbidden, "not allowed for non organizations") + } + token := ctx.Get("Authorization") + fmt.Println("HEADERS", ctx.Request().Header) + + verification, err := receiver.verifyClient.GetVerification(ctx.Context(), token, userID) + if err == errors.ErrNotFound { + return receiver.middleWare.Error(ctx, fiber.StatusForbidden, "no verification data found") + } + + if (user.Status == models.AccountStatusOrg && len(verification.Files) != 3) || + (user.Status == models.AccountStatusNko && len(verification.Files) != 4) { + return receiver.middleWare.Error(ctx, fiber.StatusForbidden, "not enough verification files") + } + + authData, err := receiver.authClient.GetUser(ctx.Context(), userID) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + err = receiver.mailClient.SendMessage(authData.Login, verification, *req.Money) + if err != nil { + return receiver.middleWare.ErrorOld(ctx, err) + } + + return ctx.SendStatus(fiber.StatusOK) +} diff --git a/internal/interface/controller/http/wallet/route.go b/internal/interface/controller/http/wallet/route.go new file mode 100644 index 0000000..c679993 --- /dev/null +++ b/internal/interface/controller/http/wallet/route.go @@ -0,0 +1,13 @@ +package wallet + +import "github.com/gofiber/fiber/v2" + +func (receiver *WalletController) Register(router fiber.Router) { + router.Patch("/wallet", receiver.ChangeCurrency) + router.Post("/wallet", receiver.RequestMoney) + router.Post("/wallet/rspay", receiver.PostWalletRspay) +} + +func (receiver *WalletController) Name() string { + return "" +} diff --git a/internal/interface/repository/account.go b/internal/interface/repository/account.go index 75142cb..4e463fa 100644 --- a/internal/interface/repository/account.go +++ b/internal/interface/repository/account.go @@ -42,21 +42,6 @@ func NewAccountRepository(deps AccountRepositoryDeps) *AccountRepository { } } -func NewAccountRepository2(logger *zap.Logger, mongo *mongo.Collection) AccountRepository { - if logger == nil { - log.Panicln("logger is nil on ") - } - - if mongo == nil { - log.Panicln("mongodb is nil on ") - } - - return AccountRepository{ - logger: logger, - mongoDB: mongo, - } -} - func (receiver *AccountRepository) FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error) { filter := bson.M{ fields.Account.UserID: id, diff --git a/internal/interface/repository/currency.go b/internal/interface/repository/currency.go index 354d4f9..e68b302 100644 --- a/internal/interface/repository/currency.go +++ b/internal/interface/repository/currency.go @@ -41,21 +41,6 @@ func NewCurrencyRepository(deps CurrencyRepositoryDeps) *CurrencyRepository { } } -func NewCurrencyRepository2(logger *zap.Logger, mongo *mongo.Collection) CurrencyRepository { - if logger == nil { - log.Panicln("logger is nil on ") - } - - if mongo == nil { - log.Panicln("mongodb is nil on ") - } - - return CurrencyRepository{ - logger: logger, - mongoDB: mongo, - } -} - func (receiver *CurrencyRepository) FindCurrenciesList(ctx context.Context, name string) (*models.CurrencyList, errors.Error) { filter := bson.M{ fields.Currency.Name: name, diff --git a/internal/interface/repository/history.go b/internal/interface/repository/history.go index 95a3508..282875b 100644 --- a/internal/interface/repository/history.go +++ b/internal/interface/repository/history.go @@ -45,21 +45,6 @@ func NewHistoryRepository(deps HistoryRepositoryDeps) *HistoryRepository { } } -func NewHistoryRepository2(logger *zap.Logger, mongo *mongo.Collection) HistoryRepository { - if logger == nil { - log.Panicln("logger is nil on ") - } - - if mongo == nil { - log.Panicln("mongodb is nil on ") - } - - return HistoryRepository{ - logger: logger, - mongoDB: mongo, - } -} - func (receiver *HistoryRepository) Insert(ctx context.Context, history *models.History) (*models.History, errors.Error) { result, err := receiver.mongoDB.InsertOne(ctx, history.Sanitize()) if err != nil { diff --git a/internal/models/payment.go b/internal/models/payment.go index d79c3a6..18ce9fe 100644 --- a/internal/models/payment.go +++ b/internal/models/payment.go @@ -31,12 +31,13 @@ type BankCard struct { type PaymentType string const ( - PaymentTypeBankCard PaymentType = "bankCard" - PaymentTypeTinkoff PaymentType = "tinkoffBank" - PaymentTypeSberPay PaymentType = "sberbank" - PaymentTypeYoomoney PaymentType = "yoomoney" - PaymentTypeSBP PaymentType = "sbp" - PaymentTypeSberB2B PaymentType = "b2bSberbank" + PaymentTypeBankCard PaymentType = "bankCard" + PaymentTypeTinkoff PaymentType = "tinkoffBank" + PaymentTypeSberPay PaymentType = "sberbank" + PaymentTypeYoomoney PaymentType = "yoomoney" + PaymentTypeSBP PaymentType = "sbp" + PaymentTypeSberB2B PaymentType = "b2bSberbank" + DefaultCurrency = "RUB" ) type PaymentEvent struct { @@ -45,6 +46,6 @@ type PaymentEvent struct { PaymentID string UserID string Currency string - Type string + Type string Amount int64 } diff --git a/internal/server/grpc.go b/internal/server/grpc.go index acf6f95..81943a5 100644 --- a/internal/server/grpc.go +++ b/internal/server/grpc.go @@ -65,7 +65,7 @@ func (receiver *GRPC) Stop(_ context.Context) error { return nil } -func (receiver *GRPC) Register(controllers *initialize.Controllers) *GRPC { +func (receiver *GRPC) Register(controllers *initialize.RpcControllers) *GRPC { payment_callback.RegisterPaymentCallbackServiceServer(receiver.grpc, controllers.PaymentController) customer.RegisterCustomerServiceServer(receiver.grpc, controllers.CustomerController) diff --git a/tests/integration/mail_test.go b/tests/integration/mail_test.go index 2cc6a3a..e301466 100644 --- a/tests/integration/mail_test.go +++ b/tests/integration/mail_test.go @@ -20,6 +20,7 @@ func TestSendMessage(t *testing.T) { Auth: &models.PlainAuth{Username: "kotilion.95@gmail.com", Password: "vWwbCSg4bf0p"}, FiberClient: fiber.AcquireClient(), Logger: zap.NewExample(), + MailAddress: "pashamullin2001@gmail.com", }) userEmail := "test@example.com" diff --git a/tests/integration/promo_ltv_test.go b/tests/integration/promo_ltv_test.go index 63f0e9d..e919c2a 100644 --- a/tests/integration/promo_ltv_test.go +++ b/tests/integration/promo_ltv_test.go @@ -42,7 +42,10 @@ func Test_PromoLTV(t *testing.T) { from := int64(0) to := int64(1714291104) - historyRepo := repository.NewHistoryRepository2(logger, mdb.Collection("histories")) + historyRepo := repository.NewHistoryRepository(repository.HistoryRepositoryDeps{ + Logger: logger, + MongoDB: mdb.Collection("histories"), + }) codewordData, err := codeword.GetAllPromoActivations(ctx, &codeword_rpc.Time{ From: from, From 01e55c129530020c05f550a480e6a6dd9d2416e8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 21 May 2024 18:03:51 +0300 Subject: [PATCH 7/8] delete file route --- internal/interface/controller/http/route.go | 30 --------------------- 1 file changed, 30 deletions(-) delete mode 100644 internal/interface/controller/http/route.go diff --git a/internal/interface/controller/http/route.go b/internal/interface/controller/http/route.go deleted file mode 100644 index 36b7167..0000000 --- a/internal/interface/controller/http/route.go +++ /dev/null @@ -1,30 +0,0 @@ -package http - -//func (api *API2) Register(router fiber.Router) { -// router.Delete("/account", api.DeleteAccount) -// router.Get("/account", api.GetAccount) -// router.Patch("/account", api.ChangeAccount) -// router.Post("/account", api.AddAccount) -// router.Delete("/account/:userId", api.DeleteDirectAccount) -// router.Get("/account/:userId", api.GetDirectAccount) -// router.Patch("/account/:userId", api.SetAccountVerificationStatus) -// router.Get("/accounts", api.PaginationAccounts) -// router.Delete("/cart", api.RemoveFromCart) -// router.Patch("/cart", api.Add2cart) -// router.Post("/cart/pay", api.PayCart) -// router.Get("/currencies", api.GetCurrencies) -// router.Put("/currencies", api.UpdateCurrencies) -// router.Get("/history", api.GetHistory) -// router.Post("/history/ltv", api.CalculateLTV) -// router.Post("/promocode/ltv", api.PromocodeLTV) -// router.Post("/quizlogo/stat", api.QuizLogoStat) -// router.Get("/recent", api.GetRecentTariffs) -// router.Post("/sendReport", api.SendReport) -// router.Patch("/wallet", api.ChangeCurrency) -// router.Post("/wallet", api.RequestMoney) -// router.Post("/wallet/rspay", api.PostWalletRspay) -//} -// -//func (api *API2) Name() string { -// return "" -//} From fb784169e66f257651f818775a23066125535ba1 Mon Sep 17 00:00:00 2001 From: skeris Date: Thu, 23 May 2024 01:42:38 +0300 Subject: [PATCH 8/8] ci: add versioning v1.0.0 --- deployments/staging/docker-compose.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployments/staging/docker-compose.yaml b/deployments/staging/docker-compose.yaml index 432a13a..401705f 100644 --- a/deployments/staging/docker-compose.yaml +++ b/deployments/staging/docker-compose.yaml @@ -1,9 +1,9 @@ version: "3.3" services: - customer-app-staging: - hostname: customer-service-staging - container_name: customer-service-staging + customer-app-stagingv1.0.0: + hostname: customer-service-stagingv1.0.0 + container_name: customer-service-stagingv1.0.0 image: $CI_REGISTRY_IMAGE/staging:$CI_COMMIT_REF_SLUG.$CI_PIPELINE_ID tty: true environment: