customer/internal/service/account/account.go
2023-06-22 09:36:43 +00:00

238 lines
6.6 KiB
Go

package account
import (
"context"
"fmt"
"log"
"math"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
)
type accountRepository interface {
FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error)
FindMany(ctx context.Context, page, limit int64) ([]models.Account, errors.Error)
Insert(ctx context.Context, account *models.Account) (*models.Account, errors.Error)
Remove(ctx context.Context, id string) (*models.Account, errors.Error)
Delete(ctx context.Context, id string) (*models.Account, errors.Error)
CountAll(ctx context.Context) (int64, errors.Error)
SetStatus(ctx context.Context, userID string, status models.AccountStatus) (*models.Account, errors.Error)
UpdateName(ctx context.Context, userID string, name *models.Name) (*models.Account, errors.Error)
}
type authClient interface {
GetUser(ctx context.Context, userID string) (*models.User, errors.Error)
}
type Deps struct {
Logger *zap.Logger
Repository accountRepository
AuthClient authClient
}
type Service struct {
logger *zap.Logger
repository accountRepository
authClient authClient
}
func New(deps Deps) *Service {
if deps.Logger == nil {
log.Panicln("logger is nil on <New (account service)>")
}
if deps.Repository == nil {
log.Panicln("repository is nil on <New (account service)>")
}
if deps.AuthClient == nil {
log.Panicln("auth client is nil on <New (account service)>")
}
return &Service{
logger: deps.Logger,
repository: deps.Repository,
authClient: deps.AuthClient,
}
}
func (receiver *Service) GetAccountByUserID(ctx context.Context, userID string) (*models.Account, errors.Error) {
account, err := receiver.repository.FindByUserID(ctx, userID)
if err != nil {
receiver.logger.Error("failed to get account by id on <GetAccountByUserID> of <AccountService>",
zap.Error(err),
zap.String("userID", userID),
)
return nil, err
}
return account, nil
}
func (receiver *Service) GetAccountsList(ctx context.Context, pagination *models.Pagination) (*models.PaginationResponse[models.Account], errors.Error) {
if pagination == nil {
return nil, errors.New(
fmt.Errorf("pagination is nil on <GetAccountsList> of <AccountService>: %w", errors.ErrInternalError),
errors.ErrInternalError,
)
}
count, err := receiver.repository.CountAll(ctx)
if err != nil {
receiver.logger.Error("failed to count accounts on <GetAccountsList> of <AccountService>",
zap.Error(err),
)
return nil, err
}
if count == 0 {
return &models.PaginationResponse[models.Account]{TotalPages: 0, Records: []models.Account{}}, nil
}
totalPages := int64(math.Ceil(float64(count) / float64(pagination.Limit)))
accounts, err := receiver.repository.FindMany(ctx, pagination.Page, pagination.Limit)
if err != nil {
receiver.logger.Error("failed to get accounts list on <GetAccountsList> of <AccountService>",
zap.Error(err),
zap.Int64("page", pagination.Page),
zap.Int64("limit", pagination.Limit),
)
return nil, err
}
return &models.PaginationResponse[models.Account]{
TotalPages: totalPages,
Records: accounts,
}, nil
}
func (receiver *Service) CreateAccount(ctx context.Context, account *models.Account) (*models.Account, errors.Error) {
findedAccount, err := receiver.GetAccountByUserID(ctx, account.UserID)
if err != nil && err.Type() != errors.ErrNotFound {
receiver.logger.Error("failed to find account on <CreateAccount> of <AccountService>",
zap.Error(err),
)
return nil, err
}
if findedAccount != nil {
return nil, errors.New(
fmt.Errorf("failed to create account with <%s> on <CreateAccount> of <AccountService>: %w",
account.UserID,
errors.ErrConflict,
),
errors.ErrConflict,
)
}
createdAccount, err := receiver.repository.Insert(ctx, account)
if err != nil {
receiver.logger.Error("failed to create account on <CreateAccount> of <AccountService>",
zap.Error(err),
zap.Any("account", account),
)
return nil, err
}
return createdAccount, nil
}
func (receiver *Service) CreateAccountByUserID(ctx context.Context, userID string) (*models.Account, errors.Error) {
account, err := receiver.GetAccountByUserID(ctx, userID)
if err != nil && err.Type() != errors.ErrNotFound {
receiver.logger.Error("failed to find account on <CreateAccountByUserID> of <AccountService>",
zap.Error(err),
)
return nil, err
}
if account != nil {
return nil, errors.New(
fmt.Errorf("failed to create account with <%s> on <CreateAccountByUserID> of <AccountService>: %w",
userID,
errors.ErrConflict,
),
errors.ErrConflict,
)
}
user, err := receiver.authClient.GetUser(ctx, userID)
if err != nil {
receiver.logger.Error("failed to get user on <CreateAccountByUserID> of <AccountService>",
zap.Error(err),
zap.String("userID", userID),
)
return nil, err
}
createdAccount, err := receiver.repository.Insert(ctx, &models.Account{UserID: user.ID})
if err != nil {
receiver.logger.Error("failed to create account on <CreateAccountByUserID> of <AccountService>",
zap.Error(err),
zap.String("userID", userID),
)
return nil, err
}
return createdAccount, nil
}
func (receiver *Service) RemoveAccount(ctx context.Context, userID string) (*models.Account, errors.Error) {
account, err := receiver.repository.Remove(ctx, userID)
if err != nil {
receiver.logger.Error("failed to remove account on <RemoveAccount> of <AccountService>",
zap.Error(err),
zap.String("userID", userID),
)
return nil, err
}
return account, nil
}
func (receiver *Service) DeleteAccount(ctx context.Context, userID string) (*models.Account, errors.Error) {
account, err := receiver.repository.Delete(ctx, userID)
if err != nil {
receiver.logger.Error("failed to delete account on <DeleteAccount> of <AccountService>",
zap.Error(err),
zap.String("userID", userID),
)
return nil, err
}
return account, nil
}
func (receiver *Service) SetVerificationStatus(ctx context.Context, userID string, status models.AccountStatus) (*models.Account, errors.Error) {
account, err := receiver.repository.SetStatus(ctx, userID, status)
if err != nil {
receiver.logger.Error("failed to set status on <SetVerificationStatus> of <AccountService>", zap.Error(err))
return nil, err
}
return account, nil
}
func (receiver *Service) UpdateAccountName(ctx context.Context, userID string, name *models.Name) (*models.Account, errors.Error) {
account, err := receiver.repository.UpdateName(ctx, userID, name)
if err != nil {
receiver.logger.Error("failed to update account name on <UpdateAccountName> of <AccountService>", zap.Error(err))
return nil, err
}
return account, nil
}