MIF_E31222379_BE/internal/services/auth.go

160 lines
3.9 KiB
Go

package services
import (
"errors"
"os"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/pahmiudahgede/senggoldong/domain"
"github.com/pahmiudahgede/senggoldong/internal/repositories"
"golang.org/x/crypto/bcrypt"
)
func RegisterUser(username, name, email, phone, password, confirmPassword, roleId string) error {
if password != confirmPassword {
return errors.New("password dan confirm password tidak cocok")
}
if repositories.IsEmailExist(email, roleId) {
return errors.New("email is already registered with the same role")
}
if repositories.IsUsernameExist(username, roleId) {
return errors.New("username is already registered with the same role")
}
if repositories.IsPhoneExist(phone, roleId) {
return errors.New("phone number is already registered with the same role")
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return errors.New("failed to hash password")
}
err = repositories.CreateUser(username, name, email, phone, string(hashedPassword), roleId)
if err != nil {
return err
}
return nil
}
func LoginUser(identifier, password string) (string, error) {
if identifier == "" || password == "" {
return "", errors.New("email/username/phone and password must be provided")
}
const roleId = ""
user, err := repositories.GetUserByEmailUsernameOrPhone(identifier, roleId)
if err != nil {
return "", errors.New("invalid email/username/phone or password")
}
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
if err != nil {
return "", errors.New("invalid email/username/phone or password")
}
token := generateJWT(user.ID, user.RoleID)
return token, nil
}
func generateJWT(userID, role string) string {
claims := jwt.MapClaims{
"sub": userID,
"role": role,
"exp": time.Now().Add(time.Hour * 24 * 7).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
t, err := token.SignedString([]byte(os.Getenv("API_KEY")))
if err != nil {
return ""
}
return t
}
func GetUserByID(userID string) (domain.User, error) {
user, err := repositories.GetUserByID(userID)
if err != nil {
return user, errors.New("user not found")
}
return user, nil
}
func UpdateUser(userID, email, username, name, phone string) error {
user, err := repositories.GetUserByID(userID)
if err != nil {
return errors.New("user not found")
}
if email != "" && email != user.Email {
if repositories.IsEmailExist(email, user.RoleID) {
return errors.New("email is already registered with the same role")
}
user.Email = email
}
if username != "" && username != user.Username {
if repositories.IsUsernameExist(username, user.RoleID) {
return errors.New("username is already registered with the same role")
}
user.Username = username
}
if phone != "" && phone != user.Phone {
if repositories.IsPhoneExist(phone, user.RoleID) {
return errors.New("phone number is already registered with the same role")
}
user.Phone = phone
}
if name != "" {
user.Name = name
}
err = repositories.UpdateUser(&user)
if err != nil {
return errors.New("failed to update user")
}
return nil
}
func UpdatePassword(userID, oldPassword, newPassword string) error {
user, err := repositories.GetUserByID(userID)
if err != nil {
return errors.New("user not found")
}
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword))
if err != nil {
return errors.New("old password is incorrect")
}
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(newPassword))
if err == nil {
return errors.New("new password cannot be the same as the old password")
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
if err != nil {
return errors.New("failed to hash new password")
}
err = repositories.UpdateUserPassword(userID, string(hashedPassword))
if err != nil {
return errors.New("failed to update password")
}
return nil
}