lifedebugger commited on
Commit
897bab5
·
1 Parent(s): ad00352

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/controller.go +1 -1
  2. space/Dockerfile +3 -0
  3. space/services/region_service.go +10 -8
  4. space/space/services/region_service.go +8 -10
  5. space/space/space/README.md +5 -1
  6. space/space/space/space/controller/user/user_profile_controller.go +1 -1
  7. space/space/space/space/controller/user/user_update_profile_controller.go +2 -4
  8. space/space/space/space/logs/error_log.txt +1 -0
  9. space/space/space/space/middleware/authentication_middleware.go +0 -3
  10. space/space/space/space/models/response_model.go +5 -0
  11. space/space/space/space/repositories/account_repository.go +0 -4
  12. space/space/space/space/repositories/forgot_password_repository.go +22 -0
  13. space/space/space/space/router/router.go +8 -1
  14. space/space/space/space/services/external_authentication_service.go +4 -5
  15. space/space/space/space/services/user_profile_service.go +50 -6
  16. space/space/space/space/space/.gitignore +4 -2
  17. space/space/space/space/space/config/config.go +10 -0
  18. space/space/space/space/space/config/database_connection_config.go +4 -0
  19. space/space/space/space/space/controller/auth/auth_external_controller.go +20 -0
  20. space/space/space/space/space/controller/auth/auth_forgot_password_controller.go +1 -0
  21. space/space/space/space/space/controller/email/email_create_verification_controller.go +21 -0
  22. space/space/space/space/space/controller/email/email_validate_controller.go +24 -0
  23. space/space/space/space/space/controller/options/option_category_controller.go +19 -0
  24. space/space/space/space/space/controller/options/option_value_controller.go +19 -0
  25. space/space/space/space/space/controller/region/city/city_list_controller.go +21 -0
  26. space/space/space/space/space/controller/region/city/city_seeds_controller.go +17 -0
  27. space/space/space/space/space/controller/region/province/province_list_controller.go +17 -0
  28. space/space/space/space/space/controller/region/province/province_seeds_controller.go +17 -0
  29. space/space/space/space/space/go.mod +23 -2
  30. space/space/space/space/space/go.sum +46 -0
  31. space/space/space/space/space/logs/error_log.txt +0 -9
  32. space/space/space/space/space/middleware/authentication_middleware.go +3 -3
  33. space/space/space/space/space/models/database_orm_model.go +33 -5
  34. space/space/space/space/space/models/request_model.go +17 -4
  35. space/space/space/space/space/models/response_model.go +7 -0
  36. space/space/space/space/space/repositories/account_repository.go +0 -1
  37. space/space/space/space/space/repositories/email_verification_repository.go +15 -1
  38. space/space/space/space/space/repositories/external_auth_repository.go +37 -0
  39. space/space/space/space/space/repositories/option_repository.go +43 -0
  40. space/space/space/space/space/repositories/region_repository.go +47 -0
  41. space/space/space/space/space/router/auth_route.go +1 -0
  42. space/space/space/space/space/router/email_route.go +3 -3
  43. space/space/space/space/space/router/options_route.go +20 -0
  44. space/space/space/space/space/router/router.go +1 -0
  45. space/space/space/space/space/services/authentication_service.go +1 -4
  46. space/space/space/space/space/services/email_verification_service.go +36 -1
  47. space/space/space/space/space/services/external_authentication_service.go +55 -0
  48. space/space/space/space/space/services/option_service.go +70 -0
  49. space/space/space/space/space/services/region_service.go +90 -0
  50. space/space/space/space/space/space/controller/email/email_create_verification.go +6 -7
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/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/services/region_service.go CHANGED
@@ -4,6 +4,8 @@ import (
4
  "encoding/json"
5
  "log"
6
  "os"
 
 
7
 
8
  "api.qobiltu.id/models"
9
  "api.qobiltu.id/repositories"
@@ -18,10 +20,10 @@ type CityService struct {
18
  }
19
 
20
  func seedCity() ([]models.RegionCity, error) {
21
- log.Println("Seed City..")
22
- path := "utils/seeds/city.json"
23
-
24
- file, err := os.Open(path)
25
  if err != nil {
26
  return nil, err
27
  }
@@ -34,10 +36,10 @@ func seedCity() ([]models.RegionCity, error) {
34
  }
35
 
36
  func seedProvince() ([]models.RegionProvince, error) {
37
- log.Println("Seed Province..")
38
- path := "utils/seeds/province.json"
39
-
40
- file, err := os.Open(path)
41
  if err != nil {
42
  return nil, err
43
  }
 
4
  "encoding/json"
5
  "log"
6
  "os"
7
+ "path/filepath"
8
+ "runtime"
9
 
10
  "api.qobiltu.id/models"
11
  "api.qobiltu.id/repositories"
 
20
  }
21
 
22
  func seedCity() ([]models.RegionCity, error) {
23
+ log.Println("Seed City")
24
+ _, b, _, _ := runtime.Caller(0)
25
+ basePath := filepath.Dir(b)
26
+ file, err := os.Open(filepath.Join(basePath, "..", "utils", "seeds", "city.json"))
27
  if err != nil {
28
  return nil, err
29
  }
 
36
  }
37
 
38
  func seedProvince() ([]models.RegionProvince, error) {
39
+ log.Println("Seed City")
40
+ _, b, _, _ := runtime.Caller(0)
41
+ basePath := filepath.Dir(b)
42
+ file, err := os.Open(filepath.Join(basePath, "..", "utils", "seeds", "province.json"))
43
  if err != nil {
44
  return nil, err
45
  }
space/space/services/region_service.go CHANGED
@@ -4,8 +4,6 @@ import (
4
  "encoding/json"
5
  "log"
6
  "os"
7
- "path/filepath"
8
- "runtime"
9
 
10
  "api.qobiltu.id/models"
11
  "api.qobiltu.id/repositories"
@@ -20,10 +18,10 @@ type CityService struct {
20
  }
21
 
22
  func seedCity() ([]models.RegionCity, error) {
23
- log.Println("Seed City")
24
- _, b, _, _ := runtime.Caller(0)
25
- basePath := filepath.Dir(b)
26
- file, err := os.Open(filepath.Join(basePath, "..", "utils", "seeds", "city.json"))
27
  if err != nil {
28
  return nil, err
29
  }
@@ -36,10 +34,10 @@ func seedCity() ([]models.RegionCity, error) {
36
  }
37
 
38
  func seedProvince() ([]models.RegionProvince, error) {
39
- log.Println("Seed City")
40
- _, b, _, _ := runtime.Caller(0)
41
- basePath := filepath.Dir(b)
42
- file, err := os.Open(filepath.Join(basePath, "..", "utils", "seeds", "province.json"))
43
  if err != nil {
44
  return nil, err
45
  }
 
4
  "encoding/json"
5
  "log"
6
  "os"
 
 
7
 
8
  "api.qobiltu.id/models"
9
  "api.qobiltu.id/repositories"
 
18
  }
19
 
20
  func seedCity() ([]models.RegionCity, error) {
21
+ log.Println("Seed City..")
22
+ path := "utils/seeds/city.json"
23
+
24
+ file, err := os.Open(path)
25
  if err != nil {
26
  return nil, err
27
  }
 
34
  }
35
 
36
  func seedProvince() ([]models.RegionProvince, error) {
37
+ log.Println("Seed Province..")
38
+ path := "utils/seeds/province.json"
39
+
40
+ file, err := os.Open(path)
41
  if err != nil {
42
  return nil, err
43
  }
space/space/space/README.md CHANGED
@@ -84,4 +84,8 @@ The API uses the `errors` package to handle errors. You can set the `ERROR_PATH`
84
 
85
  ### View Log container
86
  > docker logs --tail=50 -f api-qobiltu
87
- > docker logs postgres-db
 
 
 
 
 
84
 
85
  ### View Log container
86
  > docker logs --tail=50 -f api-qobiltu
87
+ > docker logs postgres-db
88
+
89
+ ### Menghapus Resource docker yang tidak dipakai
90
+ > docker system prune
91
+ > docker system prune -a --volumes
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/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/logs/error_log.txt CHANGED
@@ -0,0 +1 @@
 
 
1
+
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/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/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/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/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/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/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/.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/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/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/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/controller/auth/auth_forgot_password_controller.go ADDED
@@ -0,0 +1 @@
 
 
1
+ package auth
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/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/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/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/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/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/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
+ }
space/space/space/space/space/controller/region/province/province_seeds_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 Seeds(c *gin.Context) {
11
+ province := services.ProvinceService{}
12
+ ProvinceController := controller.Controller[any, models.RegionProvince, []models.RegionProvince]{
13
+ Service: &province.Service,
14
+ }
15
+ province.Create()
16
+ ProvinceController.Response(c)
17
+ }
space/space/space/space/space/go.mod CHANGED
@@ -13,15 +13,26 @@ require (
13
  )
14
 
15
  require (
 
 
 
16
  github.com/bytedance/sonic v1.13.1 // indirect
17
  github.com/bytedance/sonic/loader v0.2.4 // indirect
18
  github.com/cloudwego/base64x v0.1.5 // indirect
 
19
  github.com/gabriel-vasile/mimetype v1.4.8 // indirect
20
  github.com/gin-contrib/sse v1.0.0 // indirect
 
 
21
  github.com/go-playground/locales v0.14.1 // indirect
22
  github.com/go-playground/universal-translator v0.18.1 // indirect
23
  github.com/go-playground/validator/v10 v10.25.0 // indirect
24
  github.com/goccy/go-json v0.10.5 // indirect
 
 
 
 
 
25
  github.com/jackc/pgpassfile v1.0.0 // indirect
26
  github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
27
  github.com/jackc/pgx/v5 v5.7.2 // indirect
@@ -36,14 +47,24 @@ require (
36
  github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
37
  github.com/modern-go/reflect2 v1.0.2 // indirect
38
  github.com/pelletier/go-toml/v2 v2.2.3 // indirect
39
- github.com/rogpeppe/go-internal v1.11.0 // indirect
40
  github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
41
  github.com/ugorji/go/codec v1.2.12 // indirect
 
 
 
 
 
42
  golang.org/x/arch v0.15.0 // indirect
 
43
  golang.org/x/net v0.37.0 // indirect
 
44
  golang.org/x/sync v0.12.0 // indirect
45
  golang.org/x/sys v0.31.0 // indirect
46
  golang.org/x/text v0.23.0 // indirect
47
- google.golang.org/protobuf v1.36.5 // indirect
 
 
 
48
  gopkg.in/yaml.v3 v3.0.1 // indirect
49
  )
 
13
  )
14
 
15
  require (
16
+ cloud.google.com/go/auth v0.15.0 // indirect
17
+ cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
18
+ cloud.google.com/go/compute/metadata v0.6.0 // indirect
19
  github.com/bytedance/sonic v1.13.1 // indirect
20
  github.com/bytedance/sonic/loader v0.2.4 // indirect
21
  github.com/cloudwego/base64x v0.1.5 // indirect
22
+ github.com/felixge/httpsnoop v1.0.4 // indirect
23
  github.com/gabriel-vasile/mimetype v1.4.8 // indirect
24
  github.com/gin-contrib/sse v1.0.0 // indirect
25
+ github.com/go-logr/logr v1.4.2 // indirect
26
+ github.com/go-logr/stdr v1.2.2 // indirect
27
  github.com/go-playground/locales v0.14.1 // indirect
28
  github.com/go-playground/universal-translator v0.18.1 // indirect
29
  github.com/go-playground/validator/v10 v10.25.0 // indirect
30
  github.com/goccy/go-json v0.10.5 // indirect
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
38
  github.com/jackc/pgx/v5 v5.7.2 // 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
54
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
55
+ go.opentelemetry.io/otel v1.34.0 // indirect
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
69
  gopkg.in/yaml.v3 v3.0.1 // indirect
70
  )
space/space/space/space/space/go.sum CHANGED
@@ -1,3 +1,9 @@
 
 
 
 
 
 
1
  github.com/bytedance/sonic v1.13.1 h1:Jyd5CIvdFnkOWuKXr+wm4Nyk2h0yAFsr8ucJgEasO3g=
2
  github.com/bytedance/sonic v1.13.1/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
3
  github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
@@ -10,12 +16,19 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
10
  github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
11
  github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
12
  github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 
 
13
  github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
14
  github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
15
  github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
16
  github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
17
  github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
18
  github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
 
 
 
 
 
19
  github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
20
  github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
21
  github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -31,6 +44,16 @@ github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVI
31
  github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
32
  github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
33
  github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 
 
 
 
 
 
 
 
 
 
34
  github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
35
  github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
36
  github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
@@ -70,6 +93,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
70
  github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
71
  github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
72
  github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
 
73
  github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
74
  github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
75
  github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -88,12 +112,26 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS
88
  github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
89
  github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
90
  github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 
 
 
 
 
 
 
 
 
 
91
  golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw=
92
  golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
93
  golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
94
  golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
 
 
95
  golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
96
  golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
 
 
97
  golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
98
  golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
99
  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -103,8 +141,16 @@ golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
103
  golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
104
  golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
105
  golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 
 
 
 
 
 
106
  google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
107
  google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 
 
108
  gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
109
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
110
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 
1
+ cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps=
2
+ cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8=
3
+ cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
4
+ cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
5
+ cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
6
+ cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
7
  github.com/bytedance/sonic v1.13.1 h1:Jyd5CIvdFnkOWuKXr+wm4Nyk2h0yAFsr8ucJgEasO3g=
8
  github.com/bytedance/sonic v1.13.1/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
9
  github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
 
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=
19
+ github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
20
+ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
21
  github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
22
  github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
23
  github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
24
  github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
25
  github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
26
  github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
27
+ github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
28
+ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
29
+ github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
30
+ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
31
+ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
32
  github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
33
  github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
34
  github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
 
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=
52
+ github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
53
+ github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo=
54
+ github.com/gosimple/slug v1.15.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
55
+ github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
56
+ github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
57
  github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
58
  github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
59
  github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
 
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=
99
  github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 
112
  github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
113
  github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
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=
134
+ golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
135
  golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
136
  golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
137
  golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 
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=
155
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
156
  gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
space/space/space/space/space/logs/error_log.txt CHANGED
@@ -1,9 +0,0 @@
1
- 2025/03/23 11:04:52 Error Log : ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification (SQLSTATE 42P10)
2
- 2025/03/23 11:06:58 Error Log : ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification (SQLSTATE 42P10)
3
- 2025/03/23 11:24:49 Error Log : WHERE conditions required
4
- 2025/03/23 11:58:50 Error Log : WHERE conditions required
5
- 2025/03/23 12:01:28 Error Log : WHERE conditions required
6
- 2025/03/24 19:52:15 Error Log : ERROR: nama tabel « account_details » ditentukan lebih dari satu kali (SQLSTATE 42712)
7
- 2025/03/24 19:53:48 Error Log : ERROR: nama tabel « account_details » ditentukan lebih dari satu kali (SQLSTATE 42712)
8
- 2025/03/24 19:54:14 Error Log : WHERE conditions required
9
- 2025/03/24 19:55:31 Error Log : ERROR: nama tabel « account_details » ditentukan lebih dari satu kali (SQLSTATE 42712)
 
 
 
 
 
 
 
 
 
 
space/space/space/space/space/middleware/authentication_middleware.go CHANGED
@@ -3,6 +3,8 @@
3
  package middleware
4
 
5
  import (
 
 
6
  "api.qobiltu.id/models"
7
  "api.qobiltu.id/services"
8
  "api.qobiltu.id/utils"
@@ -13,11 +15,9 @@ func AuthUser(c *gin.Context) {
13
  var currAccData models.AccountData
14
  if c.Request.Header["Authorization"] != nil {
15
  token := c.Request.Header["Authorization"]
16
- // fmt.Println("Authorization :", token)
17
 
18
  currAccData.UserID, currAccData.VerifyStatus, currAccData.ErrVerif = services.VerifyToken(token[0])
19
- // fmt.Println("Verify Status :", currAccData.VerifyStatus)
20
- // fmt.Println("Verify UserID :", currAccData.UserID)
21
 
22
  if currAccData.VerifyStatus == "invalid-token" || currAccData.VerifyStatus == "expired" {
23
  currAccData.UserID = 0
 
3
  package middleware
4
 
5
  import (
6
+ "fmt"
7
+
8
  "api.qobiltu.id/models"
9
  "api.qobiltu.id/services"
10
  "api.qobiltu.id/utils"
 
15
  var currAccData models.AccountData
16
  if c.Request.Header["Authorization"] != nil {
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
space/space/space/space/space/models/database_orm_model.go CHANGED
@@ -28,7 +28,7 @@ type AccountDetails struct {
28
  LastJob *string `json:"last_job"`
29
  Gender *bool `json:"gender"`
30
  LastEducation *string `json:"last_education"`
31
- MaritalStatus *bool `json:"marital_status"`
32
  Avatar *string `json:"avatar"`
33
  PhoneNumber *uint `json:"phone_number"`
34
  }
@@ -44,10 +44,11 @@ type EmailVerification struct {
44
  }
45
 
46
  type ExternalAuth struct {
47
- ID uint `gorm:"primaryKey" json:"id"`
48
- OauthID string `json:"oauth_id"`
49
- AccountID uint `json:"account_id"`
50
- OauthProvider string `json:"oauth_provider"`
 
51
  }
52
 
53
  type FCM struct {
@@ -91,7 +92,17 @@ type AcademyContent struct {
91
  AcademyMaterialID uint `json:"academy_material_id"`
92
  Description string `json:"description"`
93
  }
 
 
 
 
 
94
 
 
 
 
 
 
95
  type AcademyMaterialProgress struct {
96
  ID uint `gorm:"primaryKey" json:"id"`
97
  UUID uuid.UUID `gorm:"type:uuid" json:"uuid"`
@@ -107,6 +118,21 @@ type AcademyContentProgress struct {
107
  AcademyID uint `json:"academy_id"`
108
  }
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  // Gorm table name settings
111
  func (Account) TableName() string { return "account" }
112
  func (AccountDetails) TableName() string { return "account_details" }
@@ -119,3 +145,5 @@ func (AcademyMaterial) TableName() string { return "academy_materials" }
119
  func (AcademyContent) TableName() string { return "academy_contents" }
120
  func (AcademyMaterialProgress) TableName() string { return "academy_materials_progress" }
121
  func (AcademyContentProgress) TableName() string { return "academy_contents_progress" }
 
 
 
28
  LastJob *string `json:"last_job"`
29
  Gender *bool `json:"gender"`
30
  LastEducation *string `json:"last_education"`
31
+ MaritalStatus *string `json:"marital_status"`
32
  Avatar *string `json:"avatar"`
33
  PhoneNumber *uint `json:"phone_number"`
34
  }
 
44
  }
45
 
46
  type ExternalAuth struct {
47
+ ID uint `gorm:"primaryKey" json:"id"`
48
+ UUID uuid.UUID `gorm:"type:uuid" json:"uuid" `
49
+ OauthID string `json:"oauth_id"`
50
+ AccountID uint `json:"account_id"`
51
+ OauthProvider string `json:"oauth_provider"`
52
  }
53
 
54
  type FCM struct {
 
92
  AcademyMaterialID uint `json:"academy_material_id"`
93
  Description string `json:"description"`
94
  }
95
+ type OptionCategory struct {
96
+ ID uint `gorm:"primaryKey" json:"id"`
97
+ OptionName string `json:"option_name"`
98
+ OptionSlug string `json:"option_slug"`
99
+ }
100
 
101
+ type OptionValues struct {
102
+ ID uint `gorm:"primaryKey" json:"id"`
103
+ OptionCategoryID uint `json:"option_category_id"`
104
+ OptionValue string `json:"option_value"`
105
+ }
106
  type AcademyMaterialProgress struct {
107
  ID uint `gorm:"primaryKey" json:"id"`
108
  UUID uuid.UUID `gorm:"type:uuid" json:"uuid"`
 
118
  AcademyID uint `json:"academy_id"`
119
  }
120
 
121
+ type RegionProvince struct {
122
+ ID uint `json:"id"`
123
+ Name string `json:"name"`
124
+ Code string `json:"code"`
125
+ }
126
+
127
+ type RegionCity struct {
128
+ ID uint `json:"id"`
129
+ Type string `json:"type"`
130
+ Name string `json:"name"`
131
+ Code string `json:"code"`
132
+ FullCode string `json:"full_code"`
133
+ ProvinceID uint `json:"province_id"`
134
+ }
135
+
136
  // Gorm table name settings
137
  func (Account) TableName() string { return "account" }
138
  func (AccountDetails) TableName() string { return "account_details" }
 
145
  func (AcademyContent) TableName() string { return "academy_contents" }
146
  func (AcademyMaterialProgress) TableName() string { return "academy_materials_progress" }
147
  func (AcademyContentProgress) TableName() string { return "academy_contents_progress" }
148
+ func (RegionProvince) TableName() string { return "region_provinces" }
149
+ func (RegionCity) TableName() string { return "region_cities" }
space/space/space/space/space/models/request_model.go CHANGED
@@ -1,5 +1,7 @@
1
  package models
2
 
 
 
3
  type LoginRequest struct {
4
  Email string `json:"email" binding:"required"`
5
  Password string `json:"password" binding:"required"`
@@ -12,11 +14,22 @@ type RegisterRequest struct {
12
  Password string `json:"password" binding:"required"`
13
  }
14
 
15
- type CreateEmailVerificationRequest struct {
16
- AccountID int `json:"account_id" binding:"required"`
17
- }
18
-
19
  type ChangePasswordRequest struct {
20
  OldPassword string `json:"old_password" binding:"required" `
21
  NewPassword string `json:"new_password" binding:"required" `
22
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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"`
 
14
  Password string `json:"password" binding:"required"`
15
  }
16
 
 
 
 
 
17
  type ChangePasswordRequest struct {
18
  OldPassword string `json:"old_password" binding:"required" `
19
  NewPassword string `json:"new_password" binding:"required" `
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 {
28
+ OptionName string `json:"option_name" binding:"required"`
29
+ OptionValue []string `json:"option_values" binding:"required"`
30
+ }
31
+
32
+ type ExternalAuthRequest struct {
33
+ OauthID string `json:"oauth_id" binding:"required"`
34
+ OauthProvider string `json:"oauth_provider" binding:"required"`
35
+ }
space/space/space/space/space/models/response_model.go CHANGED
@@ -18,3 +18,10 @@ type AuthenticatedUser struct {
18
  Account Account `json:"account"`
19
  Token string `json:"token"`
20
  }
 
 
 
 
 
 
 
 
18
  Account Account `json:"account"`
19
  Token string `json:"token"`
20
  }
21
+ type Options struct {
22
+ OptionCategory OptionCategory `json:"option_category"`
23
+ OptionValues []OptionValues `json:"option_values"`
24
+ }
25
+ type OptionsResponse struct {
26
+ Options []Options `json:"options"`
27
+ }
space/space/space/space/space/repositories/account_repository.go CHANGED
@@ -71,7 +71,6 @@ func CreateAccountDetails(accountDetails models.AccountDetails) Repository[model
71
  }
72
 
73
  func UpdateAccountDetails(accountDetails models.AccountDetails) Repository[models.AccountDetails, models.AccountDetails] {
74
- fmt.Println("Account ID : ", accountDetails.AccountID)
75
  repo := Construct[models.AccountDetails, models.AccountDetails](
76
  models.AccountDetails{AccountID: accountDetails.AccountID},
77
  )
 
71
  }
72
 
73
  func UpdateAccountDetails(accountDetails models.AccountDetails) Repository[models.AccountDetails, models.AccountDetails] {
 
74
  repo := Construct[models.AccountDetails, models.AccountDetails](
75
  models.AccountDetails{AccountID: accountDetails.AccountID},
76
  )
space/space/space/space/space/repositories/email_verification_repository.go CHANGED
@@ -4,15 +4,17 @@ import (
4
  "time"
5
 
6
  "api.qobiltu.id/models"
 
7
  )
8
 
9
- func CreateEmailVerification(accountId uint, dueTime time.Time, token uint) Repository[models.EmailVerification, models.EmailVerification] {
10
  repo := Construct[models.EmailVerification, models.EmailVerification](
11
  models.EmailVerification{
12
  AccountID: accountId,
13
  IsExpired: false,
14
  ExpiredAt: dueTime,
15
  Token: token,
 
16
  },
17
  )
18
  Create(repo)
@@ -34,6 +36,18 @@ func GetEmailVerification(accountId uint, token uint) Repository[models.EmailVer
34
  return *repo
35
  }
36
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  func DeleteEmailVerification(token uint) Repository[models.EmailVerification, models.EmailVerification] {
38
  repo := Construct[models.EmailVerification, models.EmailVerification](
39
  models.EmailVerification{
 
4
  "time"
5
 
6
  "api.qobiltu.id/models"
7
+ uuid "github.com/satori/go.uuid"
8
  )
9
 
10
+ func CreateEmailVerification(uuid uuid.UUID, accountId uint, dueTime time.Time, token uint) Repository[models.EmailVerification, models.EmailVerification] {
11
  repo := Construct[models.EmailVerification, models.EmailVerification](
12
  models.EmailVerification{
13
  AccountID: accountId,
14
  IsExpired: false,
15
  ExpiredAt: dueTime,
16
  Token: token,
17
+ UUID: uuid,
18
  },
19
  )
20
  Create(repo)
 
36
  return *repo
37
  }
38
 
39
+ func UpdateExpiredEmailVerification(uuid uuid.UUID) Repository[models.EmailVerification, models.EmailVerification] {
40
+ repo := Construct[models.EmailVerification, models.EmailVerification](
41
+ models.EmailVerification{UUID: uuid},
42
+ )
43
+
44
+ repo.Transaction.Where("UUID = ?", uuid).First(&repo.Constructor)
45
+ repo.Constructor.IsExpired = true
46
+ repo.Transaction.Updates(repo.Constructor)
47
+ repo.Result = repo.Constructor
48
+ return *repo
49
+ }
50
+
51
  func DeleteEmailVerification(token uint) Repository[models.EmailVerification, models.EmailVerification] {
52
  repo := Construct[models.EmailVerification, models.EmailVerification](
53
  models.EmailVerification{
space/space/space/space/space/repositories/external_auth_repository.go ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package repositories
2
+
3
+ import "api.qobiltu.id/models"
4
+
5
+ func CreateExternalAuth(oauth models.ExternalAuth) Repository[models.ExternalAuth, models.ExternalAuth] {
6
+ repo := Construct[models.ExternalAuth, models.ExternalAuth](
7
+ oauth,
8
+ )
9
+ Create(repo)
10
+ return *repo
11
+ }
12
+
13
+ func GetExternalAuthByAccountId(accountId uint) Repository[models.ExternalAuth, []models.ExternalAuth] {
14
+ repo := Construct[models.ExternalAuth, []models.ExternalAuth](
15
+ models.ExternalAuth{
16
+ AccountID: accountId,
17
+ },
18
+ )
19
+ repo.Transactions(
20
+ WhereGivenConstructor[models.ExternalAuth, []models.ExternalAuth],
21
+ Find[models.ExternalAuth, []models.ExternalAuth],
22
+ )
23
+ return *repo
24
+ }
25
+
26
+ func GetExternalAccountByOauthId(oauthId string) Repository[models.ExternalAuth, models.ExternalAuth] {
27
+ repo := Construct[models.ExternalAuth, models.ExternalAuth](
28
+ models.ExternalAuth{
29
+ OauthID: oauthId,
30
+ },
31
+ )
32
+ repo.Transactions(
33
+ WhereGivenConstructor[models.ExternalAuth, models.ExternalAuth],
34
+ Find[models.ExternalAuth, models.ExternalAuth],
35
+ )
36
+ return *repo
37
+ }
space/space/space/space/space/repositories/option_repository.go ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package repositories
2
+
3
+ import (
4
+ "api.qobiltu.id/models"
5
+ )
6
+
7
+ func CreateOptionCategory(categories models.OptionCategory) Repository[models.OptionCategory, models.OptionCategory] {
8
+ repo := Construct[models.OptionCategory, models.OptionCategory](
9
+ categories,
10
+ )
11
+ Create(repo)
12
+ return *repo
13
+ }
14
+
15
+ func CreateOptionValues(values models.OptionValues) Repository[models.OptionValues, models.OptionValues] {
16
+ repo := Construct[models.OptionValues, models.OptionValues](
17
+ values,
18
+ )
19
+ Create(repo)
20
+ return *repo
21
+ }
22
+
23
+ func GetOptionCategoryBySlug(slug string) Repository[models.OptionCategory, models.OptionCategory] {
24
+ repo := Construct[models.OptionCategory, models.OptionCategory](
25
+ models.OptionCategory{OptionSlug: slug},
26
+ )
27
+ repo.Transactions(
28
+ WhereGivenConstructor[models.OptionCategory, models.OptionCategory],
29
+ Find[models.OptionCategory, models.OptionCategory],
30
+ )
31
+ return *repo
32
+ }
33
+
34
+ func GetOptionValuesByCategoryId(categoryId uint) Repository[models.OptionValues, []models.OptionValues] {
35
+ repo := Construct[models.OptionValues, []models.OptionValues](
36
+ models.OptionValues{OptionCategoryID: categoryId},
37
+ )
38
+ repo.Transactions(
39
+ WhereGivenConstructor[models.OptionValues, []models.OptionValues],
40
+ Find[models.OptionValues, []models.OptionValues],
41
+ )
42
+ return *repo
43
+ }
space/space/space/space/space/repositories/region_repository.go ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package repositories
2
+
3
+ import (
4
+ "api.qobiltu.id/models"
5
+ )
6
+
7
+ func BulkCreateProvince(provinces []models.RegionProvince) Repository[[]models.RegionProvince, []models.RegionProvince] {
8
+ repo := Construct[[]models.RegionProvince, []models.RegionProvince](
9
+ provinces,
10
+ )
11
+
12
+ Create(repo)
13
+ return *repo
14
+ }
15
+
16
+ func BulkCreateCity(cities []models.RegionCity) Repository[[]models.RegionCity, []models.RegionCity] {
17
+ repo := Construct[[]models.RegionCity, []models.RegionCity](
18
+ cities,
19
+ )
20
+
21
+ Create(repo)
22
+ return *repo
23
+ }
24
+
25
+ func GetListProvinces() Repository[models.RegionProvince, []models.RegionProvince] {
26
+ repo := Construct[models.RegionProvince, []models.RegionProvince](
27
+ models.RegionProvince{},
28
+ )
29
+
30
+ repo.Transactions(
31
+ Find[models.RegionProvince, []models.RegionProvince],
32
+ )
33
+ return *repo
34
+ }
35
+
36
+ func GetListCitiesByProvinceId(provinceId uint) Repository[models.RegionCity, []models.RegionCity] {
37
+ repo := Construct[models.RegionCity, []models.RegionCity](
38
+ models.RegionCity{
39
+ ProvinceID: provinceId,
40
+ },
41
+ )
42
+ repo.Transactions(
43
+ WhereGivenConstructor[models.RegionCity, []models.RegionCity],
44
+ Find[models.RegionCity, []models.RegionCity],
45
+ )
46
+ return *repo
47
+ }
space/space/space/space/space/router/auth_route.go CHANGED
@@ -9,6 +9,7 @@ import (
9
  func AuthRoute(router *gin.Engine) {
10
  routerGroup := router.Group("/api/v1/auth")
11
  {
 
12
  routerGroup.POST("/login", AuthController.Login)
13
  routerGroup.POST("/register", AuthController.Register)
14
  routerGroup.PUT("/change-password", middleware.AuthUser, AuthController.ChangePassword)
 
9
  func AuthRoute(router *gin.Engine) {
10
  routerGroup := router.Group("/api/v1/auth")
11
  {
12
+ routerGroup.POST("/external-login", AuthController.ExternalAuth)
13
  routerGroup.POST("/login", AuthController.Login)
14
  routerGroup.POST("/register", AuthController.Register)
15
  routerGroup.PUT("/change-password", middleware.AuthUser, AuthController.ChangePassword)
space/space/space/space/space/router/email_route.go CHANGED
@@ -2,14 +2,14 @@ package router
2
 
3
  import (
4
  EmailController "api.qobiltu.id/controller/email"
 
5
  "github.com/gin-gonic/gin"
6
  )
7
 
8
  func EmailRoute(router *gin.Engine) {
9
  routerGroup := router.Group("/api/v1/email")
10
  {
11
- routerGroup.POST("/verify", EmailController.CreateVerification)
12
- routerGroup.POST("/create-verification", EmailController.CreateVerification)
13
- routerGroup.DELETE("/delete-verification", EmailController.DeleteVerification)
14
  }
15
  }
 
2
 
3
  import (
4
  EmailController "api.qobiltu.id/controller/email"
5
+ "api.qobiltu.id/middleware"
6
  "github.com/gin-gonic/gin"
7
  )
8
 
9
  func EmailRoute(router *gin.Engine) {
10
  routerGroup := router.Group("/api/v1/email")
11
  {
12
+ routerGroup.POST("/verify", middleware.AuthUser, EmailController.Verify)
13
+ routerGroup.POST("/create-verification", middleware.AuthUser, EmailController.CreateVerification)
 
14
  }
15
  }
space/space/space/space/space/router/options_route.go ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package router
2
+
3
+ import (
4
+ OptionsController "api.qobiltu.id/controller/options"
5
+ CityController "api.qobiltu.id/controller/region/city"
6
+ ProvinceController "api.qobiltu.id/controller/region/province"
7
+ "github.com/gin-gonic/gin"
8
+ )
9
+
10
+ func OptionsRoute(router *gin.Engine) {
11
+ routerGroup := router.Group("/api/v1/options")
12
+ {
13
+ routerGroup.POST("/create", OptionsController.AddOptions)
14
+ routerGroup.GET("/list/:slug", OptionsController.List)
15
+ routerGroup.GET("/region/provinces", ProvinceController.List)
16
+ routerGroup.GET("/region/cities", CityController.List)
17
+ routerGroup.POST("/region/seed-provinces", ProvinceController.Seeds)
18
+ routerGroup.POST("/region/seed-cities", CityController.Seeds)
19
+ }
20
+ }
space/space/space/space/space/router/router.go CHANGED
@@ -12,5 +12,6 @@ func StartService() {
12
  AuthRoute(router)
13
  UserRoute(router)
14
  EmailRoute(router)
 
15
  router.Run(config.TCP_ADDRESS)
16
  }
 
12
  AuthRoute(router)
13
  UserRoute(router)
14
  EmailRoute(router)
15
+ OptionsRoute(router)
16
  router.Run(config.TCP_ADDRESS)
17
  }
space/space/space/space/space/services/authentication_service.go CHANGED
@@ -2,7 +2,6 @@ package services
2
 
3
  import (
4
  "errors"
5
- "fmt"
6
 
7
  "api.qobiltu.id/models"
8
  "api.qobiltu.id/repositories"
@@ -45,15 +44,13 @@ func (s *AuthenticationService) Update(oldPassword string, newPassword string) {
45
  s.Exception.Message = "Password must have at least 8 characters!"
46
  return
47
  }
48
- accountData := repositories.GetAccountbyId(s.Constructor.Id)
49
 
50
  if accountData.NoRecord {
51
  s.Exception.DataNotFound = true
52
  s.Exception.Message = "there is no account with given credentials!"
53
  return
54
  }
55
- fmt.Println("Result Password", accountData.Result.Password)
56
- fmt.Println("old Password given", oldPassword)
57
  if VerifyPassword(accountData.Result.Password, oldPassword) != nil {
58
  s.Exception.Unauthorized = true
59
  s.Exception.Message = "incorrect old password!"
 
2
 
3
  import (
4
  "errors"
 
5
 
6
  "api.qobiltu.id/models"
7
  "api.qobiltu.id/repositories"
 
44
  s.Exception.Message = "Password must have at least 8 characters!"
45
  return
46
  }
47
+ accountData := repositories.GetAccountById(s.Constructor.Id)
48
 
49
  if accountData.NoRecord {
50
  s.Exception.DataNotFound = true
51
  s.Exception.Message = "there is no account with given credentials!"
52
  return
53
  }
 
 
54
  if VerifyPassword(accountData.Result.Password, oldPassword) != nil {
55
  s.Exception.Unauthorized = true
56
  s.Exception.Message = "incorrect old password!"
space/space/space/space/space/services/email_verification_service.go CHANGED
@@ -1,7 +1,10 @@
1
  package services
2
 
3
  import (
 
 
4
  "math/rand/v2"
 
5
  "time"
6
 
7
  "api.qobiltu.id/config"
@@ -28,20 +31,52 @@ func (s *EmailVerificationService) Create() {
28
 
29
  token := uint(rand.IntN(100000))
30
  s.Constructor.UUID = uuid.NewV4()
31
- repo := repositories.CreateEmailVerification(s.Constructor.AccountID, dueTime, token)
 
32
 
33
  s.Error = repo.RowsError
34
  s.Result = repo.Result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
 
37
  func (s *EmailVerificationService) Validate() {
38
  repo := repositories.GetEmailVerification(s.Constructor.AccountID, s.Constructor.Token)
39
  s.Error = repo.RowsError
 
40
  if repo.NoRecord {
41
  s.Exception.DataNotFound = true
42
  s.Exception.Message = "Invalid token!"
43
  return
44
  }
 
 
 
 
 
 
 
45
  s.Result = repo.Result
46
  }
47
 
 
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"
 
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)
36
 
37
  s.Error = repo.RowsError
38
  s.Result = repo.Result
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
+ log.Printf("Error sending verification email: %v", err)
60
+ }
61
+ }(accountRepo.Result.Email, token)
62
  }
63
 
64
  func (s *EmailVerificationService) Validate() {
65
  repo := repositories.GetEmailVerification(s.Constructor.AccountID, s.Constructor.Token)
66
  s.Error = repo.RowsError
67
+
68
  if repo.NoRecord {
69
  s.Exception.DataNotFound = true
70
  s.Exception.Message = "Invalid token!"
71
  return
72
  }
73
+
74
+ if repo.Result.ExpiredAt.Before(time.Now()) {
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
 
space/space/space/space/space/services/external_authentication_service.go ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package services
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+
7
+ "api.qobiltu.id/models"
8
+ "api.qobiltu.id/repositories"
9
+ uuid "github.com/satori/go.uuid"
10
+ "google.golang.org/api/idtoken"
11
+ )
12
+
13
+ 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
21
+ if errGoogleAuth != nil {
22
+ s.Exception.Unauthorized = true
23
+ s.Exception.Message = "Oauth Provider Failed Login (Google Authentication)"
24
+ return
25
+ }
26
+ email := payload.Claims["email"]
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)
42
+ token, err_tok := GenerateToken(&accountData.Result)
43
+
44
+ if err_tok != nil {
45
+ s.Error = errors.Join(s.Error, err_tok)
46
+ }
47
+
48
+ accountData.Result.Password = "SECRET"
49
+ s.Result = models.AuthenticatedUser{
50
+ Account: accountData.Result,
51
+ Token: token,
52
+ }
53
+ s.Error = accountData.RowsError
54
+
55
+ }
space/space/space/space/space/services/option_service.go ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package services
2
+
3
+ import (
4
+ "api.qobiltu.id/models"
5
+ "api.qobiltu.id/repositories"
6
+ "github.com/gosimple/slug"
7
+ )
8
+
9
+ type OptionService struct {
10
+ Service[[]models.OptionsRequest, models.OptionsResponse]
11
+ }
12
+
13
+ type OptionValueService struct {
14
+ Service[models.OptionCategory, models.Options]
15
+ }
16
+
17
+ func (s *OptionService) Create() {
18
+ optionsResult := []models.Options{}
19
+ for _, option := range s.Constructor {
20
+ OptionCategoryRepo := repositories.CreateOptionCategory(
21
+ models.OptionCategory{
22
+ OptionName: option.OptionName,
23
+ OptionSlug: slug.Make(option.OptionName),
24
+ },
25
+ )
26
+ if OptionCategoryRepo.RowsError != nil {
27
+ OptionCategoryRepo.Transaction.Rollback()
28
+ s.Error = OptionCategoryRepo.RowsError
29
+ return
30
+ }
31
+ optionsValueResult := []models.OptionValues{}
32
+ for _, value := range option.OptionValue {
33
+ OptionValuesRepo := repositories.CreateOptionValues(
34
+ models.OptionValues{
35
+ OptionCategoryID: OptionCategoryRepo.Result.ID,
36
+ OptionValue: value,
37
+ },
38
+ )
39
+
40
+ if OptionValuesRepo.RowsError != nil {
41
+ OptionValuesRepo.Transaction.Rollback()
42
+ s.Error = OptionValuesRepo.RowsError
43
+ return
44
+ }
45
+ optionsValueResult = append(optionsValueResult, OptionValuesRepo.Result)
46
+ }
47
+ optionsResult = append(optionsResult, models.Options{OptionCategory: OptionCategoryRepo.Result, OptionValues: optionsValueResult})
48
+ }
49
+ s.Result = models.OptionsResponse{
50
+ Options: optionsResult,
51
+ }
52
+ }
53
+
54
+ func (s *OptionValueService) Retrieve() {
55
+ optionCategory := repositories.GetOptionCategoryBySlug(s.Constructor.OptionSlug)
56
+ if optionCategory.RowsError != nil {
57
+ s.Error = optionCategory.RowsError
58
+ return
59
+ }
60
+ optionValues := repositories.GetOptionValuesByCategoryId(optionCategory.Result.ID)
61
+ if optionValues.RowsError != nil {
62
+ s.Error = optionValues.RowsError
63
+ return
64
+ }
65
+ s.Result = models.Options{
66
+ OptionCategory: optionCategory.Result,
67
+ OptionValues: optionValues.Result,
68
+ }
69
+
70
+ }
space/space/space/space/space/services/region_service.go ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package services
2
+
3
+ import (
4
+ "encoding/json"
5
+ "log"
6
+ "os"
7
+ "path/filepath"
8
+ "runtime"
9
+
10
+ "api.qobiltu.id/models"
11
+ "api.qobiltu.id/repositories"
12
+ )
13
+
14
+ type ProvinceService struct {
15
+ Service[models.RegionProvince, []models.RegionProvince]
16
+ }
17
+
18
+ type CityService struct {
19
+ Service[models.RegionCity, []models.RegionCity]
20
+ }
21
+
22
+ func seedCity() ([]models.RegionCity, error) {
23
+ log.Println("Seed City")
24
+ _, b, _, _ := runtime.Caller(0)
25
+ basePath := filepath.Dir(b)
26
+ file, err := os.Open(filepath.Join(basePath, "..", "utils", "seeds", "city.json"))
27
+ if err != nil {
28
+ return nil, err
29
+ }
30
+ defer file.Close()
31
+ var cities []models.RegionCity
32
+ if err := json.NewDecoder(file).Decode(&cities); err != nil {
33
+ return nil, err
34
+ }
35
+ return cities, nil
36
+ }
37
+
38
+ func seedProvince() ([]models.RegionProvince, error) {
39
+ log.Println("Seed City")
40
+ _, b, _, _ := runtime.Caller(0)
41
+ basePath := filepath.Dir(b)
42
+ file, err := os.Open(filepath.Join(basePath, "..", "utils", "seeds", "province.json"))
43
+ if err != nil {
44
+ return nil, err
45
+ }
46
+ defer file.Close()
47
+ var provinces []models.RegionProvince
48
+ if err := json.NewDecoder(file).Decode(&provinces); err != nil {
49
+ return nil, err
50
+ }
51
+ return provinces, nil
52
+ }
53
+
54
+ func (s *ProvinceService) Create() {
55
+ provinces, errSeed := seedProvince()
56
+ if errSeed != nil {
57
+ s.Error = errSeed
58
+ s.Exception.InternalServerError = true
59
+ s.Exception.Message = "Failed to seed province"
60
+ return
61
+ }
62
+ createProvince := repositories.BulkCreateProvince(provinces)
63
+ s.Error = createProvince.RowsError
64
+ s.Result = createProvince.Result
65
+ }
66
+
67
+ func (s *CityService) Create() {
68
+ cities, errSeed := seedCity()
69
+ if errSeed != nil {
70
+ s.Error = errSeed
71
+ s.Exception.InternalServerError = true
72
+ s.Exception.Message = "Failed to seed province"
73
+ return
74
+ }
75
+ createCity := repositories.BulkCreateCity(cities)
76
+ s.Error = createCity.RowsError
77
+ s.Result = createCity.Result
78
+ }
79
+
80
+ func (s *ProvinceService) Retrieve() {
81
+ Province := repositories.GetListProvinces()
82
+ s.Error = Province.RowsError
83
+ s.Result = Province.Result
84
+ }
85
+
86
+ func (s *CityService) Retrieve() {
87
+ cities := repositories.GetListCitiesByProvinceId(s.Constructor.ProvinceID)
88
+ s.Error = cities.RowsError
89
+ s.Result = cities.Result
90
+ }
space/space/space/space/space/space/controller/email/email_create_verification.go CHANGED
@@ -1,8 +1,6 @@
1
  package controller
2
 
3
  import (
4
- "strconv"
5
-
6
  "api.qobiltu.id/controller"
7
  "api.qobiltu.id/models"
8
  "api.qobiltu.id/services"
@@ -14,9 +12,10 @@ func CreateVerification(c *gin.Context) {
14
  emailVerificationController := controller.Controller[any, models.EmailVerification, models.EmailVerification]{
15
  Service: &emailVerification.Service,
16
  }
17
- query, _ := c.GetQuery("account_id")
18
- accountId, _ := strconv.Atoi(query)
19
- emailVerificationController.Service.Constructor.AccountID = uint(accountId)
20
- emailVerification.Create()
21
- emailVerificationController.Response(c)
 
22
  }
 
1
  package controller
2
 
3
  import (
 
 
4
  "api.qobiltu.id/controller"
5
  "api.qobiltu.id/models"
6
  "api.qobiltu.id/services"
 
12
  emailVerificationController := controller.Controller[any, 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
  }