core/internal/controllers/http_controllers/account/account.go

421 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package account
import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/gofiber/fiber/v2"
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/pj_errors"
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/brokers"
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/clients/auth"
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/models"
"strconv"
"time"
)
type Deps struct {
Dal *dal.DAL
AuthClient *auth.AuthClient
Producer *brokers.Producer
ServiceName string
RedisClient *redis.Client
}
type Account struct {
dal *dal.DAL
authClient *auth.AuthClient
producer *brokers.Producer
serviceName string
redisClient *redis.Client
}
func NewAccountController(deps Deps) *Account {
return &Account{
dal: deps.Dal,
authClient: deps.AuthClient,
producer: deps.Producer,
serviceName: deps.ServiceName,
redisClient: deps.RedisClient,
}
}
type CreateAccountReq struct {
UserID string `json:"userId"`
}
type CreateAccountResp struct {
CreatedAccount model.Account `json:"created_account"`
}
type DeleteAccountResp struct {
DeletedAccountID string `json:"account_Id"`
}
type GetPrivilegeByUserIDReq struct {
UserID string `json:"userId"`
}
type DeleteAccountByUserIDReq struct {
UserID string `json:"userId"`
}
type DeleteAccountByUserIDResp struct {
DeletedAccountUserID string `json:"userId"`
}
type GetAccountsReq struct {
Limit uint64 `json:"limit"`
Page uint64 `json:"page"`
}
type GetAccountsResp struct {
Count uint64 `json:"count"`
Items []model.Account `json:"items"`
}
// getCurrentAccount обработчик для получения текущего аккаунта
func (r *Account) GetCurrentAccount(ctx *fiber.Ctx) error {
accountID, ok := middleware.GetAccountId(ctx)
if !ok {
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
}
account, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
if err != nil && err != sql.ErrNoRows {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
//TODO: fix this later
if account.ID == "" {
return ctx.Status(fiber.StatusNotFound).SendString("no account")
}
return ctx.Status(fiber.StatusOK).JSON(account)
}
// createAccount обработчик для создания нового аккаунта
func (r *Account) CreateAccount(ctx *fiber.Ctx) error {
accountID, ok := middleware.GetAccountId(ctx)
if !ok {
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
}
hlogger := log_mw.ExtractLogger(ctx)
existingAccount, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
if err != nil && err != sql.ErrNoRows {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
if existingAccount.ID != "" {
return ctx.Status(fiber.StatusConflict).SendString("user with this ID already exists")
}
email, err := r.authClient.GetUserEmail(accountID)
if err != nil {
return err
}
newAccount := model.Account{
UserID: accountID,
CreatedAt: time.Now(),
Deleted: false,
Privileges: map[string]model.ShortPrivilege{
"quizUnlimTime": {
PrivilegeID: "quizUnlimTime",
PrivilegeName: "Безлимит Опросов",
Amount: 14,
CreatedAt: time.Now(),
},
},
}
createdAcc, err := r.dal.AccountRepo.CreateAccount(ctx.Context(), &newAccount)
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
_, err = r.dal.AccountRepo.PostLeadTarget(ctx.Context(), model.LeadTarget{
AccountID: accountID,
Target: email,
Type: model.LeadTargetEmail,
QuizID: 0,
})
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
hlogger.Emit(models.InfoAccountCreated{
CtxUserID: accountID,
CtxAccountID: createdAcc.ID,
})
err = r.producer.ToMailNotify(ctx.Context(), brokers.Message{
AccountID: accountID,
Email: email,
ServiceKey: r.serviceName,
SendAt: time.Now(),
})
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
return ctx.JSON(CreateAccountResp{
CreatedAccount: newAccount,
})
}
// deleteAccount обработчик для удаления текущего аккаунта
func (r *Account) DeleteAccount(ctx *fiber.Ctx) error {
accountID, ok := middleware.GetAccountId(ctx)
if !ok {
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
}
account, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
if err := r.dal.AccountRepo.DeleteAccount(ctx.Context(), account.ID); err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
return ctx.JSON(DeleteAccountResp{
DeletedAccountID: accountID,
})
}
// getPrivilegeByUserID обработчик для получения привилегий аккаунта по ID пользователя
func (r *Account) GetPrivilegeByUserID(ctx *fiber.Ctx) error {
var req GetPrivilegeByUserIDReq
if err := ctx.BodyParser(&req); err != nil {
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
}
privilege, err := r.dal.AccountRepo.GetPrivilegesByAccountID(ctx.Context(), req.UserID)
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
return ctx.Status(fiber.StatusOK).JSON(privilege)
}
// deleteAccountByUserID обработчик для удаления аккаунта по ID пользователя
func (r *Account) DeleteAccountByUserID(ctx *fiber.Ctx) error {
var req DeleteAccountByUserIDReq
if err := ctx.BodyParser(&req); err != nil {
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
}
existingAccount, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), req.UserID)
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
if existingAccount.ID == "" {
return ctx.Status(fiber.StatusInternalServerError).SendString("user with this ID not found")
}
if err := r.dal.AccountRepo.DeleteAccount(ctx.Context(), existingAccount.ID); err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
return ctx.JSON(DeleteAccountByUserIDResp{
DeletedAccountUserID: req.UserID,
})
}
// getAccounts обработчик для получения списка аккаунтов с пагинацией
func (r *Account) GetAccounts(ctx *fiber.Ctx) error {
var req GetAccountsReq
if err := ctx.BodyParser(&req); err != nil {
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
}
_, ok := middleware.GetAccountId(ctx)
if !ok {
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
}
accounts, totalCount, err := r.dal.AccountRepo.GetAccounts(ctx.Context(), req.Limit, req.Page)
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
response := GetAccountsResp{
Count: totalCount,
Items: accounts,
}
return ctx.Status(fiber.StatusOK).JSON(response)
}
func (r *Account) ManualDone(ctx *fiber.Ctx) error {
var req struct {
Id string `json:"id"`
}
if err := ctx.BodyParser(&req); err != nil {
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
}
if req.Id == "" {
return ctx.Status(fiber.StatusBadRequest).SendString("User id is required")
}
err := r.dal.AccountRepo.ManualDone(ctx.Context(), req.Id)
if err != nil {
if errors.Is(err, pj_errors.ErrNotFound) {
return ctx.Status(fiber.StatusNotFound).SendString("user don't have this privilege")
}
return ctx.Status(fiber.StatusInternalServerError).SendString("Internal Server Error")
}
return ctx.SendStatus(fiber.StatusOK)
}
func (r *Account) PostLeadTarget(ctx *fiber.Ctx) error {
var req struct {
Type string `json:"type"`
QuizID int32 `json:"quizID"`
Target string `json:"target"`
Name string `json:"name"`
}
if err := ctx.BodyParser(&req); err != nil {
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
}
accountID, ok := middleware.GetAccountId(ctx)
if !ok {
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
}
//accountID := "64f2cd7a7047f28fdabf6d9e"
if _, ok := model.ValidLeadTargetTypes[req.Type]; !ok {
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid type")
}
if req.Type == "" || (req.Target == "" && req.Type != string(model.LeadTargetTg)) {
return ctx.Status(fiber.StatusBadRequest).SendString("Type and Target don't be nil")
}
switch req.Type {
case "mail":
_, err := r.dal.AccountRepo.PostLeadTarget(ctx.Context(), model.LeadTarget{
AccountID: accountID,
Target: req.Target,
Type: model.LeadTargetType(req.Type),
QuizID: req.QuizID,
})
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
return ctx.SendStatus(fiber.StatusOK)
case "telegram":
targets, err := r.dal.AccountRepo.GetLeadTarget(ctx.Context(), accountID, req.QuizID)
if err != nil && !errors.Is(err, pj_errors.ErrNotFound) {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
if !errors.Is(err, pj_errors.ErrNotFound) {
for _, t := range targets {
if t.Type == model.LeadTargetTg {
return ctx.Status(fiber.StatusAlreadyReported).SendString("LeadTarget for this quiz already exist")
}
}
}
task := model.TgRedisTask{
Name: req.Name,
QuizID: req.QuizID,
AccountID: accountID,
}
taskKey := fmt.Sprintf("telegram_task:%d", time.Now().UnixNano())
taskData, err := json.Marshal(task)
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
if err := r.redisClient.Set(ctx.Context(), taskKey, taskData, 0).Err(); err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
case "whatsapp":
return ctx.Status(fiber.StatusOK).SendString("todo")
}
return nil
}
func (r *Account) DeleteLeadTarget(ctx *fiber.Ctx) error {
leadIDStr := ctx.Params("id")
leadID, err := strconv.ParseInt(leadIDStr, 10, 64)
if err != nil {
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid lead ID format")
}
err = r.dal.AccountRepo.DeleteLeadTarget(ctx.Context(), leadID)
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
return ctx.SendStatus(fiber.StatusOK)
}
func (r *Account) GetLeadTarget(ctx *fiber.Ctx) error {
accountID, ok := middleware.GetAccountId(ctx)
if !ok {
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
}
quizIDStr := ctx.Params("quizID")
quizID, err := strconv.ParseInt(quizIDStr, 10, 64)
if err != nil {
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid quiz ID format")
}
result, err := r.dal.AccountRepo.GetLeadTarget(ctx.Context(), accountID, int32(quizID))
if err != nil {
switch {
case errors.Is(err, pj_errors.ErrNotFound):
return ctx.Status(fiber.StatusNotFound).SendString("this lead target not found")
default:
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
}
return ctx.Status(fiber.StatusOK).JSON(result)
}
func (r *Account) UpdateLeadTarget(ctx *fiber.Ctx) error {
var req struct {
ID int64 `json:"id"`
Target string `json:"target"`
}
if err := ctx.BodyParser(&req); err != nil {
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
}
if req.ID == 0 || req.Target == "" {
return ctx.Status(fiber.StatusBadRequest).SendString("ID and Target don't be nil")
}
result, err := r.dal.AccountRepo.UpdateLeadTarget(ctx.Context(), model.LeadTarget{
ID: req.ID,
Target: req.Target,
})
if err != nil {
switch {
case errors.Is(err, pj_errors.ErrNotFound):
return ctx.Status(fiber.StatusNotFound).SendString("this lead target not found")
default:
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
}
}
return ctx.Status(fiber.StatusOK).JSON(result)
}