lifedebugger commited on
Commit
b2a56df
·
1 Parent(s): 16f5cb3

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. services/email_verification_service.go +3 -14
  2. space/controller/auth/auth_login_controller.go +1 -1
  3. space/controller/auth/auth_register_controller.go +1 -1
  4. space/controller/controller.go +1 -1
  5. space/space/config/config.go +2 -0
  6. space/space/services/email_verification_service.go +100 -8
  7. space/space/space/services/external_authentication_service.go +10 -6
  8. space/space/space/space/services/email_verification_service.go +1 -4
  9. space/space/space/space/services/forgot_password_service.go +1 -4
  10. space/space/space/space/space/services/external_authentication_service.go +18 -1
  11. space/space/space/space/space/space/controller/academy/academy_controller.go +31 -0
  12. space/space/space/space/space/space/logs/error_log.txt +2 -0
  13. space/space/space/space/space/space/models/database_orm_model.go +7 -7
  14. space/space/space/space/space/space/repositories/academy_repository.go +28 -2
  15. space/space/space/space/space/space/router/academy_route.go +16 -0
  16. space/space/space/space/space/space/router/router.go +1 -1
  17. space/space/space/space/space/space/services/academy_service.go +75 -11
  18. space/space/space/space/space/space/services/email_verification_service.go +5 -2
  19. space/space/space/space/space/space/services/forgot_password_service.go +4 -1
  20. space/space/space/space/space/space/space/logs/error_log.txt +0 -1
  21. space/space/space/space/space/space/space/models/response_model.go +9 -6
  22. space/space/space/space/space/space/space/repositories/academy_repository.go +47 -0
  23. space/space/space/space/space/space/space/services/academy_service.go +40 -0
  24. space/space/space/space/space/space/space/services/external_authentication_service.go +1 -0
  25. space/space/space/space/space/space/space/services/forgot_password_service.go +11 -7
  26. space/space/space/space/space/space/space/space/space/go.mod +2 -5
  27. space/space/space/space/space/space/space/space/space/go.sum +17 -13
  28. space/space/space/space/space/space/space/space/space/space/models/response_model.go +10 -0
  29. space/space/space/space/space/space/space/space/space/space/services/forgot_password_service.go +7 -3
  30. space/space/space/space/space/space/space/space/space/space/space/controller/auth/auth_external_controller.go +1 -1
  31. space/space/space/space/space/space/space/space/space/space/space/controller/auth/auth_forgot_password_controller.go +28 -0
  32. space/space/space/space/space/space/space/space/space/space/space/controller/email/email_validate_controller.go +0 -1
  33. space/space/space/space/space/space/space/space/space/space/space/models/request_model.go +9 -4
  34. space/space/space/space/space/space/space/space/space/space/space/repositories/account_repository.go +2 -4
  35. space/space/space/space/space/space/space/space/space/space/space/router/auth_route.go +2 -0
  36. space/space/space/space/space/space/space/space/space/space/space/services/authentication_service.go +2 -1
  37. space/space/space/space/space/space/space/space/space/space/space/services/email_verification_service.go +5 -1
  38. space/space/space/space/space/space/space/space/space/space/space/services/external_authentication_service.go +6 -1
  39. space/space/space/space/space/space/space/space/space/space/space/services/forgot_password_service.go +105 -0
  40. space/space/space/space/space/space/space/space/space/space/space/services/user_profile_service.go +20 -5
  41. space/space/space/space/space/space/space/space/space/space/space/space/space/services/email_verification_service.go +11 -60
  42. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/email_verification_service.go +60 -11
  43. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/models/request_model.go +4 -2
  44. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/authentication_service.go +2 -0
  45. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/email_verification_service.go +4 -0
  46. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/user_profile_service.go +8 -3
  47. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/repositories/account_repository.go +9 -0
  48. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/external_authentication_service.go +1 -1
  49. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/services/user_profile_service.go +8 -2
  50. space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/space/docker-compose.yml +1 -1
services/email_verification_service.go CHANGED
@@ -75,18 +75,7 @@ func (s *EmailVerificationService) Create() {
75
  return
76
  }
77
 
78
- // 2. Start TLS
79
- tlsconfig := &tls.Config{
80
- ServerName: smtpHost,
81
- }
82
-
83
- if err = c.StartTLS(tlsconfig); err != nil {
84
- s.Error = err
85
- log.Printf("Error start TLS: %v", err)
86
- return
87
- }
88
-
89
- // 3. Auth
90
  auth := smtp.PlainAuth("", from, password, smtpHost)
91
  if err = c.Auth(auth); err != nil {
92
  s.Error = err
@@ -94,7 +83,7 @@ func (s *EmailVerificationService) Create() {
94
  return
95
  }
96
 
97
- // 4. Set From and To
98
  if err = c.Mail(from); err != nil {
99
  s.Error = err
100
  log.Printf("Error set mail from to: %v", err)
@@ -109,7 +98,7 @@ func (s *EmailVerificationService) Create() {
109
  }
110
  }
111
 
112
- // 5. Send message
113
  wc, err := c.Data()
114
  if err != nil {
115
  s.Error = err
 
75
  return
76
  }
77
 
78
+ // 2. Auth
 
 
 
 
 
 
 
 
 
 
 
79
  auth := smtp.PlainAuth("", from, password, smtpHost)
80
  if err = c.Auth(auth); err != nil {
81
  s.Error = err
 
83
  return
84
  }
85
 
86
+ // 3. Set From and To
87
  if err = c.Mail(from); err != nil {
88
  s.Error = err
89
  log.Printf("Error set mail from to: %v", err)
 
98
  }
99
  }
100
 
101
+ // 4. Send message
102
  wc, err := c.Data()
103
  if err != nil {
104
  s.Error = err
space/controller/auth/auth_login_controller.go CHANGED
@@ -1,4 +1,4 @@
1
- package user
2
 
3
  import (
4
  "api.qobiltu.id/controller"
 
1
+ package auth
2
 
3
  import (
4
  "api.qobiltu.id/controller"
space/controller/auth/auth_register_controller.go CHANGED
@@ -1,4 +1,4 @@
1
- package user
2
 
3
  import (
4
  "api.qobiltu.id/controller"
 
1
+ package auth
2
 
3
  import (
4
  "api.qobiltu.id/controller"
space/controller/controller.go CHANGED
@@ -46,11 +46,11 @@ func (controller *Controller[T1, T2, T3]) RequestJSON(c *gin.Context, act func()
46
  func (controller *Controller[T1, T2, T3]) Response(c *gin.Context) {
47
  switch {
48
  case controller.Service.Error != nil:
 
49
  utils.ResponseFAIL(c, 500, models.Exception{
50
  InternalServerError: true,
51
  Message: "Internal Server Error",
52
  })
53
- utils.LogError(controller.Service.Error)
54
  case controller.Service.Exception.DataDuplicate:
55
  utils.ResponseFAIL(c, 400, controller.Service.Exception)
56
  case controller.Service.Exception.Unauthorized:
 
46
  func (controller *Controller[T1, T2, T3]) Response(c *gin.Context) {
47
  switch {
48
  case controller.Service.Error != nil:
49
+ utils.LogError(controller.Service.Error)
50
  utils.ResponseFAIL(c, 500, models.Exception{
51
  InternalServerError: true,
52
  Message: "Internal Server Error",
53
  })
 
54
  case controller.Service.Exception.DataDuplicate:
55
  utils.ResponseFAIL(c, 400, controller.Service.Exception)
56
  case controller.Service.Exception.Unauthorized:
space/space/config/config.go CHANGED
@@ -7,6 +7,7 @@ import (
7
  "github.com/joho/godotenv"
8
  )
9
 
 
10
  var TCP_ADDRESS string
11
  var LOG_PATH string
12
 
@@ -21,6 +22,7 @@ var SMTP_PORT string
21
 
22
  func init() {
23
  godotenv.Load()
 
24
  HOST_ADDRESS = os.Getenv("HOST_ADDRESS")
25
  HOST_PORT = os.Getenv("HOST_PORT")
26
  TCP_ADDRESS = HOST_ADDRESS + ":" + HOST_PORT
 
7
  "github.com/joho/godotenv"
8
  )
9
 
10
+ var ENV string
11
  var TCP_ADDRESS string
12
  var LOG_PATH string
13
 
 
22
 
23
  func init() {
24
  godotenv.Load()
25
+ ENV = os.Getenv("ENV")
26
  HOST_ADDRESS = os.Getenv("HOST_ADDRESS")
27
  HOST_PORT = os.Getenv("HOST_PORT")
28
  TCP_ADDRESS = HOST_ADDRESS + ":" + HOST_PORT
space/space/services/email_verification_service.go CHANGED
@@ -1,6 +1,7 @@
1
  package services
2
 
3
  import (
 
4
  "fmt"
5
  "log"
6
  "math/rand/v2"
@@ -39,27 +40,118 @@ func (s *EmailVerificationService) Create() {
39
 
40
  // ⬇ Kirim token ke email user menggunakan SMTP
41
  go func(toEmail string, token uint) {
 
42
  from := config.SMTP_SENDER_EMAIL
43
  password := config.SMTP_SENDER_PASSWORD
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
  // s.Result.Token = 0
65
  }
 
1
  package services
2
 
3
  import (
4
+ "crypto/tls"
5
  "fmt"
6
  "log"
7
  "math/rand/v2"
 
40
 
41
  // ⬇ Kirim token ke email user menggunakan SMTP
42
  go func(toEmail string, token uint) {
43
+ env := config.ENV
44
  from := config.SMTP_SENDER_EMAIL
45
  password := config.SMTP_SENDER_PASSWORD
46
  smtpHost := config.SMTP_HOST
47
  smtpPort := config.SMTP_PORT
48
+ to := []string{toEmail}
49
 
50
+ subject := "Verification token"
 
 
51
  body := fmt.Sprintf("Your verification token is: %06d\nPlease use it before it expires.", token)
52
 
53
+ msg := []byte(fmt.Sprintf("From: %s\r\n", from) +
54
+ fmt.Sprintf("To: %s\r\n", toEmail) +
55
+ fmt.Sprintf("Subject: %s\r\n", subject) +
56
+ "\r\n" + body)
57
+
58
+ // 1. Connect to the server
59
+ conn, err := tls.Dial("tcp", fmt.Sprintf("[%s]:%s", smtpHost, smtpPort), &tls.Config{
60
+ InsecureSkipVerify: env != "production", // ⚠️ set false di production
61
+ ServerName: smtpHost,
62
+ })
63
 
64
+ // conn, err := net.Dial("tcp", fmt.Sprintf("[%s]:%s", smtpHost, smtpPort))
65
  if err != nil {
66
  s.Error = err
67
  log.Printf("Error sending verification email: %v", err)
68
  return
69
  }
70
+
71
+ c, err := smtp.NewClient(conn, smtpHost)
72
+ if err != nil {
73
+ s.Error = err
74
+ log.Printf("Error create new client mail: %v", err)
75
+ return
76
+ }
77
+
78
+ // 2. Start TLS
79
+ tlsconfig := &tls.Config{
80
+ ServerName: smtpHost,
81
+ }
82
+
83
+ if err = c.StartTLS(tlsconfig); err != nil {
84
+ s.Error = err
85
+ log.Printf("Error start TLS: %v", err)
86
+ return
87
+ }
88
+
89
+ // 3. Auth
90
+ auth := smtp.PlainAuth("", from, password, smtpHost)
91
+ if err = c.Auth(auth); err != nil {
92
+ s.Error = err
93
+ log.Printf("Error auth mail: %v", err)
94
+ return
95
+ }
96
+
97
+ // 4. Set From and To
98
+ if err = c.Mail(from); err != nil {
99
+ s.Error = err
100
+ log.Printf("Error set mail from to: %v", err)
101
+ return
102
+ }
103
+
104
+ for _, addr := range to {
105
+ if err = c.Rcpt(addr); err != nil {
106
+ s.Error = err
107
+ log.Printf("Error receipt addr: %v", err)
108
+ return
109
+ }
110
+ }
111
+
112
+ // 5. Send message
113
+ wc, err := c.Data()
114
+ if err != nil {
115
+ s.Error = err
116
+ log.Printf("Error data Send Message: %v", err)
117
+ return
118
+ }
119
+
120
+ _, err = wc.Write(msg)
121
+ if err != nil {
122
+ s.Error = err
123
+ log.Printf("Error write Send Message: %v", err)
124
+ return
125
+ }
126
+
127
+ err = wc.Close()
128
+ if err != nil {
129
+ s.Error = err
130
+ log.Printf("Error close Send Message: %v", err)
131
+ return
132
+ }
133
+
134
+ c.Quit()
135
+ fmt.Println("Email sent successfully!")
136
+
137
+ // auth := smtp.PlainAuth("", from, password, smtpHost)
138
+
139
+ // subject := "Email Verification Token"
140
+ // body := fmt.Sprintf("Your verification token is: %06d\nPlease use it before it expires.", token)
141
+
142
+ // msg := []byte("To: " + toEmail + "\r\n" +
143
+ // "Subject: " + subject + "\r\n" +
144
+ // "\r\n" +
145
+ // body + "\r\n")
146
+
147
+ // err := smtp.SendMail(smtpHost+":"+smtpPort, auth, from, []string{toEmail}, msg)
148
+ // if err != nil {
149
+ // s.Error = err
150
+ // log.Printf("Error sending verification email: %v", err)
151
+ // return
152
+ // } else {
153
+ // log.Printf("Successfully sending verification email: %v", err)
154
+ // }
155
  }(accountRepo.Result.Email, token)
156
  // s.Result.Token = 0
157
  }
space/space/space/services/external_authentication_service.go CHANGED
@@ -24,6 +24,16 @@ func (s *GoogleAuthService) Authenticate(isAgree bool) {
24
  return
25
  }
26
  email := payload.Claims["email"]
 
 
 
 
 
 
 
 
 
 
27
  if GoogleAuth.NoRecord {
28
  if !isAgree {
29
  s.Exception.BadRequest = true
@@ -32,12 +42,6 @@ func (s *GoogleAuthService) Authenticate(isAgree bool) {
32
  }
33
  s.Constructor.UUID = uuid.NewV4()
34
  s.Constructor.OauthProvider = "Google"
35
- checkRegisteredEmail := repositories.GetAccountbyEmail(email.(string))
36
- if !checkRegisteredEmail.NoRecord {
37
- s.Exception.DataDuplicate = true
38
- s.Exception.Message = "Account with email" + email.(string) + "already registered!"
39
- return
40
- }
41
 
42
  createAccount := repositories.CreateAccount(models.Account{
43
  UUID: uuid.NewV4(),
 
24
  return
25
  }
26
  email := payload.Claims["email"]
27
+ checkRegisteredEmail := repositories.GetAccountbyEmail(email.(string))
28
+ if !checkRegisteredEmail.NoRecord {
29
+ token, _ := GenerateToken(&checkRegisteredEmail.Result)
30
+ checkRegisteredEmail.Result.Password = "SECRET"
31
+ s.Result = models.AuthenticatedUser{
32
+ Account: checkRegisteredEmail.Result,
33
+ Token: token,
34
+ }
35
+ return
36
+ }
37
  if GoogleAuth.NoRecord {
38
  if !isAgree {
39
  s.Exception.BadRequest = true
 
42
  }
43
  s.Constructor.UUID = uuid.NewV4()
44
  s.Constructor.OauthProvider = "Google"
 
 
 
 
 
 
45
 
46
  createAccount := repositories.CreateAccount(models.Account{
47
  UUID: uuid.NewV4(),
space/space/space/space/services/email_verification_service.go CHANGED
@@ -29,10 +29,7 @@ func (s *EmailVerificationService) Create() {
29
  remainingTime := time.Duration(config.EMAIL_VERIFICATION_DURATION) * time.Hour
30
  dueTime := CalculateDueTime(remainingTime)
31
 
32
- token := uint(rand.IntN(1000000))
33
- for token < 1000000 {
34
- token = uint(rand.IntN(1000000))
35
- }
36
  s.Constructor.UUID = uuid.NewV4()
37
 
38
  repo := repositories.CreateEmailVerification(s.Constructor.UUID, s.Constructor.AccountID, dueTime, token)
 
29
  remainingTime := time.Duration(config.EMAIL_VERIFICATION_DURATION) * time.Hour
30
  dueTime := CalculateDueTime(remainingTime)
31
 
32
+ token := uint(rand.IntN(999999-100000) + 100000)
 
 
 
33
  s.Constructor.UUID = uuid.NewV4()
34
 
35
  repo := repositories.CreateEmailVerification(s.Constructor.UUID, s.Constructor.AccountID, dueTime, token)
space/space/space/space/services/forgot_password_service.go CHANGED
@@ -34,10 +34,7 @@ func (s *ForgotPasswordService) Create(email string) {
34
  remainingTime := time.Duration(config.EMAIL_VERIFICATION_DURATION) * time.Hour
35
  dueTime := CalculateDueTime(remainingTime)
36
 
37
- token := uint(rand.IntN(1000000))
38
- for token < 1000000 {
39
- token = uint(rand.IntN(1000000))
40
- }
41
  s.Constructor.UUID = uuid.NewV4()
42
  s.Constructor.ExpiredAt = dueTime
43
  s.Constructor.AccountID = accountRepo.Result.Id
 
34
  remainingTime := time.Duration(config.EMAIL_VERIFICATION_DURATION) * time.Hour
35
  dueTime := CalculateDueTime(remainingTime)
36
 
37
+ token := uint(rand.IntN(999999-100000) + 100000)
 
 
 
38
  s.Constructor.UUID = uuid.NewV4()
39
  s.Constructor.ExpiredAt = dueTime
40
  s.Constructor.AccountID = accountRepo.Result.Id
space/space/space/space/space/services/external_authentication_service.go CHANGED
@@ -32,17 +32,34 @@ func (s *GoogleAuthService) Authenticate(isAgree bool) {
32
  }
33
  s.Constructor.UUID = uuid.NewV4()
34
  s.Constructor.OauthProvider = "Google"
 
 
 
 
 
 
 
35
  createAccount := repositories.CreateAccount(models.Account{
36
  UUID: uuid.NewV4(),
37
  Email: email.(string),
38
  IsEmailVerified: true,
39
  })
 
40
  s.Constructor.AccountID = createAccount.Result.Id
41
  createGoogleAuth := repositories.CreateExternalAuth(s.Constructor)
42
- GoogleAuth.Result.AccountID = createGoogleAuth.Result.ID
 
 
 
 
 
 
 
 
43
  s.Error = createGoogleAuth.RowsError
44
  s.Error = errors.Join(s.Error, createAccount.RowsError)
45
  }
 
46
  accountData := repositories.GetAccountById(GoogleAuth.Result.AccountID)
47
  token, err_tok := GenerateToken(&accountData.Result)
48
 
 
32
  }
33
  s.Constructor.UUID = uuid.NewV4()
34
  s.Constructor.OauthProvider = "Google"
35
+ checkRegisteredEmail := repositories.GetAccountbyEmail(email.(string))
36
+ if !checkRegisteredEmail.NoRecord {
37
+ s.Exception.DataDuplicate = true
38
+ s.Exception.Message = "Account with email" + email.(string) + "already registered!"
39
+ return
40
+ }
41
+
42
  createAccount := repositories.CreateAccount(models.Account{
43
  UUID: uuid.NewV4(),
44
  Email: email.(string),
45
  IsEmailVerified: true,
46
  })
47
+
48
  s.Constructor.AccountID = createAccount.Result.Id
49
  createGoogleAuth := repositories.CreateExternalAuth(s.Constructor)
50
+
51
+ GoogleAuth.Result.AccountID = createGoogleAuth.Result.AccountID
52
+ userProfile := UserProfileService{}
53
+ userProfile.Constructor.AccountID = GoogleAuth.Result.AccountID
54
+ userProfile.Create()
55
+ if userProfile.Error != nil {
56
+ s.Error = userProfile.Error
57
+ return
58
+ }
59
  s.Error = createGoogleAuth.RowsError
60
  s.Error = errors.Join(s.Error, createAccount.RowsError)
61
  }
62
+
63
  accountData := repositories.GetAccountById(GoogleAuth.Result.AccountID)
64
  token, err_tok := GenerateToken(&accountData.Result)
65
 
space/space/space/space/space/space/controller/academy/academy_controller.go ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package academy
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
+ academy := services.AcademyService{}
12
+ academyController := controller.Controller[any, models.Academy, models.AllAcademyResponse]{
13
+ Service: &academy.Service,
14
+ }
15
+ academyController.Service.Constructor.Slug = c.Param("slug")
16
+ academy.Retrieve()
17
+ academyController.Response(c)
18
+
19
+ }
20
+
21
+ func Create(c *gin.Context) {
22
+ createAcademy := services.CreateAcademyService{}
23
+ academyController := controller.Controller[models.AllAcademyResponse, models.AllAcademyResponse, models.AllAcademyResponse]{
24
+ Service: &createAcademy.Service,
25
+ }
26
+ academyController.RequestJSON(c, func() {
27
+ academyController.Service.Constructor.Academies = academyController.Request.Academies
28
+ createAcademy.Create()
29
+ })
30
+
31
+ }
space/space/space/space/space/space/logs/error_log.txt CHANGED
@@ -0,0 +1,2 @@
 
 
 
1
+ 2025/04/20 10:05:28 Error Log : duplicated key not allowed
2
+ 2025/04/20 10:11:41 Error Log : duplicated key not allowed
space/space/space/space/space/space/models/database_orm_model.go CHANGED
@@ -30,7 +30,7 @@ type AccountDetails struct {
30
  LastEducation *string `json:"last_education"`
31
  MaritalStatus *string `json:"marital_status"`
32
  Avatar *string `json:"avatar"`
33
- PhoneNumber *uint `json:"phone_number"`
34
  }
35
 
36
  type EmailVerification struct {
@@ -85,12 +85,12 @@ type AcademyMaterial struct {
85
  }
86
 
87
  type AcademyContent struct {
88
- ID uint `gorm:"primaryKey" json:"id"`
89
- UUID uint `json:"uuid"`
90
- Title string `json:"title"`
91
- Order uint `json:"order"`
92
- AcademyMaterialID uint `json:"academy_material_id"`
93
- Description string `json:"description"`
94
  }
95
  type OptionCategory struct {
96
  ID uint `gorm:"primaryKey" json:"id"`
 
30
  LastEducation *string `json:"last_education"`
31
  MaritalStatus *string `json:"marital_status"`
32
  Avatar *string `json:"avatar"`
33
+ PhoneNumber *string `json:"phone_number"`
34
  }
35
 
36
  type EmailVerification struct {
 
85
  }
86
 
87
  type AcademyContent struct {
88
+ ID uint `gorm:"primaryKey" json:"id"`
89
+ UUID uuid.UUID `json:"uuid"`
90
+ Title string `json:"title"`
91
+ Order uint `json:"order"`
92
+ AcademyMaterialID uint `json:"academy_material_id"`
93
+ Description string `json:"description"`
94
  }
95
  type OptionCategory struct {
96
  ID uint `gorm:"primaryKey" json:"id"`
space/space/space/space/space/space/repositories/academy_repository.go CHANGED
@@ -13,9 +13,9 @@ func GetAllAcademy() Repository[models.Academy, []models.Academy] {
13
  return *repo
14
  }
15
 
16
- func GetAcademyDataById(academyId uint) Repository[models.Academy, models.Academy] {
17
  repo := Construct[models.Academy, models.Academy](
18
- models.Academy{ID: academyId},
19
  )
20
  repo.Transactions(
21
  WhereGivenConstructor[models.Academy, models.Academy],
@@ -45,3 +45,29 @@ func GetAllAcademyContentsByMaterialID(materialId uint) Repository[models.Academ
45
  )
46
  return *repo
47
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  return *repo
14
  }
15
 
16
+ func GetAcademyDataBySlug(slug string) Repository[models.Academy, models.Academy] {
17
  repo := Construct[models.Academy, models.Academy](
18
+ models.Academy{Slug: slug},
19
  )
20
  repo.Transactions(
21
  WhereGivenConstructor[models.Academy, models.Academy],
 
45
  )
46
  return *repo
47
  }
48
+
49
+ func CreateAcademy(academies models.Academy) Repository[models.Academy, models.Academy] {
50
+ repo := Construct[models.Academy, models.Academy](
51
+ academies,
52
+ )
53
+
54
+ Create(repo)
55
+ return *repo
56
+ }
57
+
58
+ func CreateAcademyMaterial(academyMaterial models.AcademyMaterial) Repository[models.AcademyMaterial, models.AcademyMaterial] {
59
+ repo := Construct[models.AcademyMaterial, models.AcademyMaterial](
60
+ academyMaterial,
61
+ )
62
+
63
+ Create(repo)
64
+ return *repo
65
+ }
66
+
67
+ func CreateAcademyContent(academyContent models.AcademyContent) Repository[models.AcademyContent, models.AcademyContent] {
68
+ repo := Construct[models.AcademyContent, models.AcademyContent](
69
+ academyContent,
70
+ )
71
+ Create(repo)
72
+ return *repo
73
+ }
space/space/space/space/space/space/router/academy_route.go ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package router
2
+
3
+ import (
4
+ AcademyController "api.qobiltu.id/controller/academy"
5
+ "api.qobiltu.id/middleware"
6
+ "github.com/gin-gonic/gin"
7
+ )
8
+
9
+ func AcademyRoute(router *gin.Engine) {
10
+ routerGroup := router.Group("/api/v1/academy")
11
+ {
12
+ routerGroup.GET("/list/:slug", middleware.AuthUser, AcademyController.List)
13
+ routerGroup.GET("/list", middleware.AuthUser, AcademyController.List)
14
+ routerGroup.POST("/create", middleware.AuthUser, AcademyController.Create)
15
+ }
16
+ }
space/space/space/space/space/space/router/router.go CHANGED
@@ -16,7 +16,7 @@ func StartService() {
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)
 
16
  UserRoute(router)
17
  EmailRoute(router)
18
  OptionsRoute(router)
19
+ AcademyRoute(router)
20
  err := router.Run(config.TCP_ADDRESS)
21
  if err != nil {
22
  log.Fatalf("Failed to run server: %v", err)
space/space/space/space/space/space/services/academy_service.go CHANGED
@@ -3,38 +3,102 @@ package services
3
  import (
4
  "api.qobiltu.id/models"
5
  "api.qobiltu.id/repositories"
 
 
6
  )
7
 
8
  type AcademyService struct {
9
  Service[models.Academy, models.AllAcademyResponse]
10
  }
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  func (s *AcademyService) Retrieve() {
13
- if s.Constructor.ID != 0 {
14
- AcademyRepo := repositories.GetAcademyDataById(s.Constructor.ID)
15
  s.Error = AcademyRepo.RowsError
16
  if AcademyRepo.NoRecord {
17
  s.Exception.Message = "Academy not found"
18
  s.Exception.DataNotFound = true
19
  return
20
  }
21
- var ArrMaterials []models.AcademyMaterialResponse
22
- for _, academyMaterial := range repositories.GetAllAcademyMaterialsByAcademyID(s.Constructor.ID).Result {
23
- ArrMaterials = append(ArrMaterials, models.AcademyMaterialResponse{
24
- Materials: academyMaterial,
25
- Contents: repositories.GetAllAcademyContentsByMaterialID(academyMaterial.ID).Result,
26
- })
27
- }
28
  s.Result = models.AllAcademyResponse{
29
  Academies: []models.AcademyResponse{
30
  models.AcademyResponse{
31
  Academy: AcademyRepo.Result,
32
- Materials: ArrMaterials,
33
  },
34
  },
35
  }
36
  } else {
37
- // AcademyRepo := repositories.GetAllAcademy()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
 
39
 
40
  }
 
3
  import (
4
  "api.qobiltu.id/models"
5
  "api.qobiltu.id/repositories"
6
+ "github.com/gosimple/slug"
7
+ uuid "github.com/satori/go.uuid"
8
  )
9
 
10
  type AcademyService struct {
11
  Service[models.Academy, models.AllAcademyResponse]
12
  }
13
 
14
+ type CreateAcademyService struct {
15
+ Service[models.AllAcademyResponse, models.AllAcademyResponse]
16
+ }
17
+
18
+ func castAcademyMaterials(academyId uint) []models.AcademyMaterialResponse {
19
+ var ArrMaterials []models.AcademyMaterialResponse
20
+ for _, academyMaterial := range repositories.GetAllAcademyMaterialsByAcademyID(academyId).Result {
21
+ ArrMaterials = append(ArrMaterials, models.AcademyMaterialResponse{
22
+ Materials: academyMaterial,
23
+ Contents: repositories.GetAllAcademyContentsByMaterialID(academyMaterial.ID).Result,
24
+ })
25
+ }
26
+ return ArrMaterials
27
+ }
28
  func (s *AcademyService) Retrieve() {
29
+ if s.Constructor.Slug != "" {
30
+ AcademyRepo := repositories.GetAcademyDataBySlug(s.Constructor.Slug)
31
  s.Error = AcademyRepo.RowsError
32
  if AcademyRepo.NoRecord {
33
  s.Exception.Message = "Academy not found"
34
  s.Exception.DataNotFound = true
35
  return
36
  }
37
+
 
 
 
 
 
 
38
  s.Result = models.AllAcademyResponse{
39
  Academies: []models.AcademyResponse{
40
  models.AcademyResponse{
41
  Academy: AcademyRepo.Result,
42
+ Materials: castAcademyMaterials(s.Constructor.ID),
43
  },
44
  },
45
  }
46
  } else {
47
+ AcademyRepo := repositories.GetAllAcademy()
48
+ s.Error = AcademyRepo.RowsError
49
+ var ArrAcademy []models.AcademyResponse
50
+ for _, academy := range AcademyRepo.Result {
51
+ ArrAcademy = append(ArrAcademy, models.AcademyResponse{
52
+ Academy: academy,
53
+ Materials: castAcademyMaterials(academy.ID),
54
+ })
55
+ }
56
+ s.Result = models.AllAcademyResponse{
57
+ Academies: ArrAcademy,
58
+ }
59
+ }
60
+
61
+ }
62
+
63
+ func (s *CreateAcademyService) Create() {
64
+ var ArrAcademy []models.AcademyResponse
65
+ for _, academy := range s.Constructor.Academies {
66
+ academy.Academy.UUID = uuid.NewV4()
67
+ if academy.Academy.Slug == "" {
68
+ academy.Academy.Slug = slug.Make(academy.Academy.Title)
69
+ }
70
+
71
+ createdAcademy := repositories.CreateAcademy(academy.Academy)
72
+ if createdAcademy.RowsError != nil {
73
+ s.Error = createdAcademy.RowsError
74
+ return
75
+ }
76
+ for _, material := range academy.Materials {
77
+ material.Materials.AcademyID = createdAcademy.Result.ID
78
+ material.Materials.UUID = uuid.NewV4()
79
+ if material.Materials.Slug == "" {
80
+ material.Materials.Slug = slug.Make(material.Materials.Title)
81
+ }
82
+ createdMaterial := repositories.CreateAcademyMaterial(material.Materials)
83
+ if createdMaterial.RowsError != nil {
84
+ s.Error = createdMaterial.RowsError
85
+ return
86
+ }
87
+ for _, content := range material.Contents {
88
+ content.UUID = uuid.NewV4()
89
+ content.AcademyMaterialID = createdMaterial.Result.ID
90
+ createdContent := repositories.CreateAcademyContent(content)
91
+ if createdContent.RowsError != nil {
92
+ s.Error = createdContent.RowsError
93
+ return
94
+ }
95
+ ArrAcademy = append(ArrAcademy, models.AcademyResponse{
96
+ Academy: createdAcademy.Result,
97
+ Materials: castAcademyMaterials(createdAcademy.Result.ID),
98
+ })
99
+ }
100
+ }
101
  }
102
+ s.Result = models.AllAcademyResponse{Academies: ArrAcademy}
103
 
104
  }
space/space/space/space/space/space/services/email_verification_service.go CHANGED
@@ -29,7 +29,10 @@ func (s *EmailVerificationService) Create() {
29
  remainingTime := time.Duration(config.EMAIL_VERIFICATION_DURATION) * time.Hour
30
  dueTime := CalculateDueTime(remainingTime)
31
 
32
- token := uint(rand.IntN(100000))
 
 
 
33
  s.Constructor.UUID = uuid.NewV4()
34
 
35
  repo := repositories.CreateEmailVerification(s.Constructor.UUID, s.Constructor.AccountID, dueTime, token)
@@ -83,7 +86,7 @@ func (s *EmailVerificationService) Validate() {
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
  }
 
29
  remainingTime := time.Duration(config.EMAIL_VERIFICATION_DURATION) * time.Hour
30
  dueTime := CalculateDueTime(remainingTime)
31
 
32
+ token := uint(rand.IntN(1000000))
33
+ for token < 1000000 {
34
+ token = uint(rand.IntN(1000000))
35
+ }
36
  s.Constructor.UUID = uuid.NewV4()
37
 
38
  repo := repositories.CreateEmailVerification(s.Constructor.UUID, s.Constructor.AccountID, dueTime, token)
 
86
  }
87
  account := repositories.GetAccountById(repo.Result.AccountID)
88
  account.Result.IsEmailVerified = true
89
+
90
  repositories.UpdateAccount(account.Result)
91
  s.Result = repo.Result
92
  }
space/space/space/space/space/space/services/forgot_password_service.go CHANGED
@@ -34,7 +34,10 @@ func (s *ForgotPasswordService) Create(email string) {
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
 
34
  remainingTime := time.Duration(config.EMAIL_VERIFICATION_DURATION) * time.Hour
35
  dueTime := CalculateDueTime(remainingTime)
36
 
37
+ token := uint(rand.IntN(1000000))
38
+ for token < 1000000 {
39
+ token = uint(rand.IntN(1000000))
40
+ }
41
  s.Constructor.UUID = uuid.NewV4()
42
  s.Constructor.ExpiredAt = dueTime
43
  s.Constructor.AccountID = accountRepo.Result.Id
space/space/space/space/space/space/space/logs/error_log.txt CHANGED
@@ -1 +0,0 @@
1
-
 
 
space/space/space/space/space/space/space/models/response_model.go CHANGED
@@ -31,12 +31,15 @@ type UserProfileResponse struct {
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
  }
 
31
  Details AccountDetails `json:"details"`
32
  }
33
 
34
+ type AcademyMaterialResponse struct {
35
+ Materials AcademyMaterial
36
+ Contents []AcademyContent
37
+ }
38
+ type AcademyResponse struct {
39
+ Academy Academy `json:"academy"`
40
+ Materials []AcademyMaterialResponse `json:"academy_materials"`
41
  }
42
 
43
+ type AllAcademyResponse struct {
44
+ Academies []AcademyResponse `json:"academy_dasar"`
45
  }
space/space/space/space/space/space/space/repositories/academy_repository.go ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package repositories
2
+
3
+ import "api.qobiltu.id/models"
4
+
5
+ func GetAllAcademy() Repository[models.Academy, []models.Academy] {
6
+ repo := Construct[models.Academy, []models.Academy](
7
+ models.Academy{},
8
+ )
9
+ repo.Transactions(
10
+ WhereGivenConstructor[models.Academy, []models.Academy],
11
+ Find[models.Academy, []models.Academy],
12
+ )
13
+ return *repo
14
+ }
15
+
16
+ func GetAcademyDataById(academyId uint) Repository[models.Academy, models.Academy] {
17
+ repo := Construct[models.Academy, models.Academy](
18
+ models.Academy{ID: academyId},
19
+ )
20
+ repo.Transactions(
21
+ WhereGivenConstructor[models.Academy, models.Academy],
22
+ Find[models.Academy, models.Academy],
23
+ )
24
+ return *repo
25
+ }
26
+
27
+ func GetAllAcademyMaterialsByAcademyID(acaddemyId uint) Repository[models.AcademyMaterial, []models.AcademyMaterial] {
28
+ repo := Construct[models.AcademyMaterial, []models.AcademyMaterial](
29
+ models.AcademyMaterial{AcademyID: acaddemyId},
30
+ )
31
+ repo.Transactions(
32
+ WhereGivenConstructor[models.AcademyMaterial, []models.AcademyMaterial],
33
+ Find[models.AcademyMaterial, []models.AcademyMaterial],
34
+ )
35
+ return *repo
36
+ }
37
+
38
+ func GetAllAcademyContentsByMaterialID(materialId uint) Repository[models.AcademyContent, []models.AcademyContent] {
39
+ repo := Construct[models.AcademyContent, []models.AcademyContent](
40
+ models.AcademyContent{AcademyMaterialID: materialId},
41
+ )
42
+ repo.Transactions(
43
+ WhereGivenConstructor[models.AcademyContent, []models.AcademyContent],
44
+ Find[models.AcademyContent, []models.AcademyContent],
45
+ )
46
+ return *repo
47
+ }
space/space/space/space/space/space/space/services/academy_service.go ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package services
2
+
3
+ import (
4
+ "api.qobiltu.id/models"
5
+ "api.qobiltu.id/repositories"
6
+ )
7
+
8
+ type AcademyService struct {
9
+ Service[models.Academy, models.AllAcademyResponse]
10
+ }
11
+
12
+ func (s *AcademyService) Retrieve() {
13
+ if s.Constructor.ID != 0 {
14
+ AcademyRepo := repositories.GetAcademyDataById(s.Constructor.ID)
15
+ s.Error = AcademyRepo.RowsError
16
+ if AcademyRepo.NoRecord {
17
+ s.Exception.Message = "Academy not found"
18
+ s.Exception.DataNotFound = true
19
+ return
20
+ }
21
+ var ArrMaterials []models.AcademyMaterialResponse
22
+ for _, academyMaterial := range repositories.GetAllAcademyMaterialsByAcademyID(s.Constructor.ID).Result {
23
+ ArrMaterials = append(ArrMaterials, models.AcademyMaterialResponse{
24
+ Materials: academyMaterial,
25
+ Contents: repositories.GetAllAcademyContentsByMaterialID(academyMaterial.ID).Result,
26
+ })
27
+ }
28
+ s.Result = models.AllAcademyResponse{
29
+ Academies: []models.AcademyResponse{
30
+ models.AcademyResponse{
31
+ Academy: AcademyRepo.Result,
32
+ Materials: ArrMaterials,
33
+ },
34
+ },
35
+ }
36
+ } else {
37
+ // AcademyRepo := repositories.GetAllAcademy()
38
+ }
39
+
40
+ }
space/space/space/space/space/space/space/services/external_authentication_service.go CHANGED
@@ -33,6 +33,7 @@ func (s *GoogleAuthService) Authenticate(isAgree bool) {
33
  s.Constructor.UUID = uuid.NewV4()
34
  s.Constructor.OauthProvider = "Google"
35
  createAccount := repositories.CreateAccount(models.Account{
 
36
  Email: email.(string),
37
  IsEmailVerified: true,
38
  })
 
33
  s.Constructor.UUID = uuid.NewV4()
34
  s.Constructor.OauthProvider = "Google"
35
  createAccount := repositories.CreateAccount(models.Account{
36
+ UUID: uuid.NewV4(),
37
  Email: email.(string),
38
  IsEmailVerified: true,
39
  })
space/space/space/space/space/space/space/services/forgot_password_service.go CHANGED
@@ -71,13 +71,6 @@ func (s *ForgotPasswordService) Create(email string) {
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
@@ -91,13 +84,24 @@ func (s *ForgotPasswordService) Validate(newPassword *string) {
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 {
102
  s.Error = changePassword.RowsError
103
  s.Exception.QueryError = true
 
71
  }
72
 
73
  func (s *ForgotPasswordService) Validate(newPassword *string) {
 
 
 
 
 
 
 
74
 
75
  fgPasswordRepo := repositories.GetForgotPasswordByToken(s.Constructor.Token)
76
  s.Error = fgPasswordRepo.RowsError
 
84
  s.Exception.Message = "Token has expired!"
85
  return
86
  }
87
+
88
+ accountRepo := repositories.GetAccountById(fgPasswordRepo.Result.AccountID)
89
+ if accountRepo.NoRecord {
90
+ s.Error = accountRepo.RowsError
91
+ s.Exception.DataNotFound = true
92
+ s.Exception.Message = "There is no account data with given credentials!"
93
+ return
94
+ }
95
  s.Result = fgPasswordRepo.Result
96
  if newPassword == nil {
97
  return
98
  }
99
+ // fmt.Println("Previous Account", accountRepo.Result)
100
+ // fmt.Println("New password", *newPassword)
101
  hashed_password, _ := HashPassword(*newPassword)
102
  accountRepo.Result.Password = hashed_password
103
  changePassword := repositories.UpdateAccount(accountRepo.Result)
104
+ // fmt.Println("New Account", changePassword.Result)
105
  if changePassword.RowsError != nil {
106
  s.Error = changePassword.RowsError
107
  s.Exception.QueryError = true
space/space/space/space/space/space/space/space/space/go.mod CHANGED
@@ -5,9 +5,11 @@ go 1.24.0
5
  require (
6
  github.com/gin-gonic/gin v1.10.0
7
  github.com/golang-jwt/jwt/v5 v5.2.1
 
8
  github.com/joho/godotenv v1.5.1
9
  github.com/satori/go.uuid v1.2.0
10
  golang.org/x/crypto v0.36.0
 
11
  gorm.io/driver/postgres v1.5.11
12
  gorm.io/gorm v1.25.12
13
  )
@@ -31,7 +33,6 @@ require (
31
  github.com/google/s2a-go v0.1.9 // indirect
32
  github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
33
  github.com/googleapis/gax-go/v2 v2.14.1 // indirect
34
- github.com/gosimple/slug v1.15.0 // indirect
35
  github.com/gosimple/unidecode v1.0.1 // indirect
36
  github.com/jackc/pgpassfile v1.0.0 // indirect
37
  github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
@@ -41,13 +42,11 @@ require (
41
  github.com/jinzhu/now v1.1.5 // indirect
42
  github.com/json-iterator/go v1.1.12 // indirect
43
  github.com/klauspost/cpuid/v2 v2.2.10 // indirect
44
- github.com/kr/text v0.2.0 // indirect
45
  github.com/leodido/go-urn v1.4.0 // indirect
46
  github.com/mattn/go-isatty v0.0.20 // indirect
47
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
48
  github.com/modern-go/reflect2 v1.0.2 // indirect
49
  github.com/pelletier/go-toml/v2 v2.2.3 // indirect
50
- github.com/rogpeppe/go-internal v1.13.1 // indirect
51
  github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
52
  github.com/ugorji/go/codec v1.2.12 // indirect
53
  go.opentelemetry.io/auto/sdk v1.1.0 // indirect
@@ -56,13 +55,11 @@ require (
56
  go.opentelemetry.io/otel/metric v1.34.0 // indirect
57
  go.opentelemetry.io/otel/trace v1.34.0 // indirect
58
  golang.org/x/arch v0.15.0 // indirect
59
- golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
60
  golang.org/x/net v0.37.0 // indirect
61
  golang.org/x/oauth2 v0.28.0 // indirect
62
  golang.org/x/sync v0.12.0 // indirect
63
  golang.org/x/sys v0.31.0 // indirect
64
  golang.org/x/text v0.23.0 // indirect
65
- google.golang.org/api v0.228.0 // indirect
66
  google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
67
  google.golang.org/grpc v1.71.0 // indirect
68
  google.golang.org/protobuf v1.36.6 // indirect
 
5
  require (
6
  github.com/gin-gonic/gin v1.10.0
7
  github.com/golang-jwt/jwt/v5 v5.2.1
8
+ github.com/gosimple/slug v1.15.0
9
  github.com/joho/godotenv v1.5.1
10
  github.com/satori/go.uuid v1.2.0
11
  golang.org/x/crypto v0.36.0
12
+ google.golang.org/api v0.228.0
13
  gorm.io/driver/postgres v1.5.11
14
  gorm.io/gorm v1.25.12
15
  )
 
33
  github.com/google/s2a-go v0.1.9 // indirect
34
  github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
35
  github.com/googleapis/gax-go/v2 v2.14.1 // indirect
 
36
  github.com/gosimple/unidecode v1.0.1 // indirect
37
  github.com/jackc/pgpassfile v1.0.0 // indirect
38
  github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
 
42
  github.com/jinzhu/now v1.1.5 // indirect
43
  github.com/json-iterator/go v1.1.12 // indirect
44
  github.com/klauspost/cpuid/v2 v2.2.10 // indirect
 
45
  github.com/leodido/go-urn v1.4.0 // indirect
46
  github.com/mattn/go-isatty v0.0.20 // indirect
47
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
48
  github.com/modern-go/reflect2 v1.0.2 // indirect
49
  github.com/pelletier/go-toml/v2 v2.2.3 // indirect
 
50
  github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
51
  github.com/ugorji/go/codec v1.2.12 // indirect
52
  go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 
55
  go.opentelemetry.io/otel/metric v1.34.0 // indirect
56
  go.opentelemetry.io/otel/trace v1.34.0 // indirect
57
  golang.org/x/arch v0.15.0 // indirect
 
58
  golang.org/x/net v0.37.0 // indirect
59
  golang.org/x/oauth2 v0.28.0 // indirect
60
  golang.org/x/sync v0.12.0 // indirect
61
  golang.org/x/sys v0.31.0 // indirect
62
  golang.org/x/text v0.23.0 // indirect
 
63
  google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
64
  google.golang.org/grpc v1.71.0 // indirect
65
  google.golang.org/protobuf v1.36.6 // indirect
space/space/space/space/space/space/space/space/space/go.sum CHANGED
@@ -12,7 +12,6 @@ github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFos
12
  github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
13
  github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
14
  github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
15
- github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
16
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
17
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
18
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -41,11 +40,15 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
41
  github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
42
  github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
43
  github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
44
- github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
45
- github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 
 
46
  github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
47
  github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
48
  github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
 
 
49
  github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
50
  github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
51
  github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
@@ -74,8 +77,8 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
74
  github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
75
  github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
76
  github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
77
- github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
78
- github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
79
  github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
80
  github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
81
  github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
@@ -91,8 +94,7 @@ github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNH
91
  github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
92
  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
93
  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
94
- github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
95
- github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
96
  github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
97
  github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
98
  github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
@@ -114,20 +116,24 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
114
  github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
115
  go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
116
  go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
 
 
117
  go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
118
  go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
119
  go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
120
  go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
121
  go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
122
  go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
 
 
 
 
123
  go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
124
  go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
125
  golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw=
126
  golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
127
  golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
128
  golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
129
- golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
130
- golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
131
  golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
132
  golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
133
  golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
@@ -139,16 +145,14 @@ golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
139
  golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
140
  golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
141
  golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
142
- golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
143
- golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
144
  google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs=
145
  google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4=
146
  google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c=
147
  google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
148
  google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
149
  google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
150
- google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
151
- google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
152
  google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
153
  google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
154
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 
12
  github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
13
  github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
14
  github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
 
15
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
16
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
17
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 
40
  github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
41
  github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
42
  github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
43
+ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
44
+ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
45
+ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
46
+ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
47
  github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
48
  github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
49
  github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
50
+ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
51
+ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
52
  github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
53
  github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
54
  github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
 
77
  github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
78
  github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
79
  github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
80
+ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
81
+ github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
82
  github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
83
  github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
84
  github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
 
94
  github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
95
  github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
96
  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
97
+ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
 
98
  github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
99
  github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
100
  github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 
116
  github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
117
  go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
118
  go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
119
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
120
+ go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
121
  go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
122
  go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
123
  go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
124
  go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
125
  go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
126
  go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
127
+ go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
128
+ go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
129
+ go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
130
+ go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
131
  go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
132
  go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
133
  golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw=
134
  golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
135
  golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
136
  golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
 
 
137
  golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
138
  golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
139
  golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
 
145
  golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
146
  golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
147
  golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
148
+ golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
149
+ golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
150
  google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs=
151
  google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4=
152
  google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c=
153
  google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
154
  google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
155
  google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
 
 
156
  google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
157
  google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
158
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
space/space/space/space/space/space/space/space/space/space/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
+ }
space/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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"`
42
+ }
space/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/space/space/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/space/space/space/space/space/space/space/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/space/space/space/space/space/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/space/space/space/space/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/space/space/space/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/space/space/space/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/space/space/space/space/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"
@@ -71,8 +72,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 {
@@ -80,7 +83,8 @@ func (s *UserProfileService) Update() {
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 {
@@ -92,4 +96,5 @@ func (s *UserProfileService) Update() {
92
  Account: repositories.GetAccountById(s.Constructor.AccountID).Result,
93
  Details: userProfile.Result,
94
  }
 
95
  }
 
2
 
3
  import (
4
  "regexp"
5
+ "strconv"
6
  "strings"
7
 
8
  "api.qobiltu.id/models"
 
72
  }
73
 
74
  func (s *UserProfileService) Update() {
75
+ if s.Constructor.PhoneNumber != nil {
76
+ phoneNumber := *s.Constructor.PhoneNumber
77
+ *s.Constructor.PhoneNumber = SanitizePhoneNumber(phoneNumber)
78
+ }
79
  usersCount := repositories.GetAllAccount().RowsCount
80
  var initialName string
81
  if *s.Constructor.Gender {
 
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 {
 
96
  Account: repositories.GetAccountById(s.Constructor.AccountID).Result,
97
  Details: userProfile.Result,
98
  }
99
+ s.Result.Account.Password = "SECRET"
100
  }
space/space/space/space/space/space/space/space/space/space/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/space/space/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/space/space/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/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: