Skip to content

Commit

Permalink
feature: login social (#98)
Browse files Browse the repository at this point in the history
feature: login social
  • Loading branch information
masnann authored Dec 10, 2023
2 parents c769874 + fe0dd8d commit d5be7f9
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 3 deletions.
3 changes: 3 additions & 0 deletions module/entities/users_models.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import "time"

type UserModels struct {
ID uint64 `gorm:"column:id;type:BIGINT UNSIGNED;primaryKey" json:"id"`
SocialID string `gorm:"column:social_id;type:VARCHAR(255)" json:"social_id"`
Provider string `gorm:"column:provider;type:VARCHAR(255)" json:"provider"`
Email string `gorm:"column:email;type:VARCHAR(255)" json:"email"`
Password string `gorm:"column:password;type:VARCHAR(255)" json:"password"`
Phone string `gorm:"column:phone;type:VARCHAR(255)" json:"phone"`
Expand All @@ -15,6 +17,7 @@ type UserModels struct {
Level string `gorm:"column:level;type:VARCHAR(255)" json:"level"`
Exp uint64 `gorm:"column:exp;type:BIGINT UNSIGNED" json:"exp"`
IsVerified bool `gorm:"column:is_verified;default:false" json:"is_verified"`
LastLogin time.Time `gorm:"column:last_login;type:timestamp;default:CURRENT_TIMESTAMP" json:"last_login"`
PreferredTopics string `gorm:"column:preferred_topics;type:TEXT" json:"preferred_topics"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamp DEFAULT CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp DEFAULT CURRENT_TIMESTAMP" json:"updated_at"`
Expand Down
12 changes: 12 additions & 0 deletions module/feature/auth/dto/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,15 @@ type ResetPasswordRequest struct {
NewPassword string `json:"new_password" validate:"required,min=6,noSpace"`
ConfirmPassword string `json:"confirm_password" validate:"required,min=6,noSpace"`
}

type RegisterSocialRequest struct {
SocialID string `json:"social_id" validate:"required"`
Provider string `json:"provider"`
Email string `json:"email"`
Name string `json:"name"`
PhotoProfile string `json:"photo_profile"`
}

type LoginSocialRequest struct {
SocialID string `json:"social_id" validate:"required"`
}
34 changes: 34 additions & 0 deletions module/feature/auth/dto/response.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package dto

import "github.com/capstone-kelompok-7/backend-disappear/module/entities"

type LoginResponse struct {
Email string `json:"email"`
AccessToken string `json:"access_token"`
Expand All @@ -8,3 +10,35 @@ type LoginResponse struct {
type VerifyOTPResponse struct {
AccessToken string `json:"access_token"`
}

// UserDetailResponse for detail users
type UserDetailResponse struct {
ID uint64 `json:"id"`
Email string `json:"email"`
Role string `json:"role"`
Name string `json:"name"`
Phone string `json:"phone"`
PhotoProfile string `json:"photo_profile"`
TotalGram uint64 `json:"total_gram"`
TotalChallenge uint64 `json:"total_challenge"`
IsVerified bool `json:"is_verified"`
Level string `json:"level"`
Exp uint64 `json:"exp"`
}

func FormatterDetailUser(user *entities.UserModels) *UserDetailResponse {
userFormatter := &UserDetailResponse{
ID: user.ID,
Email: user.Email,
Role: user.Role,
Name: user.Name,
Phone: user.Phone,
PhotoProfile: user.PhotoProfile,
TotalGram: user.TotalGram,
TotalChallenge: user.TotalChallenge,
IsVerified: user.IsVerified,
Level: user.Level,
Exp: user.Exp,
}
return userFormatter
}
51 changes: 51 additions & 0 deletions module/feature/auth/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,54 @@ func (h *AuthHandler) ResetPassword() echo.HandlerFunc {
return response.SendStatusOkResponse(c, "Reset kata sandi berhasil")
}
}

func (h *AuthHandler) RegisterSocial() echo.HandlerFunc {
return func(c echo.Context) error {
var registerRequest *dto2.RegisterSocialRequest
if err := c.Bind(&registerRequest); err != nil {
return response.SendBadRequestResponse(c, "Format input yang Anda masukkan tidak sesuai")
}

if err := utils.ValidateStruct(registerRequest); err != nil {
return response.SendBadRequestResponse(c, "Validasi gagal: "+err.Error())
}

result, err := h.service.RegisterSocial(registerRequest)
if err != nil {
return response.SendStatusInternalServerResponse(c, "Gagal mendaftarkan akun: "+err.Error())
}
return response.SendStatusCreatedResponse(c, "Registrasi berhasil!", dto2.FormatterDetailUser(result))
}
}

func (h *AuthHandler) LoginSocial() echo.HandlerFunc {
return func(c echo.Context) error {
var loginRequest *dto2.LoginSocialRequest
if err := c.Bind(&loginRequest); err != nil {
return response.SendBadRequestResponse(c, "Format input yang Anda masukkan tidak sesuai")
}

if err := utils.ValidateStruct(loginRequest); err != nil {
return response.SendBadRequestResponse(c, "Validasi gagal: "+err.Error())
}

userLogin, accessToken, err := h.service.LoginSocial(loginRequest.SocialID)
if err != nil {
if err.Error() == "user tidak ditemukan" {
return response.SendStatusNotFoundResponse(c, "Pengguna tidak ditemukan")
} else if err.Error() == "akun anda belum diverifikasi" {
return response.SendStatusUnauthorizedResponse(c, "akun anda belum diverifikasi")
}

logrus.Error("Kesalahan : " + err.Error())
return response.SendStatusUnauthorizedResponse(c, "Email atau kata sandi salah")
}

result := &dto2.LoginResponse{
Email: userLogin.Email,
AccessToken: accessToken,
}

return response.SendSuccessResponse(c, "Selamat datang!, Anda telah berhasil masuk.", result)
}
}
9 changes: 9 additions & 0 deletions module/feature/auth/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package auth

import (
"github.com/capstone-kelompok-7/backend-disappear/module/entities"
"github.com/capstone-kelompok-7/backend-disappear/module/feature/auth/dto"
"github.com/labstack/echo/v4"
"time"
)

type RepositoryAuthInterface interface {
Expand All @@ -14,6 +16,9 @@ type RepositoryAuthInterface interface {
DeleteOTP(otp *entities.OTPModels) error
DeleteUserOTP(userId uint64) error
ResetPassword(email, newPasswordHash string) error
LoginSocial(socialID string) (*entities.UserModels, error)
FindUserBySocialID(socialID string) (*entities.UserModels, error)
UpdateLastLogin(userID uint64, lastLogin time.Time) error
}

type ServiceAuthInterface interface {
Expand All @@ -23,6 +28,8 @@ type ServiceAuthInterface interface {
ResendOTP(email string) (*entities.OTPModels, error)
ResetPassword(email, newPassword, confirmPass string) error
VerifyOTP(email, otp string) (string, error)
RegisterSocial(req *dto.RegisterSocialRequest) (*entities.UserModels, error)
LoginSocial(socialID string) (*entities.UserModels, string, error)
}

type HandlerAuthInterface interface {
Expand All @@ -33,4 +40,6 @@ type HandlerAuthInterface interface {
VerifyOTP() echo.HandlerFunc
ForgotPassword() echo.HandlerFunc
ResetPassword() echo.HandlerFunc
RegisterSocial() echo.HandlerFunc
LoginSocial() echo.HandlerFunc
}
30 changes: 30 additions & 0 deletions module/feature/auth/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,33 @@ func (r *AuthRepository) ResetPassword(email, newPasswordHash string) error {
}
return nil
}

func (r *AuthRepository) LoginSocial(socialID string) (*entities.UserModels, error) {
var user entities.UserModels
if err := r.db.Where("social_id = ?", socialID).First(&user).Error; err != nil {
return nil, err
}
return &user, nil
}

func (r *AuthRepository) FindUserBySocialID(socialID string) (*entities.UserModels, error) {
var user entities.UserModels
if err := r.db.Table("users").Where("social_id = ? AND deleted_at IS NULL", socialID).First(&user).Error; err != nil {
return nil, err
}
return &user, nil
}

func (r *AuthRepository) UpdateLastLogin(userID uint64, lastLogin time.Time) error {
var user entities.UserModels
if err := r.db.Where("id = ?", userID).First(&user).Error; err != nil {
return err
}

user.LastLogin = lastLogin
if err := r.db.Save(&user).Error; err != nil {
return err
}

return nil
}
66 changes: 63 additions & 3 deletions module/feature/auth/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"github.com/capstone-kelompok-7/backend-disappear/module/entities"
"github.com/capstone-kelompok-7/backend-disappear/module/feature/auth"
"github.com/capstone-kelompok-7/backend-disappear/module/feature/auth/dto"
"github.com/capstone-kelompok-7/backend-disappear/utils/caching"
"github.com/labstack/gommon/log"
"time"
Expand Down Expand Up @@ -48,9 +49,11 @@ func (s *AuthService) Register(newData *entities.UserModels) (*entities.UserMode
return nil, err
}
value := &entities.UserModels{
Email: newData.Email,
Password: hashPassword,
Role: "customer",
Email: newData.Email,
Password: hashPassword,
Role: "customer",
Level: "bronze",
LastLogin: time.Now(),
}

result, err := s.repo.Register(value)
Expand Down Expand Up @@ -93,6 +96,11 @@ func (s *AuthService) Login(email, password string) (*entities.UserModels, strin
return nil, "", errors.New("password salah")
}

user.LastLogin = time.Now()
if err := s.repo.UpdateLastLogin(user.ID, user.LastLogin); err != nil {
return nil, "", errors.New("gagal memperbarui LastLogin")
}

accessToken, err := s.jwt.GenerateJWT(user.ID, user.Email, user.Role)
if err != nil {
return nil, "", err
Expand Down Expand Up @@ -264,3 +272,55 @@ func (s *AuthService) VerifyOTP(email, otp string) (string, error) {

return accessToken, nil
}

func (s *AuthService) RegisterSocial(req *dto.RegisterSocialRequest) (*entities.UserModels, error) {
existingUser, _ := s.userService.GetUsersByEmail(req.Email)
if existingUser != nil {
return nil, errors.New("email sudah terdaftar")
}

existingUserBySocialID, _ := s.repo.FindUserBySocialID(req.SocialID)
if existingUserBySocialID != nil {
return nil, errors.New("Social ID sudah terdaftar")
}

value := &entities.UserModels{
SocialID: req.SocialID,
Provider: req.Provider,
Email: req.Email,
Name: req.Name,
PhotoProfile: req.PhotoProfile,
Role: "customer",
Level: "bronze",
LastLogin: time.Time{},
}

result, err := s.repo.Register(value)
if err != nil {
return nil, errors.New("gagal mendaftarkan pengguna baru")
}
return result, nil
}

func (s *AuthService) LoginSocial(socialID string) (*entities.UserModels, string, error) {
user, err := s.repo.FindUserBySocialID(socialID)
if err != nil {
return nil, "", errors.New("pengguna tidak ditemukan")
}

if user == nil {
return nil, "", errors.New("pengguna tidak ditemukan")
}

user.LastLogin = time.Now()
if err := s.repo.UpdateLastLogin(user.ID, user.LastLogin); err != nil {
return nil, "", errors.New("gagal memperbarui LastLogin")
}

accessToken, err := s.jwt.GenerateJWT(user.ID, user.Email, user.Role)
if err != nil {
return nil, "", err
}

return user, accessToken, nil
}
2 changes: 2 additions & 0 deletions routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ func RouteAuth(e *echo.Echo, h auth.HandlerAuthInterface, jwtService utils.JWTIn
authGroup.POST("/forgot-password", h.ForgotPassword())
authGroup.POST("/forgot-password/verify", h.VerifyOTP())
authGroup.POST("/forgot-password/reset", h.ResetPassword(), middlewares.AuthMiddleware(jwtService, userService))
authGroup.POST("/register-social", h.RegisterSocial())
authGroup.POST("/login-social", h.LoginSocial())
}

func RouteUser(e *echo.Echo, h users.HandlerUserInterface, jwtService utils.JWTInterface, userService users.ServiceUserInterface) {
Expand Down

0 comments on commit d5be7f9

Please sign in to comment.