feat(user): Add username support for login and implement username checks in repository
This commit is contained in:
parent
62a188fcc6
commit
98bdfce83a
|
|
@ -53,7 +53,7 @@ func (r *refreshTokenRepository) FindByToken(ctx context.Context, tx *gorm.DB, t
|
||||||
var refreshToken entities.RefreshToken
|
var refreshToken entities.RefreshToken
|
||||||
if err := tx.WithContext(ctx).
|
if err := tx.WithContext(ctx).
|
||||||
Preload("User").
|
Preload("User").
|
||||||
Preload("User.UserRoles.Role").
|
Preload("User.Roles").
|
||||||
Take(&refreshToken).Error; err != nil {
|
Take(&refreshToken).Error; err != nil {
|
||||||
return entities.RefreshToken{}, err
|
return entities.RefreshToken{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,7 @@ type (
|
||||||
}
|
}
|
||||||
|
|
||||||
UserLoginRequest struct {
|
UserLoginRequest struct {
|
||||||
Email string `json:"email" form:"email" binding:"required"`
|
Login string `json:"login" form:"login" binding:"required"`
|
||||||
Password string `json:"password" form:"password" binding:"required"`
|
Password string `json:"password" form:"password" binding:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@ type (
|
||||||
Register(ctx context.Context, tx *gorm.DB, user entities.M_User) (entities.M_User, error)
|
Register(ctx context.Context, tx *gorm.DB, user entities.M_User) (entities.M_User, error)
|
||||||
GetUserById(ctx context.Context, tx *gorm.DB, userId string) (entities.M_User, error)
|
GetUserById(ctx context.Context, tx *gorm.DB, userId string) (entities.M_User, error)
|
||||||
GetUserByEmail(ctx context.Context, tx *gorm.DB, email string) (entities.M_User, error)
|
GetUserByEmail(ctx context.Context, tx *gorm.DB, email string) (entities.M_User, error)
|
||||||
|
GetUserByUsername(ctx context.Context, tx *gorm.DB, username string) (entities.M_User, error)
|
||||||
CheckEmail(ctx context.Context, tx *gorm.DB, email string) (entities.M_User, bool, error)
|
CheckEmail(ctx context.Context, tx *gorm.DB, email string) (entities.M_User, bool, error)
|
||||||
|
CheckUsername(ctx context.Context, tx *gorm.DB, username string) (entities.M_User, bool, error)
|
||||||
Update(ctx context.Context, tx *gorm.DB, user entities.M_User) (entities.M_User, error)
|
Update(ctx context.Context, tx *gorm.DB, user entities.M_User) (entities.M_User, error)
|
||||||
Delete(ctx context.Context, tx *gorm.DB, userId string) error
|
Delete(ctx context.Context, tx *gorm.DB, userId string) error
|
||||||
SwitchRole(ctx context.Context, tx *gorm.DB, userId string, roleId string) (entities.M_User, error)
|
SwitchRole(ctx context.Context, tx *gorm.DB, userId string, roleId string) (entities.M_User, error)
|
||||||
|
|
@ -23,6 +25,37 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// CheckUsername implements UserRepository.
|
||||||
|
func (r *userRepository) CheckUsername(ctx context.Context, tx *gorm.DB, username string) (entities.M_User, bool, error) {
|
||||||
|
if tx == nil {
|
||||||
|
tx = r.db
|
||||||
|
}
|
||||||
|
|
||||||
|
var user entities.M_User
|
||||||
|
if err := tx.WithContext(ctx).Where("username = ?", username).Take(&user).Error; err != nil {
|
||||||
|
return entities.M_User{}, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByUsername implements UserRepository.
|
||||||
|
func (r *userRepository) GetUserByUsername(ctx context.Context, tx *gorm.DB, username string) (entities.M_User, error) {
|
||||||
|
if tx == nil {
|
||||||
|
tx = r.db
|
||||||
|
}
|
||||||
|
|
||||||
|
var user entities.M_User
|
||||||
|
if err := tx.WithContext(ctx).
|
||||||
|
Preload("Roles").
|
||||||
|
Where("username = ?", username).
|
||||||
|
Take(&user).Error; err != nil {
|
||||||
|
return entities.M_User{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewUserRepository(db *gorm.DB) UserRepository {
|
func NewUserRepository(db *gorm.DB) UserRepository {
|
||||||
return &userRepository{
|
return &userRepository{
|
||||||
db: db,
|
db: db,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/Caknoooo/go-gin-clean-starter/database/entities"
|
"github.com/Caknoooo/go-gin-clean-starter/database/entities"
|
||||||
authDto "github.com/Caknoooo/go-gin-clean-starter/modules/auth/dto"
|
authDto "github.com/Caknoooo/go-gin-clean-starter/modules/auth/dto"
|
||||||
|
|
@ -124,9 +125,17 @@ func (s *userService) GetUserById(ctx context.Context, userId string) (dto.UserR
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *userService) Verify(ctx context.Context, req dto.UserLoginRequest) (authDto.TokenResponse, error) {
|
func (s *userService) Verify(ctx context.Context, req dto.UserLoginRequest) (authDto.TokenResponse, error) {
|
||||||
user, err := s.userRepository.GetUserByEmail(ctx, s.db, req.Email)
|
var user entities.M_User
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if strings.Contains(req.Login, "@") {
|
||||||
|
user, err = s.userRepository.GetUserByEmail(ctx, s.db, req.Login)
|
||||||
|
} else {
|
||||||
|
user, err = s.userRepository.GetUserByUsername(ctx, s.db, req.Login)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return authDto.TokenResponse{}, dto.ErrEmailNotFound
|
return authDto.TokenResponse{}, dto.ErrUserNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid := utils.CheckPasswordHash(req.Password, user.Password)
|
isValid := utils.CheckPasswordHash(req.Password, user.Password)
|
||||||
|
|
@ -134,19 +143,18 @@ func (s *userService) Verify(ctx context.Context, req dto.UserLoginRequest) (aut
|
||||||
fmt.Println("Password validation error:", err)
|
fmt.Println("Password validation error:", err)
|
||||||
return authDto.TokenResponse{}, dto.ErrUserNotFound
|
return authDto.TokenResponse{}, dto.ErrUserNotFound
|
||||||
}
|
}
|
||||||
// Ambil roles dari UserRoles
|
|
||||||
roles := append([]entities.M_Role{}, user.Roles...)
|
roles := append([]entities.M_Role{}, user.Roles...)
|
||||||
// var roles []dto.UserRolesResponse
|
|
||||||
// for _, ur := range user.Roles {
|
|
||||||
// roles = append(roles, dto.UserRolesResponse{
|
|
||||||
// ID: ur.ID.String(),
|
|
||||||
// Name: ur.Name,
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
if len(roles) == 0 {
|
if len(roles) == 0 {
|
||||||
return authDto.TokenResponse{}, errors.New("user has no roles assigned")
|
return authDto.TokenResponse{}, errors.New("user has no roles assigned")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteByUserID
|
||||||
|
err = s.refreshTokenRepository.DeleteByUserID(ctx, s.db, user.ID.String())
|
||||||
|
if err != nil {
|
||||||
|
return authDto.TokenResponse{}, err
|
||||||
|
}
|
||||||
|
|
||||||
accessToken := s.jwtService.GenerateAccessToken(user.ClientID.String(), user.ID.String(), roles[0].ID.String())
|
accessToken := s.jwtService.GenerateAccessToken(user.ClientID.String(), user.ID.String(), roles[0].ID.String())
|
||||||
refreshTokenString, expiresAt := s.jwtService.GenerateRefreshToken()
|
refreshTokenString, expiresAt := s.jwtService.GenerateRefreshToken()
|
||||||
|
|
||||||
|
|
@ -292,31 +300,34 @@ func (s *userService) RefreshToken(ctx context.Context, req authDto.RefreshToken
|
||||||
}
|
}
|
||||||
roles := append([]entities.M_Role{}, refreshToken.User.Roles...)
|
roles := append([]entities.M_Role{}, refreshToken.User.Roles...)
|
||||||
if len(roles) == 0 {
|
if len(roles) == 0 {
|
||||||
return authDto.TokenResponse{}, errors.New("user has no roles assigned")
|
return authDto.TokenResponse{}, errors.New("1 user has no roles assigned")
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken := s.jwtService.GenerateAccessToken(refreshToken.ClientID.String(), refreshToken.UserID.String(), roles[0].ID.String())
|
accessToken := s.jwtService.GenerateAccessToken(refreshToken.ClientID.String(), refreshToken.UserID.String(), roles[0].ID.String())
|
||||||
newRefreshTokenString, expiresAt := s.jwtService.GenerateRefreshToken()
|
// newRefreshTokenString, expiresAt := s.jwtService.GenerateRefreshToken()
|
||||||
|
|
||||||
err = s.refreshTokenRepository.DeleteByToken(ctx, s.db, req.RefreshToken)
|
// err = s.refreshTokenRepository.DeleteByToken(ctx, s.db, req.RefreshToken)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return authDto.TokenResponse{}, err
|
// return authDto.TokenResponse{}, err
|
||||||
}
|
// }
|
||||||
|
|
||||||
newRefreshToken := entities.RefreshToken{
|
// newRefreshToken := entities.RefreshToken{
|
||||||
ID: uuid.New(),
|
// ID: uuid.New(),
|
||||||
UserID: refreshToken.UserID,
|
// UserID: refreshToken.UserID,
|
||||||
Token: newRefreshTokenString,
|
// ClientID: refreshToken.ClientID,
|
||||||
ExpiresAt: expiresAt,
|
// Token: newRefreshTokenString,
|
||||||
}
|
// ExpiresAt: expiresAt,
|
||||||
|
// }
|
||||||
|
|
||||||
_, err = s.refreshTokenRepository.Create(ctx, s.db, newRefreshToken)
|
// _, err = s.refreshTokenRepository.Create(ctx, s.db, newRefreshToken)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return authDto.TokenResponse{}, err
|
// return authDto.TokenResponse{}, err
|
||||||
}
|
// }
|
||||||
|
|
||||||
return authDto.TokenResponse{
|
return authDto.TokenResponse{
|
||||||
AccessToken: accessToken,
|
AccessToken: accessToken,
|
||||||
RefreshToken: newRefreshTokenString,
|
// RefreshToken: newRefreshTokenString,
|
||||||
|
RefreshToken: req.RefreshToken, // atau kosongkan jika tidak ingin return refresh token sama sekali
|
||||||
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue