add forget password
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user