lifedebugger commited on
Commit
8c37caf
·
1 Parent(s): aabd743

Deploy files from GitHub repository

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. controller/auth/auth_forgot_password_controller.go +1 -1
  2. models/request_model.go +1 -1
  3. models/response_model.go +10 -0
  4. services/forgot_password_service.go +7 -3
  5. space/controller/auth/auth_external_controller.go +1 -1
  6. space/controller/auth/auth_forgot_password_controller.go +28 -0
  7. space/controller/email/email_validate_controller.go +0 -1
  8. space/models/request_model.go +9 -4
  9. space/repositories/account_repository.go +2 -4
  10. space/router/auth_route.go +2 -0
  11. space/services/authentication_service.go +2 -1
  12. space/services/email_verification_service.go +5 -1
  13. space/services/external_authentication_service.go +6 -1
  14. space/services/forgot_password_service.go +105 -0
  15. space/services/user_profile_service.go +20 -5
  16. space/space/space/services/email_verification_service.go +11 -60
  17. space/space/space/space/space/services/email_verification_service.go +60 -11
  18. space/space/space/space/space/space/services/user_profile_service.go +3 -1
  19. space/space/space/space/space/space/space/models/request_model.go +4 -2
  20. space/space/space/space/space/space/space/services/authentication_service.go +2 -0
  21. space/space/space/space/space/space/space/services/email_verification_service.go +4 -0
  22. space/space/space/space/space/space/space/services/user_profile_service.go +5 -2
  23. space/space/space/space/space/space/space/space/repositories/account_repository.go +9 -0
  24. space/space/space/space/space/space/space/space/services/external_authentication_service.go +1 -1
  25. space/space/space/space/space/space/space/space/services/user_profile_service.go +8 -0
  26. space/space/space/space/space/space/space/space/space/services/user_profile_service.go +8 -2
  27. space/space/space/space/space/space/space/space/space/space/docker-compose.yml +1 -1
  28. space/space/space/space/space/space/space/space/space/space/space/space/Dockerfile +3 -0
  29. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/user/user_profile_controller.go +1 -1
  30. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/user/user_update_profile_controller.go +2 -4
  31. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/logs/error_log.txt +1 -0
  32. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/middleware/authentication_middleware.go +0 -3
  33. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/models/response_model.go +5 -0
  34. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/repositories/account_repository.go +0 -4
  35. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/repositories/forgot_password_repository.go +22 -0
  36. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/router/router.go +8 -1
  37. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/external_authentication_service.go +4 -5
  38. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/user_profile_service.go +50 -6
  39. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/.gitignore +4 -2
  40. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/config/config.go +10 -0
  41. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/config/database_connection_config.go +4 -0
  42. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/auth/auth_external_controller.go +20 -0
  43. 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
  44. 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
  45. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/email/email_validate_controller.go +24 -0
  46. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/options/option_category_controller.go +19 -0
  47. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/controller/options/option_value_controller.go +19 -0
  48. 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
  49. 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
  50. 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" binding:"required"`
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
- hashed_password, _ := HashPassword(newPassword)
 
 
 
 
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
- s.Result = fgPasswordRepo.Result
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 `json:"token" binding:"required"`
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.Transactions(
43
- WhereGivenConstructor[models.Account, models.Account],
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
- accountData.Result.Password = newPassword
 
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 *s.Constructor.Gender {
82
- initialName = "IKH_"
83
- } else {
84
- initialName = "AKH_"
 
 
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: repositories.GetAccountById(s.Constructor.AccountID).Result,
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
- 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
 
 
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
- 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
 
 
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 += string(usersCount)
 
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 string `json:"oauth_id" binding:"required"`
34
- OauthProvider string `json:"oauth_provider" binding:"required"`
 
 
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
- phoneNumber := *s.Constructor.PhoneNumber
75
- *s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
 
 
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
- - db-data:/var/lib/postgresql/data
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.AccountDetails]{
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.AccountDetails]{
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
- fmt.Println("Account ID:", userUpdateProfileController.Service.Constructor.AccountID)
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
- router.Run(config.TCP_ADDRESS)
 
 
 
 
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
- "fmt"
 
5
 
6
  "api.qobiltu.id/models"
7
  "api.qobiltu.id/repositories"
8
  )
9
 
10
  type UserProfileService struct {
11
- Service[models.AccountDetails, models.AccountDetails]
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 = userProfile.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 = userProfile.Result
 
 
 
33
  }
34
 
35
  func (s *UserProfileService) Update() {
36
- fmt.Println("Account ID:", s.Constructor.AccountID)
 
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 = userProfile.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
+ }