add forget password

This commit is contained in:
aditya.siregar
2024-07-23 01:36:25 +07:00
parent 7ea809cc09
commit 5a0dec6128
22 changed files with 907 additions and 76 deletions
+11 -1
View File
@@ -53,6 +53,13 @@ func NewServiceException(errType ErrType) *ServiceException {
}
}
func NewError(errType ErrType, message string) *ServiceException {
return &ServiceException{
errorType: errType,
message: message,
}
}
func (s *ServiceException) ErrorType() ErrType {
return s.errorType
}
@@ -95,7 +102,10 @@ func (s *ServiceException) MapErrorsToCode() Code {
case errUserIsNotFound:
return BadRequest
case errInvalidLogin:
return BadRequest
default:
return ServerError
return BadRequest
}
}
+15 -12
View File
@@ -34,6 +34,7 @@ type UserDB struct {
DeletedAt *time.Time `gorm:"column:deleted_at" json:"deleted_at"`
CreatedBy int64 `gorm:"column:created_by" json:"created_by"`
UpdatedBy int64 `gorm:"column:updated_by" json:"updated_by"`
ResetPassword bool `gorm:"column:reset_password" json:"reset_password"`
}
func (u *UserDB) ToUser() *User {
@@ -42,18 +43,19 @@ func (u *UserDB) ToUser() *User {
}
userEntity := &User{
ID: u.ID,
Name: u.Name,
Email: u.Email,
Status: u.Status,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
RoleID: role.Role(u.RoleID),
RoleName: u.RoleName,
PartnerID: u.PartnerID,
PartnerName: u.PartnerName,
SiteID: u.SiteID,
SiteName: u.SiteName,
ID: u.ID,
Name: u.Name,
Email: u.Email,
Status: u.Status,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
RoleID: role.Role(u.RoleID),
RoleName: u.RoleName,
PartnerID: u.PartnerID,
PartnerName: u.PartnerName,
SiteID: u.SiteID,
SiteName: u.SiteName,
ResetPassword: u.ResetPassword,
}
return userEntity
@@ -92,6 +94,7 @@ func (u *UserDB) ToUserAuthenticate(signedToken string) *AuthenticateUser {
PartnerStatus: u.PartnerStatus,
SiteID: u.SiteID,
SiteName: u.SiteName,
ResetPassword: u.ResetPassword,
}
}
+13
View File
@@ -0,0 +1,13 @@
package entity
type (
SendEmailNotificationParam struct {
Sender string
Recipient string
CcEmails []string
Subject string
TemplateName string
TemplatePath string
Data interface{}
}
)
+16 -14
View File
@@ -10,20 +10,21 @@ import (
)
type User struct {
ID int64
Name string
Email string
Password string
Status userstatus.UserStatus
NIK string
CreatedAt time.Time
UpdatedAt time.Time
RoleID role.Role
RoleName string
PartnerID *int64
SiteID *int64
SiteName string
PartnerName string
ID int64
Name string
Email string
Password string
Status userstatus.UserStatus
NIK string
CreatedAt time.Time
UpdatedAt time.Time
RoleID role.Role
RoleName string
PartnerID *int64
SiteID *int64
SiteName string
PartnerName string
ResetPassword bool
}
type AuthenticateUser struct {
@@ -36,6 +37,7 @@ type AuthenticateUser struct {
PartnerStatus string
SiteID *int64
SiteName string
ResetPassword bool
}
type UserRoleDB struct {
+74 -1
View File
@@ -1,6 +1,7 @@
package auth
import (
"fmt"
"furtuna-be/internal/constants/role"
"net/http"
@@ -19,6 +20,8 @@ type AuthHandler struct {
func (a *AuthHandler) Route(group *gin.RouterGroup, jwt gin.HandlerFunc) {
authRoute := group.Group("/auth")
authRoute.POST("/login", a.AuthLogin)
authRoute.POST("/forgot-password", a.ForgotPassword)
authRoute.POST("/reset-password", jwt, a.ResetPassword)
}
func NewAuthHandler(service services.Auth) *AuthHandler {
@@ -77,7 +80,8 @@ func (h *AuthHandler) AuthLogin(c *gin.Context) {
ID: int64(authUser.RoleID),
Role: authUser.RoleName,
},
Site: site,
Site: site,
ResetPassword: authUser.ResetPassword,
}
c.JSON(http.StatusOK, response.BaseResponse{
@@ -87,3 +91,72 @@ func (h *AuthHandler) AuthLogin(c *gin.Context) {
Data: resp,
})
}
// ForgotPassword handles the request for password reset.
// @Summary Request password reset
// @Description Sends a password reset link to the user's email.
// @Accept json
// @Produce json
// @Param bodyParam body auth2.ForgotPasswordRequest true "User email"
// @Success 200 {object} response.BaseResponse "Password reset link sent"
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
// @Router /api/v1/auth/forgot-password [post]
// @Tags Auth Password API's
func (h *AuthHandler) ForgotPassword(c *gin.Context) {
var bodyParam auth2.ResetPasswordRequest
if err := c.ShouldBindJSON(&bodyParam); err != nil {
response.ErrorWrapper(c, errors.ErrorBadRequest)
return
}
err := h.service.SendPasswordResetLink(c, bodyParam.Email)
if err != nil {
response.ErrorWrapper(c, err)
return
}
c.JSON(http.StatusOK, response.BaseResponse{
Success: true,
Status: http.StatusOK,
Message: "Password reset link sent",
})
}
// ResetPassword handles the password reset process.
// @Summary Reset user password
// @Description Resets the user's password using the provided token.
// @Accept json
// @Produce json
// @Param bodyParam body auth2.ResetPasswordRequest true "Reset password details"
// @Success 200 {object} response.BaseResponse "Password reset successful"
// @Failure 400 {object} response.BaseResponse{data=errors.Error} "Bad request"
// @Router /api/v1/auth/reset-password [post]
// @Tags Auth Password API's
func (h *AuthHandler) ResetPassword(c *gin.Context) {
ctx := auth2.GetMyContext(c)
var req auth2.ResetPasswordChangeRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.ErrorWrapper(c, errors.ErrorBadRequest)
return
}
if err := req.Validate(); err != nil {
response.ErrorWrapper(c, errors.NewError(
errors.ErrorBadRequest.ErrorType(),
fmt.Sprintf("invalid request %v", err.Error())))
return
}
err := h.service.ResetPassword(ctx, req.OldPassword, req.NewPassword)
if err != nil {
response.ErrorWrapper(c, err)
return
}
c.JSON(http.StatusOK, response.BaseResponse{
Success: true,
Status: http.StatusOK,
Message: "Password reset successful",
})
}
+65 -2
View File
@@ -1,5 +1,11 @@
package request
import (
"errors"
"fmt"
"github.com/go-playground/validator/v10"
)
type LoginRequest struct {
Email string `json:"email"`
Password string `json:"password"`
@@ -10,6 +16,63 @@ type ResetPasswordRequest struct {
}
type ResetPasswordChangeRequest struct {
Token string `json:"token" validate:"required"`
Password string `json:"password" validate:"required"`
OldPassword string `json:"old_password" validate:"required"`
NewPassword string `json:"new_password" validate:"required,strongpwd"`
}
func (e *ResetPasswordChangeRequest) Validate() error {
validate := validator.New()
validate.RegisterValidation("strongpwd", validateStrongPassword)
if err := validate.Struct(e); err != nil {
// Handle the validation errors
for _, err := range err.(validator.ValidationErrors) {
switch err.Field() {
case "NewPassword":
return fmt.Errorf("%w", validatePasswordError(err.Tag()))
default:
return fmt.Errorf("validation failed: %w", err)
}
}
}
return nil
}
func validateStrongPassword(fl validator.FieldLevel) bool {
password := fl.Field().String()
var (
hasMinLen = len(password) >= 8
)
return hasMinLen
}
// Error messages for password validation
var (
ErrPasswordTooShort = errors.New("password must be at least 8 characters long")
ErrPasswordNoUpper = errors.New("password must contain at least one uppercase letter")
ErrPasswordNoLower = errors.New("password must contain at least one lowercase letter")
ErrPasswordNoNumber = errors.New("password must contain at least one digit")
ErrPasswordNoSpecial = errors.New("password must contain at least one special character (!@#$%^&*)")
ErrPasswordValidation = errors.New("password does not meet the strength requirements")
)
func validatePasswordError(tag string) error {
switch tag {
case "min":
return ErrPasswordTooShort
case "uppercase":
return ErrPasswordNoUpper
case "lowercase":
return ErrPasswordNoLower
case "number":
return ErrPasswordNoNumber
case "special":
return ErrPasswordNoSpecial
default:
return ErrPasswordValidation
}
}
+6 -5
View File
@@ -1,11 +1,12 @@
package response
type LoginResponse struct {
Token string `json:"token"`
Name string `json:"name"`
Role Role `json:"role"`
Partner *Partner `json:"partner"`
Site *SiteName `json:"site,omitempty"`
Token string `json:"token"`
Name string `json:"name"`
Role Role `json:"role"`
Partner *Partner `json:"partner"`
Site *SiteName `json:"site,omitempty"`
ResetPassword bool `json:"reset_password"`
}
type Role struct {
+48 -1
View File
@@ -26,7 +26,8 @@ func (r *AuthRepository) CheckExistsUserAccount(ctx context.Context, email strin
err := r.db.
Table("users").
Select("users.*, user_roles.role_id, user_roles.partner_id, user_roles.site_id, sites.name, roles.role_name, partners.name as partner_name, partners.status as partner_status").
Select("users.*, user_roles.role_id, user_roles.partner_id, user_roles.site_id,"+
" sites.name, roles.role_name, partners.name as partner_name, partners.status as partner_status, users.reset_password").
Where("users.email = ?", email).
Joins("left join user_roles on users.id = user_roles.user_id").
Joins("left join roles on user_roles.role_id = roles.role_id").
@@ -49,3 +50,49 @@ func (r *AuthRepository) CheckExistsUserAccount(ctx context.Context, email strin
return &user, nil
}
func (r *AuthRepository) CheckExistsUserAccountByID(ctx context.Context, userID int64) (*entity.UserDB, error) {
var user entity.UserDB
err := r.db.
Table("users").
Select("users.*, user_roles.role_id, user_roles.partner_id, user_roles.site_id, sites.name, roles.role_name, partners.name as partner_name, partners.status as partner_status").
Where("users.id = ?", userID).
Joins("left join user_roles on users.id = user_roles.user_id").
Joins("left join roles on user_roles.role_id = roles.role_id").
Joins("left join partners on user_roles.partner_id = partners.id").
Joins("left join sites on user_roles.site_id = sites.id").
First(&user).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("user with not exist") // or use a custom error type
}
logger.ContextLogger(ctx).Error(fmt.Sprintf("Failed to get user"), zap.Error(err))
return nil, err
}
return &user, nil
}
func (r *AuthRepository) UpdatePassword(ctx context.Context, trx *gorm.DB, newHashedPassword string, userID int64, resetPassword bool) error {
// Perform the update using a single Updates call
err := trx.Model(&entity.UserDB{}).
Where("id = ?", userID).
Updates(map[string]interface{}{
"password": newHashedPassword,
"reset_password": resetPassword,
}).Error
if err != nil {
logger.ContextLogger(ctx).Error(fmt.Sprintf("Failed to update password for user with id: %d", userID), zap.Error(err))
return err
}
return nil
}
+88
View File
@@ -0,0 +1,88 @@
package brevo
import (
"bytes"
"context"
"fmt"
"furtuna-be/internal/entity"
"html/template"
"io/ioutil"
"log"
brevo "github.com/getbrevo/brevo-go/lib"
)
type Config interface {
GetApiKey() string
}
type ServiceImpl struct {
brevoConn *brevo.APIClient
}
func (s ServiceImpl) SendEmailTransactional(ctx context.Context, param entity.SendEmailNotificationParam) error {
templateFile, err := ioutil.ReadFile(param.TemplatePath)
if err != nil {
log.Println(err)
return err
}
renderedTemplate, err := template.New(param.TemplateName).Parse(string(templateFile))
if err != nil {
log.Println(err)
return err
}
return s.sendEmail(ctx, renderedTemplate, param)
}
func (s ServiceImpl) sendEmail(ctx context.Context, tmpl *template.Template, param entity.SendEmailNotificationParam) error {
var body bytes.Buffer
err := tmpl.Execute(&body, param.Data)
if err != nil {
log.Println(err)
return err
}
payload := brevo.SendSmtpEmail{
Sender: &brevo.SendSmtpEmailSender{
Email: "siregaraditya@gmail.com",
},
To: []brevo.SendSmtpEmailTo{
{
Email: "avranata01@gmail.com",
},
},
Subject: param.Subject,
HtmlContent: body.String(),
}
if len(param.CcEmails) != 0 {
for _, email := range param.CcEmails {
payload.Cc = append(payload.Cc, brevo.SendSmtpEmailCc{
Email: email,
})
}
}
_, _, err = s.brevoConn.TransactionalEmailsApi.SendTransacEmail(ctx, payload)
if err != nil {
return err
}
return nil
}
func New(conf Config) *ServiceImpl {
cfg := brevo.NewConfiguration()
cfg.AddDefaultHeader("api-key", conf.GetApiKey())
client := brevo.NewAPIClient(cfg)
result, resp, err := client.AccountApi.GetAccount(context.Background())
if err != nil {
fmt.Println("Error when calling AccountApi->get_account: ", err.Error())
log.Fatal("error")
}
fmt.Println("GetAccount Object:", result, " GetAccount Response: ", resp)
return &ServiceImpl{brevoConn: client}
}
+46
View File
@@ -23,6 +23,8 @@ type CryptoConfig interface {
AccessTokenOrderSecret() string
AccessTokenOrderExpiresDate() time.Time
AccessTokenExpiresDate() time.Time
AccessTokenResetPasswordSecret() string
AccessTokenResetPasswordExpire() time.Time
}
type CryptoImpl struct {
@@ -83,6 +85,30 @@ func (c *CryptoImpl) GenerateJWT(user *entity.User) (string, error) {
return token, nil
}
func (c *CryptoImpl) GenerateJWTReseetPassword(user *entity.User) (string, error) {
claims := &entity.JWTAuthClaims{
StandardClaims: jwt.StandardClaims{
Subject: strconv.FormatInt(user.ID, 10),
ExpiresAt: c.Config.AccessTokenResetPasswordExpire().Unix(),
IssuedAt: time.Now().Unix(),
NotBefore: time.Now().Unix(),
},
UserID: user.ID,
Name: user.Name,
Email: user.Email,
}
token, err := jwt.
NewWithClaims(jwt.SigningMethodHS256, claims).
SignedString([]byte(c.Config.AccessTokenResetPasswordSecret()))
if err != nil {
return "", err
}
return token, nil
}
func (c *CryptoImpl) ParseAndValidateJWT(tokenString string) (*entity.JWTAuthClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &entity.JWTAuthClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(c.Config.AccessTokenSecret()), nil
@@ -140,3 +166,23 @@ func (c *CryptoImpl) ValidateJWTOrder(tokenString string) (int64, int64, error)
return claims.PartnerID, claims.OrderID, nil
}
func (c *CryptoImpl) ValidateResetPassword(tokenString string) (int64, error) {
token, err := jwt.ParseWithClaims(tokenString, &entity.JWTOrderClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(c.Config.AccessTokenResetPasswordSecret()), nil
})
if err != nil {
return 0, err
}
claims, ok := token.Claims.(*entity.JWTAuthClaims)
if !ok || !token.Valid {
return 0, fmt.Errorf("invalid token %v", token.Header["alg"])
}
return claims.UserID, nil
}
+41 -30
View File
@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"furtuna-be/internal/repository/branches"
"furtuna-be/internal/repository/brevo"
mdtrns "furtuna-be/internal/repository/midtrans"
"furtuna-be/internal/repository/orders"
"furtuna-be/internal/repository/oss"
@@ -26,45 +27,49 @@ import (
)
type RepoManagerImpl struct {
Crypto Crypto
Auth Auth
Event Event
User User
Branch Branch
Studio Studio
Product Product
Order Order
OSS OSSRepository
Partner PartnerRepository
Site SiteRepository
Trx TransactionManager
Wallet WalletRepository
Midtrans Midtrans
Payment Payment
Crypto Crypto
Auth Auth
Event Event
User User
Branch Branch
Studio Studio
Product Product
Order Order
OSS OSSRepository
Partner PartnerRepository
Site SiteRepository
Trx TransactionManager
Wallet WalletRepository
Midtrans Midtrans
Payment Payment
EmailService EmailService
}
func NewRepoManagerImpl(db *gorm.DB, cfg *config.Config) *RepoManagerImpl {
return &RepoManagerImpl{
Crypto: crypto.NewCrypto(cfg.Auth()),
Auth: auth.NewAuthRepository(db),
Event: event.NewEventRepo(db),
User: users.NewUserRepository(db),
Branch: branches.NewBranchRepository(db),
Studio: studios.NewStudioRepository(db),
Product: products.NewProductRepository(db),
Order: orders.NewOrderRepository(db),
OSS: oss.NewOssRepositoryImpl(cfg.OSSConfig),
Partner: partners.NewPartnerRepository(db),
Site: sites.NewSiteRepository(db),
Trx: trx.NewGormTransactionManager(db),
Wallet: repository.NewWalletRepository(db),
Midtrans: mdtrns.New(&cfg.Midtrans),
Payment: payment.NewPaymentRepository(db),
Crypto: crypto.NewCrypto(cfg.Auth()),
Auth: auth.NewAuthRepository(db),
Event: event.NewEventRepo(db),
User: users.NewUserRepository(db),
Branch: branches.NewBranchRepository(db),
Studio: studios.NewStudioRepository(db),
Product: products.NewProductRepository(db),
Order: orders.NewOrderRepository(db),
OSS: oss.NewOssRepositoryImpl(cfg.OSSConfig),
Partner: partners.NewPartnerRepository(db),
Site: sites.NewSiteRepository(db),
Trx: trx.NewGormTransactionManager(db),
Wallet: repository.NewWalletRepository(db),
Midtrans: mdtrns.New(&cfg.Midtrans),
Payment: payment.NewPaymentRepository(db),
EmailService: brevo.New(&cfg.Brevo),
}
}
type Auth interface {
CheckExistsUserAccount(ctx context.Context, email string) (*entity.UserDB, error)
CheckExistsUserAccountByID(ctx context.Context, userID int64) (*entity.UserDB, error)
UpdatePassword(ctx context.Context, trx *gorm.DB, newHashedPassword string, userID int64, resetPassword bool) error
}
type Event interface {
@@ -79,8 +84,10 @@ type Crypto interface {
CompareHashAndPassword(hash string, password string) bool
ValidateWT(tokenString string) (*jwt.Token, error)
GenerateJWT(user *entity.User) (string, error)
GenerateJWTReseetPassword(user *entity.User) (string, error)
GenerateJWTOrder(order *entity.Order) (string, error)
ValidateJWTOrder(tokenString string) (int64, int64, error)
ValidateResetPassword(tokenString string) (int64, error)
ParseAndValidateJWT(token string) (*entity.JWTAuthClaims, error)
}
@@ -171,3 +178,7 @@ type Payment interface {
FindByOrderAndPartnerID(ctx context.Context, orderID, partnerID int64) (*entity.Payment, error)
FindByReferenceID(ctx context.Context, db *gorm.DB, referenceID string) (*entity.Payment, error)
}
type EmailService interface {
SendEmailTransactional(ctx context.Context, param entity.SendEmailNotificationParam) error
}
+127 -1
View File
@@ -2,7 +2,10 @@ package auth
import (
"context"
"furtuna-be/config"
"furtuna-be/internal/common/mycontext"
"furtuna-be/internal/entity"
"furtuna-be/internal/utils"
"go.uber.org/zap"
@@ -14,12 +17,23 @@ import (
type AuthServiceImpl struct {
authRepo repository.Auth
crypto repository.Crypto
user repository.User
emailSvc repository.EmailService
emailCfg config.Email
trxRepo repository.TransactionManager
}
func New(authRepo repository.Auth, crypto repository.Crypto) *AuthServiceImpl {
func New(authRepo repository.Auth,
crypto repository.Crypto, user repository.User, emailSvc repository.EmailService,
emailCfg config.Email, trxRepo repository.TransactionManager,
) *AuthServiceImpl {
return &AuthServiceImpl{
authRepo: authRepo,
crypto: crypto,
user: user,
emailSvc: emailSvc,
emailCfg: emailCfg,
trxRepo: trxRepo,
}
}
@@ -46,3 +60,115 @@ func (u *AuthServiceImpl) AuthenticateUser(ctx context.Context, email, password
return user.ToUserAuthenticate(signedToken), 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
}
// Update the user's password in the database
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 a custom receiver is specified, override the email
if u.emailCfg.CustomReceiver != "" {
email = u.emailCfg.CustomReceiver
}
// Prepare the email notification parameters
renewPasswordRequest := entity.SendEmailNotificationParam{
Recipient: email,
Subject: u.emailCfg.ResetPassword.Subject,
TemplateName: u.emailCfg.ResetPassword.TemplateName,
TemplatePath: u.emailCfg.ResetPassword.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.ErrorInternalServer
}
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
}
+3 -1
View File
@@ -35,7 +35,7 @@ type ServiceManagerImpl struct {
func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl) *ServiceManagerImpl {
return &ServiceManagerImpl{
AuthSvc: auth.New(repo.Auth, repo.Crypto),
AuthSvc: auth.New(repo.Auth, repo.Crypto, repo.User, repo.EmailService, cfg.Email, repo.Trx),
EventSvc: event.NewEventService(repo.Event),
UserSvc: users.NewUserService(repo.User, repo.Branch),
BranchSvc: branch.NewBranchService(repo.Branch),
@@ -52,6 +52,8 @@ func NewServiceManagerImpl(cfg *config.Config, repo *repository.RepoManagerImpl)
type Auth interface {
AuthenticateUser(ctx context.Context, email, password string) (*entity.AuthenticateUser, error)
SendPasswordResetLink(ctx context.Context, email string) error
ResetPassword(ctx mycontext.Context, oldPassword, newPassword string) error
}
type Event interface {