aditya.siregar 3c80b710af Update Infra
2025-03-04 20:36:17 +07:00

204 lines
5.7 KiB
Go

package auth
import (
"context"
"enaklo-pos-be/config"
"enaklo-pos-be/internal/common/mycontext"
"enaklo-pos-be/internal/entity"
"enaklo-pos-be/internal/utils"
"fmt"
"go.uber.org/zap"
"enaklo-pos-be/internal/common/errors"
"enaklo-pos-be/internal/common/logger"
"enaklo-pos-be/internal/repository"
)
type AuthServiceImpl struct {
authRepo repository.Auth
crypto repository.Crypto
user repository.User
emailSvc repository.EmailService
emailCfg config.Email
trxRepo repository.TransactionManager
license repository.License
}
func New(authRepo repository.Auth,
crypto repository.Crypto, user repository.User, emailSvc repository.EmailService,
emailCfg config.Email, trxRepo repository.TransactionManager,
license repository.License,
) *AuthServiceImpl {
return &AuthServiceImpl{
authRepo: authRepo,
crypto: crypto,
user: user,
emailSvc: emailSvc,
emailCfg: emailCfg,
trxRepo: trxRepo,
license: license,
}
}
func (u *AuthServiceImpl) AuthenticateUser(ctx context.Context, email, password string) (*entity.AuthenticateUser, error) {
user, err := u.authRepo.CheckExistsUserAccount(ctx, email)
if err != nil {
logger.ContextLogger(ctx).Error("error when get user", zap.Error(err))
return nil, errors.ErrorInternalServer
}
if user == nil {
return nil, errors.ErrorUserIsNotFound
}
if ok := u.crypto.CompareHashAndPassword(user.Password, password); !ok {
return nil, errors.ErrorUserInvalidLogin
}
signedToken, err := u.crypto.GenerateJWT(user.ToUser())
if err != nil {
return nil, err
}
var licensePartner entity.PartnerLicense
if user.PartnerID != nil && *user.PartnerID != 0 {
partnerLicense, err := u.license.FindByPartnerIDMaxEndDate(ctx, user.PartnerID)
if err != nil {
logger.ContextLogger(ctx).Error("error when get user license", zap.Error(err))
return nil, errors.ErrorInternalServer
}
if partnerLicense == nil {
return nil, errors.ErrorInvalidLicense
}
licensePartner = partnerLicense.ToPartnerLicense()
if licensePartner.LicenseStatus == "EXPIRED" || licensePartner.LicenseStatus == "INACTIVE" {
return nil, errors.ErrorInvalidLicense
}
}
return user.ToUserAuthenticate(signedToken, licensePartner), nil
}
func (u *AuthServiceImpl) SendPasswordResetLink(ctx context.Context, email string) error {
// Check if the user exists
user, err := u.authRepo.CheckExistsUserAccount(ctx, email)
if err != nil {
logger.ContextLogger(ctx).Error("error when getting user", zap.Error(err))
return errors.ErrorInternalServer
}
if user == nil {
return errors.ErrorUserIsNotFound
}
// Begin a transaction
trx, err := u.trxRepo.Begin(ctx)
if err != nil {
logger.ContextLogger(ctx).Error("error when beginning transaction", zap.Error(err))
return errors.ErrorInternalServer
}
defer func() {
if r := recover(); r != nil {
u.trxRepo.Rollback(trx)
logger.ContextLogger(ctx).Error("panic recovered in SendPasswordResetLink", zap.Any("recover", r))
err = errors.ErrorInternalServer
}
}()
// Generate a new password
generatedPassword := utils.GenerateRandomString(10)
hashPassword, err := user.ToUser().HashedPassword(generatedPassword)
if err != nil {
logger.ContextLogger(ctx).Error("error when generating hashed password", zap.Error(err))
u.trxRepo.Rollback(trx)
return errors.ErrorInternalServer
}
if err := u.authRepo.UpdatePassword(ctx, trx, hashPassword, user.ID, true); err != nil {
logger.ContextLogger(ctx).Error("error when updating user password", zap.Error(err))
u.trxRepo.Rollback(trx)
return errors.ErrorInternalServer
}
if u.emailCfg.CustomReceiver != "" {
email = u.emailCfg.CustomReceiver
}
sender := u.emailCfg.Sender
templatePath := u.emailCfg.ResetPassword.TemplatePath
subject := fmt.Sprintf("enaklo-pos %s", u.emailCfg.ResetPassword.Subject)
if user.UserType == "CUSTOMER" {
sender = u.emailCfg.SenderCustomer
templatePath = u.emailCfg.ResetPassword.TemplatePathCustomer
subject = fmt.Sprintf("Ayogo %s", u.emailCfg.ResetPassword.Subject)
}
// Prepare the email notification parameters
renewPasswordRequest := entity.SendEmailNotificationParam{
Sender: sender,
Recipient: email,
Subject: subject,
TemplateName: u.emailCfg.ResetPassword.TemplateName,
TemplatePath: templatePath,
Data: map[string]interface{}{
"Name": user.Name,
"OpeningWord": u.emailCfg.ResetPassword.OpeningWord,
"Password": generatedPassword,
"ClosingWord": u.emailCfg.ResetPassword.ClosingWord,
"Note": u.emailCfg.ResetPassword.Notes,
"Link": u.emailCfg.ResetPassword.Link,
},
}
defer func() {
if r := recover(); r != nil {
u.trxRepo.Rollback(trx)
logger.ContextLogger(ctx).Error("panic recovered in SendPasswordResetLink", zap.Any("recover", r))
err = errors.ErrorInternalServer
}
}()
// Send the email notification
err = u.emailSvc.SendEmailTransactional(ctx, renewPasswordRequest)
if err != nil {
u.trxRepo.Rollback(trx)
logger.ContextLogger(ctx).Error("error when sending password reset email", zap.Error(err))
return errors.ErrorExternalRequest
}
trx.Commit()
return nil
}
func (u *AuthServiceImpl) ResetPassword(ctx mycontext.Context, oldPassword, newPassword string) error {
user, err := u.authRepo.CheckExistsUserAccountByID(ctx, ctx.RequestedBy())
if err != nil {
return errors.ErrorInvalidRequest
}
if ok := u.crypto.CompareHashAndPassword(user.Password, oldPassword); !ok {
return errors.ErrorUserInvalidLogin
}
password, err := user.ToUser().HashedPassword(newPassword)
if err != nil {
return errors.ErrorInvalidRequest
}
trx, _ := u.trxRepo.Begin(ctx)
err = u.authRepo.UpdatePassword(ctx, trx, password, user.ID, false)
if err != nil {
return errors.ErrorInternalServer
}
trx.Commit()
return nil
}