Spaces:
Configuration error
Configuration error
Commit ·
8c37caf
1
Parent(s): aabd743
Deploy files from GitHub repository
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- controller/auth/auth_forgot_password_controller.go +1 -1
- models/request_model.go +1 -1
- models/response_model.go +10 -0
- services/forgot_password_service.go +7 -3
- space/controller/auth/auth_external_controller.go +1 -1
- space/controller/auth/auth_forgot_password_controller.go +28 -0
- space/controller/email/email_validate_controller.go +0 -1
- space/models/request_model.go +9 -4
- space/repositories/account_repository.go +2 -4
- space/router/auth_route.go +2 -0
- space/services/authentication_service.go +2 -1
- space/services/email_verification_service.go +5 -1
- space/services/external_authentication_service.go +6 -1
- space/services/forgot_password_service.go +105 -0
- space/services/user_profile_service.go +20 -5
- space/space/space/services/email_verification_service.go +11 -60
- space/space/space/space/space/services/email_verification_service.go +60 -11
- space/space/space/space/space/space/services/user_profile_service.go +3 -1
- space/space/space/space/space/space/space/models/request_model.go +4 -2
- space/space/space/space/space/space/space/services/authentication_service.go +2 -0
- space/space/space/space/space/space/space/services/email_verification_service.go +4 -0
- space/space/space/space/space/space/space/services/user_profile_service.go +5 -2
- space/space/space/space/space/space/space/space/repositories/account_repository.go +9 -0
- space/space/space/space/space/space/space/space/services/external_authentication_service.go +1 -1
- space/space/space/space/space/space/space/space/services/user_profile_service.go +8 -0
- space/space/space/space/space/space/space/space/space/services/user_profile_service.go +8 -2
- space/space/space/space/space/space/space/space/space/space/docker-compose.yml +1 -1
- space/space/space/space/space/space/space/space/space/space/space/space/Dockerfile +3 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/user/user_profile_controller.go +1 -1
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/user/user_update_profile_controller.go +2 -4
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/logs/error_log.txt +1 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/middleware/authentication_middleware.go +0 -3
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/models/response_model.go +5 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/repositories/account_repository.go +0 -4
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/repositories/forgot_password_repository.go +22 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/router/router.go +8 -1
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/external_authentication_service.go +4 -5
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/user_profile_service.go +50 -6
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/.gitignore +4 -2
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/config/config.go +10 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/config/database_connection_config.go +4 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/auth/auth_external_controller.go +20 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/auth/auth_forgot_password_controller.go +1 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/email/email_create_verification_controller.go +21 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/email/email_validate_controller.go +24 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/options/option_category_controller.go +19 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/options/option_value_controller.go +19 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/region/city/city_list_controller.go +21 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/region/city/city_seeds_controller.go +17 -0
- space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/region/province/province_list_controller.go +17 -0
controller/auth/auth_forgot_password_controller.go
CHANGED
|
@@ -24,6 +24,6 @@ func ValidateForgotPassword(c *gin.Context) {
|
|
| 24 |
}
|
| 25 |
ForgotPasswordController.RequestJSON(c, func() {
|
| 26 |
ForgotPasswordController.Service.Constructor.Token = ForgotPasswordController.Request.Token
|
| 27 |
-
ForgotPassword.Validate(ForgotPasswordController.Request.NewPassword)
|
| 28 |
})
|
| 29 |
}
|
|
|
|
| 24 |
}
|
| 25 |
ForgotPasswordController.RequestJSON(c, func() {
|
| 26 |
ForgotPasswordController.Service.Constructor.Token = ForgotPasswordController.Request.Token
|
| 27 |
+
ForgotPassword.Validate(&ForgotPasswordController.Request.NewPassword)
|
| 28 |
})
|
| 29 |
}
|
models/request_model.go
CHANGED
|
@@ -38,5 +38,5 @@ type ForgotPasswordRequest struct {
|
|
| 38 |
}
|
| 39 |
type ValidateForgotPasswordRequest struct {
|
| 40 |
Token uint `json:"token" binding:"required"`
|
| 41 |
-
NewPassword string `json:"new_password"
|
| 42 |
}
|
|
|
|
| 38 |
}
|
| 39 |
type ValidateForgotPasswordRequest struct {
|
| 40 |
Token uint `json:"token" binding:"required"`
|
| 41 |
+
NewPassword string `json:"new_password"`
|
| 42 |
}
|
models/response_model.go
CHANGED
|
@@ -30,3 +30,13 @@ type UserProfileResponse struct {
|
|
| 30 |
Account Account `json:"account"`
|
| 31 |
Details AccountDetails `json:"details"`
|
| 32 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
Account Account `json:"account"`
|
| 31 |
Details AccountDetails `json:"details"`
|
| 32 |
}
|
| 33 |
+
|
| 34 |
+
type AkademiDasar struct {
|
| 35 |
+
Academies Academy `json:"academy"`
|
| 36 |
+
Materials []AcademyMaterial `json:"academy_material"`
|
| 37 |
+
Contents []AcademyContent `json:"academy_content"`
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
type AkademiDasarResponse struct {
|
| 41 |
+
AkademiDasar []AkademiDasar `json:"academy_dasar"`
|
| 42 |
+
}
|
services/forgot_password_service.go
CHANGED
|
@@ -70,7 +70,7 @@ func (s *ForgotPasswordService) Create(email string) {
|
|
| 70 |
// s.Result.Token = 0
|
| 71 |
}
|
| 72 |
|
| 73 |
-
func (s *ForgotPasswordService) Validate(newPassword string) {
|
| 74 |
accountRepo := repositories.GetAccountById(s.Constructor.AccountID)
|
| 75 |
if accountRepo.NoRecord {
|
| 76 |
s.Error = accountRepo.RowsError
|
|
@@ -91,7 +91,11 @@ func (s *ForgotPasswordService) Validate(newPassword string) {
|
|
| 91 |
s.Exception.Message = "Token has expired!"
|
| 92 |
return
|
| 93 |
}
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
accountRepo.Result.Password = hashed_password
|
| 96 |
changePassword := repositories.UpdateAccount(accountRepo.Result)
|
| 97 |
if changePassword.RowsError != nil {
|
|
@@ -101,5 +105,5 @@ func (s *ForgotPasswordService) Validate(newPassword string) {
|
|
| 101 |
return
|
| 102 |
}
|
| 103 |
// fgPasswordRepo.Result.Token = 0
|
| 104 |
-
|
| 105 |
}
|
|
|
|
| 70 |
// s.Result.Token = 0
|
| 71 |
}
|
| 72 |
|
| 73 |
+
func (s *ForgotPasswordService) Validate(newPassword *string) {
|
| 74 |
accountRepo := repositories.GetAccountById(s.Constructor.AccountID)
|
| 75 |
if accountRepo.NoRecord {
|
| 76 |
s.Error = accountRepo.RowsError
|
|
|
|
| 91 |
s.Exception.Message = "Token has expired!"
|
| 92 |
return
|
| 93 |
}
|
| 94 |
+
s.Result = fgPasswordRepo.Result
|
| 95 |
+
if newPassword == nil {
|
| 96 |
+
return
|
| 97 |
+
}
|
| 98 |
+
hashed_password, _ := HashPassword(*newPassword)
|
| 99 |
accountRepo.Result.Password = hashed_password
|
| 100 |
changePassword := repositories.UpdateAccount(accountRepo.Result)
|
| 101 |
if changePassword.RowsError != nil {
|
|
|
|
| 105 |
return
|
| 106 |
}
|
| 107 |
// fgPasswordRepo.Result.Token = 0
|
| 108 |
+
|
| 109 |
}
|
space/controller/auth/auth_external_controller.go
CHANGED
|
@@ -14,7 +14,7 @@ func ExternalAuth(c *gin.Context) {
|
|
| 14 |
GoogleLogin := services.GoogleAuthService{}
|
| 15 |
ExternalAuthController.Service = &GoogleLogin.Service
|
| 16 |
ExternalAuthController.Service.Constructor.OauthID = ExternalAuthController.Request.OauthID
|
| 17 |
-
GoogleLogin.Authenticate()
|
| 18 |
}
|
| 19 |
})
|
| 20 |
}
|
|
|
|
| 14 |
GoogleLogin := services.GoogleAuthService{}
|
| 15 |
ExternalAuthController.Service = &GoogleLogin.Service
|
| 16 |
ExternalAuthController.Service.Constructor.OauthID = ExternalAuthController.Request.OauthID
|
| 17 |
+
GoogleLogin.Authenticate(ExternalAuthController.Request.IsAgreeTerms && !ExternalAuthController.Request.IsSexualDisease)
|
| 18 |
}
|
| 19 |
})
|
| 20 |
}
|
space/controller/auth/auth_forgot_password_controller.go
CHANGED
|
@@ -1 +1,29 @@
|
|
| 1 |
package auth
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
package auth
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"api.qobiltu.id/controller"
|
| 5 |
+
"api.qobiltu.id/models"
|
| 6 |
+
"api.qobiltu.id/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
func CreateForgotPassword(c *gin.Context) {
|
| 11 |
+
ForgotPassword := services.ForgotPasswordService{}
|
| 12 |
+
ForgotPasswordController := controller.Controller[models.ForgotPasswordRequest, models.ForgotPassword, models.ForgotPassword]{
|
| 13 |
+
Service: &ForgotPassword.Service,
|
| 14 |
+
}
|
| 15 |
+
ForgotPasswordController.RequestJSON(c, func() {
|
| 16 |
+
ForgotPassword.Create(ForgotPasswordController.Request.Email)
|
| 17 |
+
})
|
| 18 |
+
|
| 19 |
+
}
|
| 20 |
+
func ValidateForgotPassword(c *gin.Context) {
|
| 21 |
+
ForgotPassword := services.ForgotPasswordService{}
|
| 22 |
+
ForgotPasswordController := controller.Controller[models.ValidateForgotPasswordRequest, models.ForgotPassword, models.ForgotPassword]{
|
| 23 |
+
Service: &ForgotPassword.Service,
|
| 24 |
+
}
|
| 25 |
+
ForgotPasswordController.RequestJSON(c, func() {
|
| 26 |
+
ForgotPasswordController.Service.Constructor.Token = ForgotPasswordController.Request.Token
|
| 27 |
+
ForgotPassword.Validate(&ForgotPasswordController.Request.NewPassword)
|
| 28 |
+
})
|
| 29 |
+
}
|
space/controller/email/email_validate_controller.go
CHANGED
|
@@ -16,7 +16,6 @@ func Verify(c *gin.Context) {
|
|
| 16 |
emailVerificationController.Service.Constructor.AccountID = uint(emailVerificationController.AccountData.UserID)
|
| 17 |
emailVerificationController.RequestJSON(c, func() {
|
| 18 |
emailVerificationController.Service.Constructor.Token = emailVerificationController.Request.Token
|
| 19 |
-
emailVerificationController.Service.Constructor.UUID = emailVerificationController.Request.UUID
|
| 20 |
emailVerification.Validate()
|
| 21 |
})
|
| 22 |
})
|
|
|
|
| 16 |
emailVerificationController.Service.Constructor.AccountID = uint(emailVerificationController.AccountData.UserID)
|
| 17 |
emailVerificationController.RequestJSON(c, func() {
|
| 18 |
emailVerificationController.Service.Constructor.Token = emailVerificationController.Request.Token
|
|
|
|
| 19 |
emailVerification.Validate()
|
| 20 |
})
|
| 21 |
})
|
space/models/request_model.go
CHANGED
|
@@ -1,7 +1,5 @@
|
|
| 1 |
package models
|
| 2 |
|
| 3 |
-
import uuid "github.com/satori/go.uuid"
|
| 4 |
-
|
| 5 |
type LoginRequest struct {
|
| 6 |
Email string `json:"email" binding:"required"`
|
| 7 |
Password string `json:"password" binding:"required"`
|
|
@@ -20,8 +18,7 @@ type ChangePasswordRequest struct {
|
|
| 20 |
}
|
| 21 |
|
| 22 |
type CreateVerifyEmailRequest struct {
|
| 23 |
-
Token uint
|
| 24 |
-
UUID uuid.UUID `json:"uuid" binding:"required"`
|
| 25 |
}
|
| 26 |
|
| 27 |
type OptionsRequest struct {
|
|
@@ -35,3 +32,11 @@ type ExternalAuthRequest struct {
|
|
| 35 |
IsAgreeTerms bool `json:"is_agree_terms"`
|
| 36 |
IsSexualDisease bool `json:"is_sexual_disease"`
|
| 37 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
package models
|
| 2 |
|
|
|
|
|
|
|
| 3 |
type LoginRequest struct {
|
| 4 |
Email string `json:"email" binding:"required"`
|
| 5 |
Password string `json:"password" binding:"required"`
|
|
|
|
| 18 |
}
|
| 19 |
|
| 20 |
type CreateVerifyEmailRequest struct {
|
| 21 |
+
Token uint `json:"token" binding:"required"`
|
|
|
|
| 22 |
}
|
| 23 |
|
| 24 |
type OptionsRequest struct {
|
|
|
|
| 32 |
IsAgreeTerms bool `json:"is_agree_terms"`
|
| 33 |
IsSexualDisease bool `json:"is_sexual_disease"`
|
| 34 |
}
|
| 35 |
+
|
| 36 |
+
type ForgotPasswordRequest struct {
|
| 37 |
+
Email string `json:"email" binding:"required,email"`
|
| 38 |
+
}
|
| 39 |
+
type ValidateForgotPasswordRequest struct {
|
| 40 |
+
Token uint `json:"token" binding:"required"`
|
| 41 |
+
NewPassword string `json:"new_password" binding:"required"`
|
| 42 |
+
}
|
space/repositories/account_repository.go
CHANGED
|
@@ -39,10 +39,8 @@ func UpdateAccount(account models.Account) Repository[models.Account, models.Acc
|
|
| 39 |
repo := Construct[models.Account, models.Account](
|
| 40 |
account,
|
| 41 |
)
|
| 42 |
-
repo.
|
| 43 |
-
|
| 44 |
-
Update[models.Account],
|
| 45 |
-
)
|
| 46 |
return *repo
|
| 47 |
}
|
| 48 |
|
|
|
|
| 39 |
repo := Construct[models.Account, models.Account](
|
| 40 |
account,
|
| 41 |
)
|
| 42 |
+
repo.Transaction.Save(&repo.Constructor)
|
| 43 |
+
repo.Result = repo.Constructor
|
|
|
|
|
|
|
| 44 |
return *repo
|
| 45 |
}
|
| 46 |
|
space/router/auth_route.go
CHANGED
|
@@ -13,5 +13,7 @@ func AuthRoute(router *gin.Engine) {
|
|
| 13 |
routerGroup.POST("/login", AuthController.Login)
|
| 14 |
routerGroup.POST("/register", AuthController.Register)
|
| 15 |
routerGroup.PUT("/change-password", middleware.AuthUser, AuthController.ChangePassword)
|
|
|
|
|
|
|
| 16 |
}
|
| 17 |
}
|
|
|
|
| 13 |
routerGroup.POST("/login", AuthController.Login)
|
| 14 |
routerGroup.POST("/register", AuthController.Register)
|
| 15 |
routerGroup.PUT("/change-password", middleware.AuthUser, AuthController.ChangePassword)
|
| 16 |
+
routerGroup.POST("/forgot-password", AuthController.CreateForgotPassword)
|
| 17 |
+
routerGroup.PUT("/forgot-password", AuthController.ValidateForgotPassword)
|
| 18 |
}
|
| 19 |
}
|
space/services/authentication_service.go
CHANGED
|
@@ -58,7 +58,8 @@ func (s *AuthenticationService) Update(oldPassword string, newPassword string) {
|
|
| 58 |
s.Exception.Message = "incorrect old password!"
|
| 59 |
return
|
| 60 |
}
|
| 61 |
-
|
|
|
|
| 62 |
changePassword := repositories.UpdateAccount(accountData.Result)
|
| 63 |
changePassword.Result.Password = "SECRET"
|
| 64 |
s.Result = models.AuthenticatedUser{
|
|
|
|
| 58 |
s.Exception.Message = "incorrect old password!"
|
| 59 |
return
|
| 60 |
}
|
| 61 |
+
hashed_password, _ := HashPassword(newPassword)
|
| 62 |
+
accountData.Result.Password = hashed_password
|
| 63 |
changePassword := repositories.UpdateAccount(accountData.Result)
|
| 64 |
changePassword.Result.Password = "SECRET"
|
| 65 |
s.Result = models.AuthenticatedUser{
|
space/services/email_verification_service.go
CHANGED
|
@@ -61,6 +61,7 @@ func (s *EmailVerificationService) Create() {
|
|
| 61 |
return
|
| 62 |
}
|
| 63 |
}(accountRepo.Result.Email, token)
|
|
|
|
| 64 |
}
|
| 65 |
|
| 66 |
func (s *EmailVerificationService) Validate() {
|
|
@@ -80,8 +81,11 @@ func (s *EmailVerificationService) Validate() {
|
|
| 80 |
s.Delete()
|
| 81 |
return
|
| 82 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
s.Result = repo.Result
|
| 84 |
-
s.Delete()
|
| 85 |
}
|
| 86 |
|
| 87 |
func (s *EmailVerificationService) Delete() {
|
|
|
|
| 61 |
return
|
| 62 |
}
|
| 63 |
}(accountRepo.Result.Email, token)
|
| 64 |
+
// s.Result.Token = 0
|
| 65 |
}
|
| 66 |
|
| 67 |
func (s *EmailVerificationService) Validate() {
|
|
|
|
| 81 |
s.Delete()
|
| 82 |
return
|
| 83 |
}
|
| 84 |
+
account := repositories.GetAccountById(repo.Result.AccountID)
|
| 85 |
+
account.Result.IsEmailVerified = true
|
| 86 |
+
|
| 87 |
+
repositories.UpdateAccount(account.Result)
|
| 88 |
s.Result = repo.Result
|
|
|
|
| 89 |
}
|
| 90 |
|
| 91 |
func (s *EmailVerificationService) Delete() {
|
space/services/external_authentication_service.go
CHANGED
|
@@ -14,7 +14,7 @@ type GoogleAuthService struct {
|
|
| 14 |
Service[models.ExternalAuth, models.AuthenticatedUser]
|
| 15 |
}
|
| 16 |
|
| 17 |
-
func (s *GoogleAuthService) Authenticate() {
|
| 18 |
GoogleAuth := repositories.GetExternalAccountByOauthId(s.Constructor.OauthID)
|
| 19 |
payload, errGoogleAuth := idtoken.Validate(context.Background(), s.Constructor.OauthID, "")
|
| 20 |
s.Error = errGoogleAuth
|
|
@@ -25,6 +25,11 @@ func (s *GoogleAuthService) Authenticate() {
|
|
| 25 |
}
|
| 26 |
email := payload.Claims["email"]
|
| 27 |
if GoogleAuth.NoRecord {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
s.Constructor.UUID = uuid.NewV4()
|
| 29 |
s.Constructor.OauthProvider = "Google"
|
| 30 |
createAccount := repositories.CreateAccount(models.Account{
|
|
|
|
| 14 |
Service[models.ExternalAuth, models.AuthenticatedUser]
|
| 15 |
}
|
| 16 |
|
| 17 |
+
func (s *GoogleAuthService) Authenticate(isAgree bool) {
|
| 18 |
GoogleAuth := repositories.GetExternalAccountByOauthId(s.Constructor.OauthID)
|
| 19 |
payload, errGoogleAuth := idtoken.Validate(context.Background(), s.Constructor.OauthID, "")
|
| 20 |
s.Error = errGoogleAuth
|
|
|
|
| 25 |
}
|
| 26 |
email := payload.Claims["email"]
|
| 27 |
if GoogleAuth.NoRecord {
|
| 28 |
+
if !isAgree {
|
| 29 |
+
s.Exception.BadRequest = true
|
| 30 |
+
s.Exception.Message = "Please agree to the terms and conditions to create an account"
|
| 31 |
+
return
|
| 32 |
+
}
|
| 33 |
s.Constructor.UUID = uuid.NewV4()
|
| 34 |
s.Constructor.OauthProvider = "Google"
|
| 35 |
createAccount := repositories.CreateAccount(models.Account{
|
space/services/forgot_password_service.go
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package services
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"fmt"
|
| 5 |
+
"log"
|
| 6 |
+
"math/rand/v2"
|
| 7 |
+
"net/smtp"
|
| 8 |
+
"time"
|
| 9 |
+
|
| 10 |
+
"api.qobiltu.id/config"
|
| 11 |
+
"api.qobiltu.id/models"
|
| 12 |
+
"api.qobiltu.id/repositories"
|
| 13 |
+
uuid "github.com/satori/go.uuid"
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
type ForgotPasswordService struct {
|
| 17 |
+
Service[models.ForgotPassword, models.ForgotPassword]
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
func (s *ForgotPasswordService) Create(email string) {
|
| 21 |
+
if email == "" {
|
| 22 |
+
s.Exception.BadRequest = true
|
| 23 |
+
s.Exception.Message = "Email is required!"
|
| 24 |
+
return
|
| 25 |
+
}
|
| 26 |
+
accountRepo := repositories.GetAccountbyEmail(email)
|
| 27 |
+
if accountRepo.NoRecord {
|
| 28 |
+
s.Error = accountRepo.RowsError
|
| 29 |
+
s.Exception.DataNotFound = true
|
| 30 |
+
s.Exception.Message = "There is no account data with given credentials!"
|
| 31 |
+
return
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
remainingTime := time.Duration(config.EMAIL_VERIFICATION_DURATION) * time.Hour
|
| 35 |
+
dueTime := CalculateDueTime(remainingTime)
|
| 36 |
+
|
| 37 |
+
token := uint(rand.IntN(100000))
|
| 38 |
+
s.Constructor.UUID = uuid.NewV4()
|
| 39 |
+
s.Constructor.ExpiredAt = dueTime
|
| 40 |
+
s.Constructor.AccountID = accountRepo.Result.Id
|
| 41 |
+
s.Constructor.Token = token
|
| 42 |
+
repo := repositories.CreateForgotPassword(s.Constructor)
|
| 43 |
+
|
| 44 |
+
s.Error = repo.RowsError
|
| 45 |
+
s.Result = repo.Result
|
| 46 |
+
// ⬇ Kirim token ke email user menggunakan SMTP
|
| 47 |
+
go func(toEmail string, token uint) {
|
| 48 |
+
from := config.SMTP_SENDER_EMAIL
|
| 49 |
+
password := config.SMTP_SENDER_PASSWORD
|
| 50 |
+
smtpHost := config.SMTP_HOST
|
| 51 |
+
smtpPort := config.SMTP_PORT
|
| 52 |
+
|
| 53 |
+
auth := smtp.PlainAuth("", from, password, smtpHost)
|
| 54 |
+
|
| 55 |
+
subject := "Forgot Password Token"
|
| 56 |
+
body := fmt.Sprintf("Your Forgot Password token is: %06d\nPlease use it before it expires.", token)
|
| 57 |
+
|
| 58 |
+
msg := []byte("To: " + toEmail + "\r\n" +
|
| 59 |
+
"Subject: " + subject + "\r\n" +
|
| 60 |
+
"\r\n" +
|
| 61 |
+
body + "\r\n")
|
| 62 |
+
|
| 63 |
+
err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, []string{toEmail}, msg)
|
| 64 |
+
if err != nil {
|
| 65 |
+
s.Error = err
|
| 66 |
+
log.Printf("Error sending verification email: %v", err)
|
| 67 |
+
return
|
| 68 |
+
}
|
| 69 |
+
}(accountRepo.Result.Email, token)
|
| 70 |
+
// s.Result.Token = 0
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
func (s *ForgotPasswordService) Validate(newPassword string) {
|
| 74 |
+
accountRepo := repositories.GetAccountById(s.Constructor.AccountID)
|
| 75 |
+
if accountRepo.NoRecord {
|
| 76 |
+
s.Error = accountRepo.RowsError
|
| 77 |
+
s.Exception.DataNotFound = true
|
| 78 |
+
s.Exception.Message = "There is no account data with given credentials!"
|
| 79 |
+
return
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
fgPasswordRepo := repositories.GetForgotPasswordByToken(s.Constructor.Token)
|
| 83 |
+
s.Error = fgPasswordRepo.RowsError
|
| 84 |
+
if fgPasswordRepo.NoRecord {
|
| 85 |
+
s.Exception.DataNotFound = true
|
| 86 |
+
s.Exception.Message = "There is no forgot password data with given credentials!"
|
| 87 |
+
return
|
| 88 |
+
}
|
| 89 |
+
if fgPasswordRepo.Result.ExpiredAt.Before(time.Now()) {
|
| 90 |
+
s.Exception.Unauthorized = true
|
| 91 |
+
s.Exception.Message = "Token has expired!"
|
| 92 |
+
return
|
| 93 |
+
}
|
| 94 |
+
hashed_password, _ := HashPassword(newPassword)
|
| 95 |
+
accountRepo.Result.Password = hashed_password
|
| 96 |
+
changePassword := repositories.UpdateAccount(accountRepo.Result)
|
| 97 |
+
if changePassword.RowsError != nil {
|
| 98 |
+
s.Error = changePassword.RowsError
|
| 99 |
+
s.Exception.QueryError = true
|
| 100 |
+
s.Exception.Message = "Failed to update password!"
|
| 101 |
+
return
|
| 102 |
+
}
|
| 103 |
+
// fgPasswordRepo.Result.Token = 0
|
| 104 |
+
s.Result = fgPasswordRepo.Result
|
| 105 |
+
}
|
space/services/user_profile_service.go
CHANGED
|
@@ -69,6 +69,7 @@ func (s *UserProfileService) Retrieve() {
|
|
| 69 |
Account: repositories.GetAccountById(s.Constructor.AccountID).Result,
|
| 70 |
Details: userProfile.Result,
|
| 71 |
}
|
|
|
|
| 72 |
}
|
| 73 |
|
| 74 |
func (s *UserProfileService) Update() {
|
|
@@ -78,11 +79,14 @@ func (s *UserProfileService) Update() {
|
|
| 78 |
}
|
| 79 |
usersCount := repositories.GetAllAccount().RowsCount
|
| 80 |
var initialName string
|
| 81 |
-
if
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
|
|
|
|
|
|
| 85 |
}
|
|
|
|
| 86 |
initialName += strconv.Itoa(usersCount)
|
| 87 |
s.Constructor.InitialName = initialName
|
| 88 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
|
@@ -92,8 +96,19 @@ func (s *UserProfileService) Update() {
|
|
| 92 |
s.Exception.Message = "There is no account with given credentials!"
|
| 93 |
return
|
| 94 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
s.Result = models.UserProfileResponse{
|
| 96 |
-
Account:
|
| 97 |
Details: userProfile.Result,
|
| 98 |
}
|
| 99 |
s.Result.Account.Password = "SECRET"
|
|
|
|
| 69 |
Account: repositories.GetAccountById(s.Constructor.AccountID).Result,
|
| 70 |
Details: userProfile.Result,
|
| 71 |
}
|
| 72 |
+
s.Result.Account.Password = "SECRET"
|
| 73 |
}
|
| 74 |
|
| 75 |
func (s *UserProfileService) Update() {
|
|
|
|
| 79 |
}
|
| 80 |
usersCount := repositories.GetAllAccount().RowsCount
|
| 81 |
var initialName string
|
| 82 |
+
if s.Constructor.Gender != nil {
|
| 83 |
+
if *s.Constructor.Gender {
|
| 84 |
+
initialName = "IKH_"
|
| 85 |
+
} else {
|
| 86 |
+
initialName = "AKH_"
|
| 87 |
+
}
|
| 88 |
}
|
| 89 |
+
|
| 90 |
initialName += strconv.Itoa(usersCount)
|
| 91 |
s.Constructor.InitialName = initialName
|
| 92 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
|
|
|
| 96 |
s.Exception.Message = "There is no account with given credentials!"
|
| 97 |
return
|
| 98 |
}
|
| 99 |
+
account := repositories.GetAccountById(s.Constructor.AccountID)
|
| 100 |
+
account.Result.IsDetailCompleted = (userProfile.Result.InitialName != "" &&
|
| 101 |
+
userProfile.Result.FullName != nil &&
|
| 102 |
+
userProfile.Result.DateOfBirth != nil &&
|
| 103 |
+
userProfile.Result.PlaceOfBirth != nil &&
|
| 104 |
+
userProfile.Result.Domicile != nil &&
|
| 105 |
+
userProfile.Result.LastJob != nil &&
|
| 106 |
+
userProfile.Result.Gender != nil &&
|
| 107 |
+
userProfile.Result.LastEducation != nil &&
|
| 108 |
+
userProfile.Result.MaritalStatus != nil)
|
| 109 |
+
repositories.UpdateAccount(account.Result)
|
| 110 |
s.Result = models.UserProfileResponse{
|
| 111 |
+
Account: account.Result,
|
| 112 |
Details: userProfile.Result,
|
| 113 |
}
|
| 114 |
s.Result.Account.Password = "SECRET"
|
space/space/space/services/email_verification_service.go
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
package services
|
| 2 |
|
| 3 |
import (
|
| 4 |
-
"crypto/tls"
|
| 5 |
"fmt"
|
|
|
|
| 6 |
"math/rand/v2"
|
| 7 |
"net/smtp"
|
| 8 |
"time"
|
|
@@ -44,71 +44,22 @@ func (s *EmailVerificationService) Create() {
|
|
| 44 |
smtpHost := config.SMTP_HOST
|
| 45 |
smtpPort := config.SMTP_PORT
|
| 46 |
|
| 47 |
-
tlsconfig := &tls.Config{
|
| 48 |
-
InsecureSkipVerify: true,
|
| 49 |
-
ServerName: smtpHost,
|
| 50 |
-
}
|
| 51 |
-
|
| 52 |
-
conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", smtpHost, smtpPort), tlsconfig)
|
| 53 |
-
if err != nil {
|
| 54 |
-
panic(err)
|
| 55 |
-
}
|
| 56 |
-
|
| 57 |
-
client, err := smtp.NewClient(conn, smtpHost)
|
| 58 |
-
if err != nil {
|
| 59 |
-
panic(err)
|
| 60 |
-
}
|
| 61 |
-
|
| 62 |
-
// auth := smtp.PlainAuth("", from, password, smtpHost)
|
| 63 |
auth := smtp.PlainAuth("", from, password, smtpHost)
|
| 64 |
-
if err = client.Auth(auth); err != nil {
|
| 65 |
-
panic(err)
|
| 66 |
-
}
|
| 67 |
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
}
|
| 71 |
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
}
|
| 77 |
-
}
|
| 78 |
|
| 79 |
-
|
| 80 |
if err != nil {
|
| 81 |
-
|
|
|
|
|
|
|
| 82 |
}
|
| 83 |
-
|
| 84 |
-
msg := []byte("Subject: Test Email\r\n\r\nThis is the email body.")
|
| 85 |
-
_, err = wc.Write(msg)
|
| 86 |
-
if err != nil {
|
| 87 |
-
panic(err)
|
| 88 |
-
}
|
| 89 |
-
|
| 90 |
-
err = wc.Close()
|
| 91 |
-
if err != nil {
|
| 92 |
-
panic(err)
|
| 93 |
-
}
|
| 94 |
-
|
| 95 |
-
client.Quit()
|
| 96 |
-
fmt.Println("Email sent successfully!")
|
| 97 |
-
|
| 98 |
-
// subject := "Email Verification Token"
|
| 99 |
-
// body := fmt.Sprintf("Your verification token is: %06d\nPlease use it before it expires.", token)
|
| 100 |
-
|
| 101 |
-
// msg := []byte("To: " + toEmail + "\r\n" +
|
| 102 |
-
// "Subject: " + subject + "\r\n" +
|
| 103 |
-
// "\r\n" +
|
| 104 |
-
// body + "\r\n")
|
| 105 |
-
|
| 106 |
-
// err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, []string{toEmail}, msg)
|
| 107 |
-
// if err != nil {
|
| 108 |
-
// s.Error = err
|
| 109 |
-
// log.Printf("Error sending verification email: %v", err)
|
| 110 |
-
// return
|
| 111 |
-
// }
|
| 112 |
}(accountRepo.Result.Email, token)
|
| 113 |
}
|
| 114 |
|
|
|
|
| 1 |
package services
|
| 2 |
|
| 3 |
import (
|
|
|
|
| 4 |
"fmt"
|
| 5 |
+
"log"
|
| 6 |
"math/rand/v2"
|
| 7 |
"net/smtp"
|
| 8 |
"time"
|
|
|
|
| 44 |
smtpHost := config.SMTP_HOST
|
| 45 |
smtpPort := config.SMTP_PORT
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
auth := smtp.PlainAuth("", from, password, smtpHost)
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
+
subject := "Email Verification Token"
|
| 50 |
+
body := fmt.Sprintf("Your verification token is: %06d\nPlease use it before it expires.", token)
|
|
|
|
| 51 |
|
| 52 |
+
msg := []byte("To: " + toEmail + "\r\n" +
|
| 53 |
+
"Subject: " + subject + "\r\n" +
|
| 54 |
+
"\r\n" +
|
| 55 |
+
body + "\r\n")
|
|
|
|
|
|
|
| 56 |
|
| 57 |
+
err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, []string{toEmail}, msg)
|
| 58 |
if err != nil {
|
| 59 |
+
s.Error = err
|
| 60 |
+
log.Printf("Error sending verification email: %v", err)
|
| 61 |
+
return
|
| 62 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
}(accountRepo.Result.Email, token)
|
| 64 |
}
|
| 65 |
|
space/space/space/space/space/services/email_verification_service.go
CHANGED
|
@@ -1,8 +1,8 @@
|
|
| 1 |
package services
|
| 2 |
|
| 3 |
import (
|
|
|
|
| 4 |
"fmt"
|
| 5 |
-
"log"
|
| 6 |
"math/rand/v2"
|
| 7 |
"net/smtp"
|
| 8 |
"time"
|
|
@@ -44,22 +44,71 @@ func (s *EmailVerificationService) Create() {
|
|
| 44 |
smtpHost := config.SMTP_HOST
|
| 45 |
smtpPort := config.SMTP_PORT
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
auth := smtp.PlainAuth("", from, password, smtpHost)
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
-
|
| 50 |
-
|
|
|
|
| 51 |
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
| 56 |
|
| 57 |
-
err :=
|
| 58 |
if err != nil {
|
| 59 |
-
|
| 60 |
-
log.Printf("Error sending verification email: %v", err)
|
| 61 |
-
return
|
| 62 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
}(accountRepo.Result.Email, token)
|
| 64 |
}
|
| 65 |
|
|
|
|
| 1 |
package services
|
| 2 |
|
| 3 |
import (
|
| 4 |
+
"crypto/tls"
|
| 5 |
"fmt"
|
|
|
|
| 6 |
"math/rand/v2"
|
| 7 |
"net/smtp"
|
| 8 |
"time"
|
|
|
|
| 44 |
smtpHost := config.SMTP_HOST
|
| 45 |
smtpPort := config.SMTP_PORT
|
| 46 |
|
| 47 |
+
tlsconfig := &tls.Config{
|
| 48 |
+
InsecureSkipVerify: true,
|
| 49 |
+
ServerName: smtpHost,
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", smtpHost, smtpPort), tlsconfig)
|
| 53 |
+
if err != nil {
|
| 54 |
+
panic(err)
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
client, err := smtp.NewClient(conn, smtpHost)
|
| 58 |
+
if err != nil {
|
| 59 |
+
panic(err)
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
// auth := smtp.PlainAuth("", from, password, smtpHost)
|
| 63 |
auth := smtp.PlainAuth("", from, password, smtpHost)
|
| 64 |
+
if err = client.Auth(auth); err != nil {
|
| 65 |
+
panic(err)
|
| 66 |
+
}
|
| 67 |
|
| 68 |
+
if err = client.Mail(from); err != nil {
|
| 69 |
+
panic(err)
|
| 70 |
+
}
|
| 71 |
|
| 72 |
+
to := []string{toEmail}
|
| 73 |
+
for _, addr := range to {
|
| 74 |
+
if err = client.Rcpt(addr); err != nil {
|
| 75 |
+
panic(err)
|
| 76 |
+
}
|
| 77 |
+
}
|
| 78 |
|
| 79 |
+
wc, err := client.Data()
|
| 80 |
if err != nil {
|
| 81 |
+
panic(err)
|
|
|
|
|
|
|
| 82 |
}
|
| 83 |
+
|
| 84 |
+
msg := []byte("Subject: Test Email\r\n\r\nThis is the email body.")
|
| 85 |
+
_, err = wc.Write(msg)
|
| 86 |
+
if err != nil {
|
| 87 |
+
panic(err)
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
err = wc.Close()
|
| 91 |
+
if err != nil {
|
| 92 |
+
panic(err)
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
client.Quit()
|
| 96 |
+
fmt.Println("Email sent successfully!")
|
| 97 |
+
|
| 98 |
+
// subject := "Email Verification Token"
|
| 99 |
+
// body := fmt.Sprintf("Your verification token is: %06d\nPlease use it before it expires.", token)
|
| 100 |
+
|
| 101 |
+
// msg := []byte("To: " + toEmail + "\r\n" +
|
| 102 |
+
// "Subject: " + subject + "\r\n" +
|
| 103 |
+
// "\r\n" +
|
| 104 |
+
// body + "\r\n")
|
| 105 |
+
|
| 106 |
+
// err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, []string{toEmail}, msg)
|
| 107 |
+
// if err != nil {
|
| 108 |
+
// s.Error = err
|
| 109 |
+
// log.Printf("Error sending verification email: %v", err)
|
| 110 |
+
// return
|
| 111 |
+
// }
|
| 112 |
}(accountRepo.Result.Email, token)
|
| 113 |
}
|
| 114 |
|
space/space/space/space/space/space/services/user_profile_service.go
CHANGED
|
@@ -2,6 +2,7 @@ package services
|
|
| 2 |
|
| 3 |
import (
|
| 4 |
"regexp"
|
|
|
|
| 5 |
"strings"
|
| 6 |
|
| 7 |
"api.qobiltu.id/models"
|
|
@@ -82,7 +83,8 @@ func (s *UserProfileService) Update() {
|
|
| 82 |
} else {
|
| 83 |
initialName = "AKH_"
|
| 84 |
}
|
| 85 |
-
initialName +=
|
|
|
|
| 86 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
| 87 |
s.Error = userProfile.RowsError
|
| 88 |
if userProfile.NoRecord {
|
|
|
|
| 2 |
|
| 3 |
import (
|
| 4 |
"regexp"
|
| 5 |
+
"strconv"
|
| 6 |
"strings"
|
| 7 |
|
| 8 |
"api.qobiltu.id/models"
|
|
|
|
| 83 |
} else {
|
| 84 |
initialName = "AKH_"
|
| 85 |
}
|
| 86 |
+
initialName += strconv.Itoa(usersCount)
|
| 87 |
+
s.Constructor.InitialName = initialName
|
| 88 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
| 89 |
s.Error = userProfile.RowsError
|
| 90 |
if userProfile.NoRecord {
|
space/space/space/space/space/space/space/models/request_model.go
CHANGED
|
@@ -30,6 +30,8 @@ type OptionsRequest struct {
|
|
| 30 |
}
|
| 31 |
|
| 32 |
type ExternalAuthRequest struct {
|
| 33 |
-
OauthID
|
| 34 |
-
OauthProvider
|
|
|
|
|
|
|
| 35 |
}
|
|
|
|
| 30 |
}
|
| 31 |
|
| 32 |
type ExternalAuthRequest struct {
|
| 33 |
+
OauthID string `json:"oauth_id" binding:"required"`
|
| 34 |
+
OauthProvider string `json:"oauth_provider" binding:"required"`
|
| 35 |
+
IsAgreeTerms bool `json:"is_agree_terms"`
|
| 36 |
+
IsSexualDisease bool `json:"is_sexual_disease"`
|
| 37 |
}
|
space/space/space/space/space/space/space/services/authentication_service.go
CHANGED
|
@@ -18,6 +18,7 @@ func (s *AuthenticationService) Authenticate() {
|
|
| 18 |
s.Exception.Message = "there is no account with given credentials!"
|
| 19 |
return
|
| 20 |
}
|
|
|
|
| 21 |
if VerifyPassword(accountData.Result.Password, s.Constructor.Password) != nil {
|
| 22 |
s.Exception.Unauthorized = true
|
| 23 |
s.Exception.Message = "incorrect password!"
|
|
@@ -28,6 +29,7 @@ func (s *AuthenticationService) Authenticate() {
|
|
| 28 |
|
| 29 |
if err_tok != nil {
|
| 30 |
s.Error = errors.Join(s.Error, err_tok)
|
|
|
|
| 31 |
}
|
| 32 |
|
| 33 |
accountData.Result.Password = "SECRET"
|
|
|
|
| 18 |
s.Exception.Message = "there is no account with given credentials!"
|
| 19 |
return
|
| 20 |
}
|
| 21 |
+
|
| 22 |
if VerifyPassword(accountData.Result.Password, s.Constructor.Password) != nil {
|
| 23 |
s.Exception.Unauthorized = true
|
| 24 |
s.Exception.Message = "incorrect password!"
|
|
|
|
| 29 |
|
| 30 |
if err_tok != nil {
|
| 31 |
s.Error = errors.Join(s.Error, err_tok)
|
| 32 |
+
return
|
| 33 |
}
|
| 34 |
|
| 35 |
accountData.Result.Password = "SECRET"
|
space/space/space/space/space/space/space/services/email_verification_service.go
CHANGED
|
@@ -56,7 +56,9 @@ func (s *EmailVerificationService) Create() {
|
|
| 56 |
|
| 57 |
err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, []string{toEmail}, msg)
|
| 58 |
if err != nil {
|
|
|
|
| 59 |
log.Printf("Error sending verification email: %v", err)
|
|
|
|
| 60 |
}
|
| 61 |
}(accountRepo.Result.Email, token)
|
| 62 |
}
|
|
@@ -75,9 +77,11 @@ func (s *EmailVerificationService) Validate() {
|
|
| 75 |
s.Exception.Unauthorized = true
|
| 76 |
s.Exception.Message = "Token has expired!"
|
| 77 |
repositories.UpdateExpiredEmailVerification(s.Constructor.UUID)
|
|
|
|
| 78 |
return
|
| 79 |
}
|
| 80 |
s.Result = repo.Result
|
|
|
|
| 81 |
}
|
| 82 |
|
| 83 |
func (s *EmailVerificationService) Delete() {
|
|
|
|
| 56 |
|
| 57 |
err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, []string{toEmail}, msg)
|
| 58 |
if err != nil {
|
| 59 |
+
s.Error = err
|
| 60 |
log.Printf("Error sending verification email: %v", err)
|
| 61 |
+
return
|
| 62 |
}
|
| 63 |
}(accountRepo.Result.Email, token)
|
| 64 |
}
|
|
|
|
| 77 |
s.Exception.Unauthorized = true
|
| 78 |
s.Exception.Message = "Token has expired!"
|
| 79 |
repositories.UpdateExpiredEmailVerification(s.Constructor.UUID)
|
| 80 |
+
s.Delete()
|
| 81 |
return
|
| 82 |
}
|
| 83 |
s.Result = repo.Result
|
| 84 |
+
s.Delete()
|
| 85 |
}
|
| 86 |
|
| 87 |
func (s *EmailVerificationService) Delete() {
|
space/space/space/space/space/space/space/services/user_profile_service.go
CHANGED
|
@@ -71,8 +71,10 @@ func (s *UserProfileService) Retrieve() {
|
|
| 71 |
}
|
| 72 |
|
| 73 |
func (s *UserProfileService) Update() {
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
| 76 |
usersCount := repositories.GetAllAccount().RowsCount
|
| 77 |
var initialName string
|
| 78 |
if *s.Constructor.Gender {
|
|
@@ -92,4 +94,5 @@ func (s *UserProfileService) Update() {
|
|
| 92 |
Account: repositories.GetAccountById(s.Constructor.AccountID).Result,
|
| 93 |
Details: userProfile.Result,
|
| 94 |
}
|
|
|
|
| 95 |
}
|
|
|
|
| 71 |
}
|
| 72 |
|
| 73 |
func (s *UserProfileService) Update() {
|
| 74 |
+
if s.Constructor.PhoneNumber != nil {
|
| 75 |
+
phoneNumber := *s.Constructor.PhoneNumber
|
| 76 |
+
*s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
|
| 77 |
+
}
|
| 78 |
usersCount := repositories.GetAllAccount().RowsCount
|
| 79 |
var initialName string
|
| 80 |
if *s.Constructor.Gender {
|
|
|
|
| 94 |
Account: repositories.GetAccountById(s.Constructor.AccountID).Result,
|
| 95 |
Details: userProfile.Result,
|
| 96 |
}
|
| 97 |
+
s.Result.Account.Password = "SECRET"
|
| 98 |
}
|
space/space/space/space/space/space/space/space/repositories/account_repository.go
CHANGED
|
@@ -15,6 +15,15 @@ func GetAccountbyEmail(email string) Repository[models.Account, models.Account]
|
|
| 15 |
return *repo
|
| 16 |
}
|
| 17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
func GetAccountById(accountId uint) Repository[models.Account, models.Account] {
|
| 19 |
repo := Construct[models.Account, models.Account](
|
| 20 |
models.Account{Id: accountId},
|
|
|
|
| 15 |
return *repo
|
| 16 |
}
|
| 17 |
|
| 18 |
+
func GetAllAccount() Repository[models.Account, []models.Account] {
|
| 19 |
+
repo := Construct[models.Account, []models.Account](
|
| 20 |
+
models.Account{},
|
| 21 |
+
)
|
| 22 |
+
repo.Transactions(
|
| 23 |
+
Find[models.Account, []models.Account],
|
| 24 |
+
)
|
| 25 |
+
return *repo
|
| 26 |
+
}
|
| 27 |
func GetAccountById(accountId uint) Repository[models.Account, models.Account] {
|
| 28 |
repo := Construct[models.Account, models.Account](
|
| 29 |
models.Account{Id: accountId},
|
space/space/space/space/space/space/space/space/services/external_authentication_service.go
CHANGED
|
@@ -33,7 +33,7 @@ func (s *GoogleAuthService) Authenticate() {
|
|
| 33 |
})
|
| 34 |
s.Constructor.AccountID = createAccount.Result.Id
|
| 35 |
createGoogleAuth := repositories.CreateExternalAuth(s.Constructor)
|
| 36 |
-
|
| 37 |
s.Error = createGoogleAuth.RowsError
|
| 38 |
s.Error = errors.Join(s.Error, createAccount.RowsError)
|
| 39 |
}
|
|
|
|
| 33 |
})
|
| 34 |
s.Constructor.AccountID = createAccount.Result.Id
|
| 35 |
createGoogleAuth := repositories.CreateExternalAuth(s.Constructor)
|
| 36 |
+
GoogleAuth.Result.AccountID = createGoogleAuth.Result.ID
|
| 37 |
s.Error = createGoogleAuth.RowsError
|
| 38 |
s.Error = errors.Join(s.Error, createAccount.RowsError)
|
| 39 |
}
|
space/space/space/space/space/space/space/space/services/user_profile_service.go
CHANGED
|
@@ -73,6 +73,14 @@ func (s *UserProfileService) Retrieve() {
|
|
| 73 |
func (s *UserProfileService) Update() {
|
| 74 |
phoneNumber := *s.Constructor.PhoneNumber
|
| 75 |
*s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
| 77 |
s.Error = userProfile.RowsError
|
| 78 |
if userProfile.NoRecord {
|
|
|
|
| 73 |
func (s *UserProfileService) Update() {
|
| 74 |
phoneNumber := *s.Constructor.PhoneNumber
|
| 75 |
*s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
|
| 76 |
+
usersCount := repositories.GetAllAccount().RowsCount
|
| 77 |
+
var initialName string
|
| 78 |
+
if *s.Constructor.Gender {
|
| 79 |
+
initialName = "IKH_"
|
| 80 |
+
} else {
|
| 81 |
+
initialName = "AKH_"
|
| 82 |
+
}
|
| 83 |
+
initialName += string(usersCount)
|
| 84 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
| 85 |
s.Error = userProfile.RowsError
|
| 86 |
if userProfile.NoRecord {
|
space/space/space/space/space/space/space/space/space/services/user_profile_service.go
CHANGED
|
@@ -44,8 +44,6 @@ func SanitizePhoneNumber(input string) string {
|
|
| 44 |
return input
|
| 45 |
}
|
| 46 |
func (s *UserProfileService) Create() {
|
| 47 |
-
phoneNumber := *s.Constructor.PhoneNumber
|
| 48 |
-
*s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
|
| 49 |
userProfile := repositories.CreateAccountDetails(s.Constructor)
|
| 50 |
s.Error = userProfile.RowsError
|
| 51 |
if userProfile.NoRecord {
|
|
@@ -75,6 +73,14 @@ func (s *UserProfileService) Retrieve() {
|
|
| 75 |
func (s *UserProfileService) Update() {
|
| 76 |
phoneNumber := *s.Constructor.PhoneNumber
|
| 77 |
*s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
| 79 |
s.Error = userProfile.RowsError
|
| 80 |
if userProfile.NoRecord {
|
|
|
|
| 44 |
return input
|
| 45 |
}
|
| 46 |
func (s *UserProfileService) Create() {
|
|
|
|
|
|
|
| 47 |
userProfile := repositories.CreateAccountDetails(s.Constructor)
|
| 48 |
s.Error = userProfile.RowsError
|
| 49 |
if userProfile.NoRecord {
|
|
|
|
| 73 |
func (s *UserProfileService) Update() {
|
| 74 |
phoneNumber := *s.Constructor.PhoneNumber
|
| 75 |
*s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
|
| 76 |
+
usersCount := repositories.GetAllAccount().RowsCount
|
| 77 |
+
var initialName string
|
| 78 |
+
if *s.Constructor.Gender {
|
| 79 |
+
initialName = "IKH_"
|
| 80 |
+
} else {
|
| 81 |
+
initialName = "AKH_"
|
| 82 |
+
}
|
| 83 |
+
initialName += string(usersCount)
|
| 84 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
| 85 |
s.Error = userProfile.RowsError
|
| 86 |
if userProfile.NoRecord {
|
space/space/space/space/space/space/space/space/space/space/docker-compose.yml
CHANGED
|
@@ -24,7 +24,7 @@ services:
|
|
| 24 |
ports:
|
| 25 |
- "5432:5432"
|
| 26 |
volumes:
|
| 27 |
-
-
|
| 28 |
restart: always
|
| 29 |
|
| 30 |
volumes:
|
|
|
|
| 24 |
ports:
|
| 25 |
- "5432:5432"
|
| 26 |
volumes:
|
| 27 |
+
- /home/qobiltu/postgres-data:/var/lib/postgresql/data
|
| 28 |
restart: always
|
| 29 |
|
| 30 |
volumes:
|
space/space/space/space/space/space/space/space/space/space/space/space/Dockerfile
CHANGED
|
@@ -28,6 +28,9 @@ WORKDIR /app
|
|
| 28 |
# Copy hasil build dari builder ke image runtime
|
| 29 |
COPY --from=builder /app/main .
|
| 30 |
|
|
|
|
|
|
|
|
|
|
| 31 |
# Copy file .env untuk konfigurasi environment
|
| 32 |
COPY .env .env
|
| 33 |
|
|
|
|
| 28 |
# Copy hasil build dari builder ke image runtime
|
| 29 |
COPY --from=builder /app/main .
|
| 30 |
|
| 31 |
+
# Copy folder utils (termasuk file seeder) dari builder ke runtime
|
| 32 |
+
COPY --from=builder /app/utils ./utils
|
| 33 |
+
|
| 34 |
# Copy file .env untuk konfigurasi environment
|
| 35 |
COPY .env .env
|
| 36 |
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/user/user_profile_controller.go
CHANGED
|
@@ -9,7 +9,7 @@ import (
|
|
| 9 |
|
| 10 |
func Profile(c *gin.Context) {
|
| 11 |
userProfile := services.UserProfileService{}
|
| 12 |
-
userProfileController := controller.Controller[any, models.AccountDetails, models.
|
| 13 |
Service: &userProfile.Service,
|
| 14 |
}
|
| 15 |
userProfileController.HeaderParse(c, func() {
|
|
|
|
| 9 |
|
| 10 |
func Profile(c *gin.Context) {
|
| 11 |
userProfile := services.UserProfileService{}
|
| 12 |
+
userProfileController := controller.Controller[any, models.AccountDetails, models.UserProfileResponse]{
|
| 13 |
Service: &userProfile.Service,
|
| 14 |
}
|
| 15 |
userProfileController.HeaderParse(c, func() {
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/user/user_update_profile_controller.go
CHANGED
|
@@ -1,8 +1,6 @@
|
|
| 1 |
package user
|
| 2 |
|
| 3 |
import (
|
| 4 |
-
"fmt"
|
| 5 |
-
|
| 6 |
"api.qobiltu.id/controller"
|
| 7 |
"api.qobiltu.id/models"
|
| 8 |
"api.qobiltu.id/services"
|
|
@@ -11,7 +9,7 @@ import (
|
|
| 11 |
|
| 12 |
func UpdateProfile(c *gin.Context) {
|
| 13 |
userProfile := services.UserProfileService{}
|
| 14 |
-
userUpdateProfileController := controller.Controller[models.AccountDetails, models.AccountDetails, models.
|
| 15 |
Service: &userProfile.Service,
|
| 16 |
}
|
| 17 |
|
|
@@ -19,7 +17,7 @@ func UpdateProfile(c *gin.Context) {
|
|
| 19 |
userUpdateProfileController.Service.Constructor = userUpdateProfileController.Request
|
| 20 |
userUpdateProfileController.HeaderParse(c, func() {
|
| 21 |
userUpdateProfileController.Service.Constructor.AccountID = uint(userUpdateProfileController.AccountData.UserID)
|
| 22 |
-
|
| 23 |
})
|
| 24 |
userProfile.Update()
|
| 25 |
},
|
|
|
|
| 1 |
package user
|
| 2 |
|
| 3 |
import (
|
|
|
|
|
|
|
| 4 |
"api.qobiltu.id/controller"
|
| 5 |
"api.qobiltu.id/models"
|
| 6 |
"api.qobiltu.id/services"
|
|
|
|
| 9 |
|
| 10 |
func UpdateProfile(c *gin.Context) {
|
| 11 |
userProfile := services.UserProfileService{}
|
| 12 |
+
userUpdateProfileController := controller.Controller[models.AccountDetails, models.AccountDetails, models.UserProfileResponse]{
|
| 13 |
Service: &userProfile.Service,
|
| 14 |
}
|
| 15 |
|
|
|
|
| 17 |
userUpdateProfileController.Service.Constructor = userUpdateProfileController.Request
|
| 18 |
userUpdateProfileController.HeaderParse(c, func() {
|
| 19 |
userUpdateProfileController.Service.Constructor.AccountID = uint(userUpdateProfileController.AccountData.UserID)
|
| 20 |
+
|
| 21 |
})
|
| 22 |
userProfile.Update()
|
| 23 |
},
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/logs/error_log.txt
CHANGED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/middleware/authentication_middleware.go
CHANGED
|
@@ -3,8 +3,6 @@
|
|
| 3 |
package middleware
|
| 4 |
|
| 5 |
import (
|
| 6 |
-
"fmt"
|
| 7 |
-
|
| 8 |
"api.qobiltu.id/models"
|
| 9 |
"api.qobiltu.id/services"
|
| 10 |
"api.qobiltu.id/utils"
|
|
@@ -17,7 +15,6 @@ func AuthUser(c *gin.Context) {
|
|
| 17 |
token := c.Request.Header["Authorization"]
|
| 18 |
|
| 19 |
currAccData.UserID, currAccData.VerifyStatus, currAccData.ErrVerif = services.VerifyToken(token[0])
|
| 20 |
-
fmt.Println(token[0])
|
| 21 |
|
| 22 |
if currAccData.VerifyStatus == "invalid-token" || currAccData.VerifyStatus == "expired" {
|
| 23 |
currAccData.UserID = 0
|
|
|
|
| 3 |
package middleware
|
| 4 |
|
| 5 |
import (
|
|
|
|
|
|
|
| 6 |
"api.qobiltu.id/models"
|
| 7 |
"api.qobiltu.id/services"
|
| 8 |
"api.qobiltu.id/utils"
|
|
|
|
| 15 |
token := c.Request.Header["Authorization"]
|
| 16 |
|
| 17 |
currAccData.UserID, currAccData.VerifyStatus, currAccData.ErrVerif = services.VerifyToken(token[0])
|
|
|
|
| 18 |
|
| 19 |
if currAccData.VerifyStatus == "invalid-token" || currAccData.VerifyStatus == "expired" {
|
| 20 |
currAccData.UserID = 0
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/models/response_model.go
CHANGED
|
@@ -25,3 +25,8 @@ type Options struct {
|
|
| 25 |
type OptionsResponse struct {
|
| 26 |
Options []Options `json:"options"`
|
| 27 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
type OptionsResponse struct {
|
| 26 |
Options []Options `json:"options"`
|
| 27 |
}
|
| 28 |
+
|
| 29 |
+
type UserProfileResponse struct {
|
| 30 |
+
Account Account `json:"account"`
|
| 31 |
+
Details AccountDetails `json:"details"`
|
| 32 |
+
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/repositories/account_repository.go
CHANGED
|
@@ -1,8 +1,6 @@
|
|
| 1 |
package repositories
|
| 2 |
|
| 3 |
import (
|
| 4 |
-
"fmt"
|
| 5 |
-
|
| 6 |
"api.qobiltu.id/models"
|
| 7 |
)
|
| 8 |
|
|
@@ -64,8 +62,6 @@ func CreateAccountDetails(accountDetails models.AccountDetails) Repository[model
|
|
| 64 |
repo := Construct[models.AccountDetails, models.AccountDetails](
|
| 65 |
accountDetails,
|
| 66 |
)
|
| 67 |
-
fmt.Println(accountDetails)
|
| 68 |
-
fmt.Println("Account ID : ", accountDetails.AccountID)
|
| 69 |
Create(repo)
|
| 70 |
return *repo
|
| 71 |
}
|
|
|
|
| 1 |
package repositories
|
| 2 |
|
| 3 |
import (
|
|
|
|
|
|
|
| 4 |
"api.qobiltu.id/models"
|
| 5 |
)
|
| 6 |
|
|
|
|
| 62 |
repo := Construct[models.AccountDetails, models.AccountDetails](
|
| 63 |
accountDetails,
|
| 64 |
)
|
|
|
|
|
|
|
| 65 |
Create(repo)
|
| 66 |
return *repo
|
| 67 |
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/repositories/forgot_password_repository.go
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package repositories
|
| 2 |
+
|
| 3 |
+
import "api.qobiltu.id/models"
|
| 4 |
+
|
| 5 |
+
func CreateForgotPassword(forgotPassword models.ForgotPassword) Repository[models.ForgotPassword, models.ForgotPassword] {
|
| 6 |
+
repo := Construct[models.ForgotPassword, models.ForgotPassword](
|
| 7 |
+
forgotPassword,
|
| 8 |
+
)
|
| 9 |
+
Create(repo)
|
| 10 |
+
return *repo
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
func GetForgotPasswordByToken(token uint) Repository[models.ForgotPassword, models.ForgotPassword] {
|
| 14 |
+
repo := Construct[models.ForgotPassword, models.ForgotPassword](
|
| 15 |
+
models.ForgotPassword{Token: token},
|
| 16 |
+
)
|
| 17 |
+
repo.Transactions(
|
| 18 |
+
WhereGivenConstructor[models.ForgotPassword, models.ForgotPassword],
|
| 19 |
+
Find[models.ForgotPassword, models.ForgotPassword],
|
| 20 |
+
)
|
| 21 |
+
return *repo
|
| 22 |
+
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/router/router.go
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
package router
|
| 2 |
|
| 3 |
import (
|
|
|
|
|
|
|
| 4 |
"api.qobiltu.id/config"
|
| 5 |
"api.qobiltu.id/controller"
|
| 6 |
"github.com/gin-gonic/gin"
|
|
@@ -9,9 +11,14 @@ import (
|
|
| 9 |
func StartService() {
|
| 10 |
router := gin.Default()
|
| 11 |
router.GET("/", controller.HomeController)
|
|
|
|
| 12 |
AuthRoute(router)
|
| 13 |
UserRoute(router)
|
| 14 |
EmailRoute(router)
|
| 15 |
OptionsRoute(router)
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
}
|
|
|
|
| 1 |
package router
|
| 2 |
|
| 3 |
import (
|
| 4 |
+
"log"
|
| 5 |
+
|
| 6 |
"api.qobiltu.id/config"
|
| 7 |
"api.qobiltu.id/controller"
|
| 8 |
"github.com/gin-gonic/gin"
|
|
|
|
| 11 |
func StartService() {
|
| 12 |
router := gin.Default()
|
| 13 |
router.GET("/", controller.HomeController)
|
| 14 |
+
|
| 15 |
AuthRoute(router)
|
| 16 |
UserRoute(router)
|
| 17 |
EmailRoute(router)
|
| 18 |
OptionsRoute(router)
|
| 19 |
+
|
| 20 |
+
err := router.Run(config.TCP_ADDRESS)
|
| 21 |
+
if err != nil {
|
| 22 |
+
log.Fatalf("Failed to run server: %v", err)
|
| 23 |
+
}
|
| 24 |
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/external_authentication_service.go
CHANGED
|
@@ -27,15 +27,14 @@ func (s *GoogleAuthService) Authenticate() {
|
|
| 27 |
if GoogleAuth.NoRecord {
|
| 28 |
s.Constructor.UUID = uuid.NewV4()
|
| 29 |
s.Constructor.OauthProvider = "Google"
|
| 30 |
-
|
| 31 |
-
createGoogleAuth := repositories.CreateExternalAuth(s.Constructor)
|
| 32 |
-
|
| 33 |
-
s.Error = createGoogleAuth.RowsError
|
| 34 |
-
|
| 35 |
createAccount := repositories.CreateAccount(models.Account{
|
| 36 |
Email: email.(string),
|
| 37 |
IsEmailVerified: true,
|
| 38 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
s.Error = errors.Join(s.Error, createAccount.RowsError)
|
| 40 |
}
|
| 41 |
accountData := repositories.GetAccountById(GoogleAuth.Result.AccountID)
|
|
|
|
| 27 |
if GoogleAuth.NoRecord {
|
| 28 |
s.Constructor.UUID = uuid.NewV4()
|
| 29 |
s.Constructor.OauthProvider = "Google"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
createAccount := repositories.CreateAccount(models.Account{
|
| 31 |
Email: email.(string),
|
| 32 |
IsEmailVerified: true,
|
| 33 |
})
|
| 34 |
+
s.Constructor.AccountID = createAccount.Result.Id
|
| 35 |
+
createGoogleAuth := repositories.CreateExternalAuth(s.Constructor)
|
| 36 |
+
|
| 37 |
+
s.Error = createGoogleAuth.RowsError
|
| 38 |
s.Error = errors.Join(s.Error, createAccount.RowsError)
|
| 39 |
}
|
| 40 |
accountData := repositories.GetAccountById(GoogleAuth.Result.AccountID)
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/user_profile_service.go
CHANGED
|
@@ -1,17 +1,51 @@
|
|
| 1 |
package services
|
| 2 |
|
| 3 |
import (
|
| 4 |
-
"
|
|
|
|
| 5 |
|
| 6 |
"api.qobiltu.id/models"
|
| 7 |
"api.qobiltu.id/repositories"
|
| 8 |
)
|
| 9 |
|
| 10 |
type UserProfileService struct {
|
| 11 |
-
Service[models.AccountDetails, models.
|
| 12 |
}
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
func (s *UserProfileService) Create() {
|
|
|
|
|
|
|
| 15 |
userProfile := repositories.CreateAccountDetails(s.Constructor)
|
| 16 |
s.Error = userProfile.RowsError
|
| 17 |
if userProfile.NoRecord {
|
|
@@ -19,7 +53,10 @@ func (s *UserProfileService) Create() {
|
|
| 19 |
s.Exception.Message = "There is no account with given credentials!"
|
| 20 |
return
|
| 21 |
}
|
| 22 |
-
s.Result =
|
|
|
|
|
|
|
|
|
|
| 23 |
}
|
| 24 |
func (s *UserProfileService) Retrieve() {
|
| 25 |
userProfile := repositories.GetDetailAccountById(s.Constructor.AccountID)
|
|
@@ -29,11 +66,15 @@ func (s *UserProfileService) Retrieve() {
|
|
| 29 |
s.Exception.Message = "There is no account with given credentials!"
|
| 30 |
return
|
| 31 |
}
|
| 32 |
-
s.Result =
|
|
|
|
|
|
|
|
|
|
| 33 |
}
|
| 34 |
|
| 35 |
func (s *UserProfileService) Update() {
|
| 36 |
-
|
|
|
|
| 37 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
| 38 |
s.Error = userProfile.RowsError
|
| 39 |
if userProfile.NoRecord {
|
|
@@ -41,5 +82,8 @@ func (s *UserProfileService) Update() {
|
|
| 41 |
s.Exception.Message = "There is no account with given credentials!"
|
| 42 |
return
|
| 43 |
}
|
| 44 |
-
s.Result =
|
|
|
|
|
|
|
|
|
|
| 45 |
}
|
|
|
|
| 1 |
package services
|
| 2 |
|
| 3 |
import (
|
| 4 |
+
"regexp"
|
| 5 |
+
"strings"
|
| 6 |
|
| 7 |
"api.qobiltu.id/models"
|
| 8 |
"api.qobiltu.id/repositories"
|
| 9 |
)
|
| 10 |
|
| 11 |
type UserProfileService struct {
|
| 12 |
+
Service[models.AccountDetails, models.UserProfileResponse]
|
| 13 |
}
|
| 14 |
|
| 15 |
+
// SanitizePhoneNumber membersihkan dan menormalkan nomor telepon ke format +62
|
| 16 |
+
func SanitizePhoneNumber(input string) string {
|
| 17 |
+
// Hilangkan semua spasi dan strip
|
| 18 |
+
input = strings.ReplaceAll(input, " ", "")
|
| 19 |
+
input = strings.ReplaceAll(input, "-", "")
|
| 20 |
+
input = strings.ReplaceAll(input, "(", "")
|
| 21 |
+
input = strings.ReplaceAll(input, ")", "")
|
| 22 |
+
|
| 23 |
+
// Hilangkan semua karakter non-digit kecuali +
|
| 24 |
+
re := regexp.MustCompile(`[^0-9\+]`)
|
| 25 |
+
input = re.ReplaceAllString(input, "")
|
| 26 |
+
|
| 27 |
+
// Handle nomor diawali 0 (contoh: 0812...) menjadi +62812...
|
| 28 |
+
if strings.HasPrefix(input, "0") {
|
| 29 |
+
input = "+62" + input[1:]
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
// Handle jika diawali dengan 62 tanpa + (contoh: 62812...)
|
| 33 |
+
if strings.HasPrefix(input, "62") && !strings.HasPrefix(input, "+62") {
|
| 34 |
+
input = "+" + input
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
// Handle jika tidak ada awalan +62 sama sekali (contoh: 8123456789)
|
| 38 |
+
if !strings.HasPrefix(input, "+62") {
|
| 39 |
+
if strings.HasPrefix(input, "8") {
|
| 40 |
+
input = "+62" + input
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
return input
|
| 45 |
+
}
|
| 46 |
func (s *UserProfileService) Create() {
|
| 47 |
+
phoneNumber := *s.Constructor.PhoneNumber
|
| 48 |
+
*s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
|
| 49 |
userProfile := repositories.CreateAccountDetails(s.Constructor)
|
| 50 |
s.Error = userProfile.RowsError
|
| 51 |
if userProfile.NoRecord {
|
|
|
|
| 53 |
s.Exception.Message = "There is no account with given credentials!"
|
| 54 |
return
|
| 55 |
}
|
| 56 |
+
s.Result = models.UserProfileResponse{
|
| 57 |
+
Account: repositories.GetAccountById(s.Constructor.AccountID).Result,
|
| 58 |
+
Details: userProfile.Result,
|
| 59 |
+
}
|
| 60 |
}
|
| 61 |
func (s *UserProfileService) Retrieve() {
|
| 62 |
userProfile := repositories.GetDetailAccountById(s.Constructor.AccountID)
|
|
|
|
| 66 |
s.Exception.Message = "There is no account with given credentials!"
|
| 67 |
return
|
| 68 |
}
|
| 69 |
+
s.Result = models.UserProfileResponse{
|
| 70 |
+
Account: repositories.GetAccountById(s.Constructor.AccountID).Result,
|
| 71 |
+
Details: userProfile.Result,
|
| 72 |
+
}
|
| 73 |
}
|
| 74 |
|
| 75 |
func (s *UserProfileService) Update() {
|
| 76 |
+
phoneNumber := *s.Constructor.PhoneNumber
|
| 77 |
+
*s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
|
| 78 |
userProfile := repositories.UpdateAccountDetails(s.Constructor)
|
| 79 |
s.Error = userProfile.RowsError
|
| 80 |
if userProfile.NoRecord {
|
|
|
|
| 82 |
s.Exception.Message = "There is no account with given credentials!"
|
| 83 |
return
|
| 84 |
}
|
| 85 |
+
s.Result = models.UserProfileResponse{
|
| 86 |
+
Account: repositories.GetAccountById(s.Constructor.AccountID).Result,
|
| 87 |
+
Details: userProfile.Result,
|
| 88 |
+
}
|
| 89 |
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/.gitignore
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
.env
|
| 2 |
vendor/
|
| 3 |
quzuu-be.exe
|
| 4 |
-
README.md
|
| 5 |
-
.qodo
|
|
|
|
|
|
|
|
|
| 1 |
.env
|
| 2 |
vendor/
|
| 3 |
quzuu-be.exe
|
| 4 |
+
README.md
|
| 5 |
+
.qodo
|
| 6 |
+
.error
|
| 7 |
+
logs/
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/config/config.go
CHANGED
|
@@ -9,10 +9,16 @@ import (
|
|
| 9 |
|
| 10 |
var TCP_ADDRESS string
|
| 11 |
var LOG_PATH string
|
|
|
|
| 12 |
var HOST_ADDRESS string
|
| 13 |
var HOST_PORT string
|
| 14 |
var EMAIL_VERIFICATION_DURATION int
|
| 15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
func init() {
|
| 17 |
godotenv.Load()
|
| 18 |
HOST_ADDRESS = os.Getenv("HOST_ADDRESS")
|
|
@@ -20,5 +26,9 @@ func init() {
|
|
| 20 |
TCP_ADDRESS = HOST_ADDRESS + ":" + HOST_PORT
|
| 21 |
LOG_PATH = os.Getenv("LOG_PATH")
|
| 22 |
EMAIL_VERIFICATION_DURATION, _ = strconv.Atoi(os.Getenv("EMAIL_VERIFICATION_DURATION"))
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
// Menampilkan nilai variabel lingkungan
|
| 24 |
}
|
|
|
|
| 9 |
|
| 10 |
var TCP_ADDRESS string
|
| 11 |
var LOG_PATH string
|
| 12 |
+
|
| 13 |
var HOST_ADDRESS string
|
| 14 |
var HOST_PORT string
|
| 15 |
var EMAIL_VERIFICATION_DURATION int
|
| 16 |
|
| 17 |
+
var SMTP_SENDER_EMAIL string
|
| 18 |
+
var SMTP_SENDER_PASSWORD string
|
| 19 |
+
var SMTP_HOST string
|
| 20 |
+
var SMTP_PORT string
|
| 21 |
+
|
| 22 |
func init() {
|
| 23 |
godotenv.Load()
|
| 24 |
HOST_ADDRESS = os.Getenv("HOST_ADDRESS")
|
|
|
|
| 26 |
TCP_ADDRESS = HOST_ADDRESS + ":" + HOST_PORT
|
| 27 |
LOG_PATH = os.Getenv("LOG_PATH")
|
| 28 |
EMAIL_VERIFICATION_DURATION, _ = strconv.Atoi(os.Getenv("EMAIL_VERIFICATION_DURATION"))
|
| 29 |
+
SMTP_SENDER_EMAIL = os.Getenv("SMTP_SENDER_EMAIL")
|
| 30 |
+
SMTP_SENDER_PASSWORD = os.Getenv("SMTP_SENDER_PASSWORD")
|
| 31 |
+
SMTP_HOST = os.Getenv("SMTP_HOST")
|
| 32 |
+
SMTP_PORT = os.Getenv("SMTP_PORT")
|
| 33 |
// Menampilkan nilai variabel lingkungan
|
| 34 |
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/config/database_connection_config.go
CHANGED
|
@@ -60,6 +60,10 @@ func AutoMigrateAll(db *gorm.DB) {
|
|
| 60 |
&models.AcademyContent{},
|
| 61 |
&models.AcademyMaterialProgress{},
|
| 62 |
&models.AcademyContentProgress{},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
)
|
| 64 |
|
| 65 |
if err != nil {
|
|
|
|
| 60 |
&models.AcademyContent{},
|
| 61 |
&models.AcademyMaterialProgress{},
|
| 62 |
&models.AcademyContentProgress{},
|
| 63 |
+
&models.RegionCity{},
|
| 64 |
+
&models.RegionProvince{},
|
| 65 |
+
&models.OptionCategory{},
|
| 66 |
+
&models.OptionValues{},
|
| 67 |
)
|
| 68 |
|
| 69 |
if err != nil {
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/auth/auth_external_controller.go
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package auth
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"api.qobiltu.id/controller"
|
| 5 |
+
"api.qobiltu.id/models"
|
| 6 |
+
"api.qobiltu.id/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
func ExternalAuth(c *gin.Context) {
|
| 11 |
+
ExternalAuthController := controller.Controller[models.ExternalAuthRequest, models.ExternalAuth, models.AuthenticatedUser]{}
|
| 12 |
+
ExternalAuthController.RequestJSON(c, func() {
|
| 13 |
+
if ExternalAuthController.Request.OauthProvider == "google" {
|
| 14 |
+
GoogleLogin := services.GoogleAuthService{}
|
| 15 |
+
ExternalAuthController.Service = &GoogleLogin.Service
|
| 16 |
+
ExternalAuthController.Service.Constructor.OauthID = ExternalAuthController.Request.OauthID
|
| 17 |
+
GoogleLogin.Authenticate()
|
| 18 |
+
}
|
| 19 |
+
})
|
| 20 |
+
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/auth/auth_forgot_password_controller.go
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
package auth
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/email/email_create_verification_controller.go
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package controller
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"api.qobiltu.id/controller"
|
| 5 |
+
"api.qobiltu.id/models"
|
| 6 |
+
"api.qobiltu.id/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
func CreateVerification(c *gin.Context) {
|
| 11 |
+
emailVerification := services.EmailVerificationService{}
|
| 12 |
+
emailVerificationController := controller.Controller[models.CreateVerifyEmailRequest, models.EmailVerification, models.EmailVerification]{
|
| 13 |
+
Service: &emailVerification.Service,
|
| 14 |
+
}
|
| 15 |
+
emailVerificationController.HeaderParse(c, func() {
|
| 16 |
+
emailVerificationController.Service.Constructor.AccountID = uint(emailVerificationController.AccountData.UserID)
|
| 17 |
+
emailVerification.Create()
|
| 18 |
+
emailVerificationController.Response(c)
|
| 19 |
+
})
|
| 20 |
+
|
| 21 |
+
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/email/email_validate_controller.go
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package controller
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"api.qobiltu.id/controller"
|
| 5 |
+
"api.qobiltu.id/models"
|
| 6 |
+
"api.qobiltu.id/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
func Verify(c *gin.Context) {
|
| 11 |
+
emailVerification := services.EmailVerificationService{}
|
| 12 |
+
emailVerificationController := controller.Controller[models.CreateVerifyEmailRequest, models.EmailVerification, models.EmailVerification]{
|
| 13 |
+
Service: &emailVerification.Service,
|
| 14 |
+
}
|
| 15 |
+
emailVerificationController.HeaderParse(c, func() {
|
| 16 |
+
emailVerificationController.Service.Constructor.AccountID = uint(emailVerificationController.AccountData.UserID)
|
| 17 |
+
emailVerificationController.RequestJSON(c, func() {
|
| 18 |
+
emailVerificationController.Service.Constructor.Token = emailVerificationController.Request.Token
|
| 19 |
+
emailVerificationController.Service.Constructor.UUID = emailVerificationController.Request.UUID
|
| 20 |
+
emailVerification.Validate()
|
| 21 |
+
})
|
| 22 |
+
})
|
| 23 |
+
|
| 24 |
+
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/options/option_category_controller.go
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package options
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"api.qobiltu.id/controller"
|
| 5 |
+
"api.qobiltu.id/models"
|
| 6 |
+
"api.qobiltu.id/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
func AddOptions(c *gin.Context) {
|
| 11 |
+
options := services.OptionService{}
|
| 12 |
+
addOptionController := controller.Controller[[]models.OptionsRequest, []models.OptionsRequest, models.OptionsResponse]{
|
| 13 |
+
Service: &options.Service,
|
| 14 |
+
}
|
| 15 |
+
addOptionController.RequestJSON(c, func() {
|
| 16 |
+
options.Constructor = addOptionController.Request
|
| 17 |
+
options.Create()
|
| 18 |
+
})
|
| 19 |
+
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/options/option_value_controller.go
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package options
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"api.qobiltu.id/controller"
|
| 5 |
+
"api.qobiltu.id/models"
|
| 6 |
+
"api.qobiltu.id/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
func List(c *gin.Context) {
|
| 11 |
+
options := services.OptionValueService{}
|
| 12 |
+
optionValueController := controller.Controller[any, models.OptionCategory, models.Options]{
|
| 13 |
+
Service: &options.Service,
|
| 14 |
+
}
|
| 15 |
+
slug := c.Param("slug")
|
| 16 |
+
options.Constructor.OptionSlug = slug
|
| 17 |
+
options.Retrieve()
|
| 18 |
+
optionValueController.Response(c)
|
| 19 |
+
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/region/city/city_list_controller.go
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package city
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"strconv"
|
| 5 |
+
|
| 6 |
+
"api.qobiltu.id/controller"
|
| 7 |
+
"api.qobiltu.id/models"
|
| 8 |
+
"api.qobiltu.id/services"
|
| 9 |
+
"github.com/gin-gonic/gin"
|
| 10 |
+
)
|
| 11 |
+
|
| 12 |
+
func List(c *gin.Context) {
|
| 13 |
+
city := services.CityService{}
|
| 14 |
+
CityController := controller.Controller[any, models.RegionCity, []models.RegionCity]{
|
| 15 |
+
Service: &city.Service,
|
| 16 |
+
}
|
| 17 |
+
ProvinceID, _ := strconv.Atoi(c.Query("province_id"))
|
| 18 |
+
city.Constructor.ProvinceID = uint(ProvinceID)
|
| 19 |
+
city.Retrieve()
|
| 20 |
+
CityController.Response(c)
|
| 21 |
+
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/region/city/city_seeds_controller.go
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package city
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"api.qobiltu.id/controller"
|
| 5 |
+
"api.qobiltu.id/models"
|
| 6 |
+
"api.qobiltu.id/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
func Seeds(c *gin.Context) {
|
| 11 |
+
city := services.CityService{}
|
| 12 |
+
CityController := controller.Controller[any, models.RegionCity, []models.RegionCity]{
|
| 13 |
+
Service: &city.Service,
|
| 14 |
+
}
|
| 15 |
+
city.Create()
|
| 16 |
+
CityController.Response(c)
|
| 17 |
+
}
|
space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/region/province/province_list_controller.go
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
package province
|
| 2 |
+
|
| 3 |
+
import (
|
| 4 |
+
"api.qobiltu.id/controller"
|
| 5 |
+
"api.qobiltu.id/models"
|
| 6 |
+
"api.qobiltu.id/services"
|
| 7 |
+
"github.com/gin-gonic/gin"
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
func List(c *gin.Context) {
|
| 11 |
+
province := services.ProvinceService{}
|
| 12 |
+
ProvinceController := controller.Controller[any, models.RegionProvince, []models.RegionProvince]{
|
| 13 |
+
Service: &province.Service,
|
| 14 |
+
}
|
| 15 |
+
province.Retrieve()
|
| 16 |
+
ProvinceController.Response(c)
|
| 17 |
+
}
|