generated from PenaSide/GolangTemplate
306 lines
8.6 KiB
Go
306 lines
8.6 KiB
Go
package account
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"go.uber.org/zap"
|
|
"math"
|
|
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
|
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"
|
|
"time"
|
|
)
|
|
|
|
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) Delete(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) Update(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) SetVerificationStatus(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 <SetVerificationStatus> of <AccountService>", zap.Error(err))
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
}
|
|
|
|
return ctx.Status(fiber.StatusOK).JSON(account)
|
|
}
|
|
|
|
func (receiver *AccountController) Get(ctx *fiber.Ctx) error {
|
|
userID, ok := receiver.middleWare.ExtractUserID(ctx)
|
|
if !ok || userID == "" {
|
|
return receiver.middleWare.NoAuth(ctx)
|
|
}
|
|
|
|
hlogger := log_mw.ExtractLogger(ctx)
|
|
|
|
account, err := receiver.accountRepo.FindByUserID(ctx.Context(), userID)
|
|
if err != nil {
|
|
if err.Type() == errors.ErrNotFound {
|
|
return receiver.middleWare.Error(ctx, fiber.StatusNotFound, "no account", err)
|
|
}
|
|
return receiver.middleWare.ErrorOld(ctx, err)
|
|
}
|
|
|
|
hlogger.Emit(models.InfoGetAccount{
|
|
CtxUserID: userID,
|
|
CtxAccountID: account.ID,
|
|
})
|
|
|
|
return ctx.Status(fiber.StatusOK).JSON(account)
|
|
}
|
|
|
|
func (receiver *AccountController) Create(ctx *fiber.Ctx) error {
|
|
userID, ok := receiver.middleWare.ExtractUserID(ctx)
|
|
if !ok || userID == "" {
|
|
return receiver.middleWare.NoAuth(ctx)
|
|
}
|
|
|
|
hlogger := log_mw.ExtractLogger(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)
|
|
}
|
|
|
|
quiz := ""
|
|
if quizFrom != "" {
|
|
quiz = "quiz"
|
|
}
|
|
|
|
hlogger.Emit(models.InfoCreateAccount{
|
|
CtxUserID: userID,
|
|
CtxAccountID: account.ID,
|
|
KeyFromSource: quiz,
|
|
KeyFromID: quizFrom,
|
|
KeyFromPartner: quizUser,
|
|
CtxLogin: user.Login,
|
|
CtxEmail: user.Email,
|
|
CtxPhone: user.PhoneNumber,
|
|
KeyCurrency: account.Wallet.Currency,
|
|
})
|
|
|
|
return ctx.Status(fiber.StatusOK).JSON(account)
|
|
}
|
|
|
|
func (receiver *AccountController) DeleteCurrent(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) GetCurrent(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) Pagination(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)
|
|
}
|
|
|
|
func (receiver *AccountController) AccountPipe(ctx *fiber.Ctx) error {
|
|
userID, ok := receiver.middleWare.ExtractUserID(ctx)
|
|
if !ok || userID == "" {
|
|
return receiver.middleWare.NoAuth(ctx)
|
|
}
|
|
|
|
ctx.Set(fiber.HeaderContentType, "text/event-stream")
|
|
ctx.Set("Cache-Control", "no-cache")
|
|
ctx.Set("Connection", "keep-alive")
|
|
ctx.Set("Transfer-Encoding", "chunked")
|
|
|
|
accountCh := make(chan map[string]interface{})
|
|
cancelCtx, cancel := context.WithCancel(ctx.Context())
|
|
|
|
go func(ctx context.Context) {
|
|
defer close(accountCh)
|
|
if err := receiver.accountRepo.AccountPipe(ctx, userID, accountCh); err != nil {
|
|
receiver.logger.Error("error in account pipe repo method", zap.Error(err))
|
|
}
|
|
}(cancelCtx)
|
|
|
|
ctx.Status(fiber.StatusOK).Context().SetBodyStreamWriter(func(w *bufio.Writer) {
|
|
pingTicker := time.NewTicker(5 * time.Second)
|
|
defer pingTicker.Stop()
|
|
for {
|
|
select {
|
|
case accountData, ok := <-accountCh:
|
|
if !ok {
|
|
return
|
|
}
|
|
accountJSON, err := json.Marshal(accountData)
|
|
if err != nil {
|
|
//receiver.logger.Error("error marshal account JSON", zap.Error(err))
|
|
continue
|
|
}
|
|
fmt.Fprintf(w, "data: %s\n\n", accountJSON)
|
|
if err := w.Flush(); err != nil {
|
|
receiver.logger.Error("error flushing", zap.Error(err))
|
|
cancel()
|
|
receiver.logger.Info("Close connection Account Pipe sse")
|
|
return
|
|
}
|
|
case <-pingTicker.C:
|
|
fmt.Fprintf(w, "data: %s\n\n", `{"event": "ping"}`)
|
|
if err := w.Flush(); err != nil {
|
|
receiver.logger.Error("error sending ping Account Pipe sse, close connection", zap.Error(err))
|
|
cancel()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
return nil
|
|
}
|