lifedebugger commited on
Commit
b2f75d9
·
1 Parent(s): 8a17702

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/academy/academy_contents_controller.go +1 -1
  2. models/database_orm_model.go +5 -3
  3. models/response_model.go +1 -1
  4. repositories/academy_repository.go +4 -4
  5. services/academy_service.go +24 -9
  6. services/register_service.go +43 -3
  7. space/controller/academy/academy_contents_controller.go +19 -0
  8. space/controller/academy/academy_controller.go +1 -1
  9. space/controller/academy/academy_materials_controller.go +19 -0
  10. space/models/database_orm_model.go +8 -5
  11. space/repositories/academy_repository.go +11 -0
  12. space/router/academy_route.go +2 -1
  13. space/services/academy_service.go +36 -18
  14. space/services/jwt_service.go +1 -1
  15. space/services/service.go +3 -0
  16. space/space/services/email_verification_service.go +3 -14
  17. space/space/space/space/config/config.go +2 -0
  18. space/space/space/space/services/email_verification_service.go +100 -8
  19. space/space/space/space/space/services/external_authentication_service.go +10 -6
  20. space/space/space/space/space/space/services/email_verification_service.go +1 -4
  21. space/space/space/space/space/space/services/forgot_password_service.go +1 -4
  22. space/space/space/space/space/space/space/services/external_authentication_service.go +18 -1
  23. space/space/space/space/space/space/space/space/controller/academy/academy_controller.go +31 -0
  24. space/space/space/space/space/space/space/space/logs/error_log.txt +2 -0
  25. space/space/space/space/space/space/space/space/models/database_orm_model.go +7 -7
  26. space/space/space/space/space/space/space/space/repositories/academy_repository.go +28 -2
  27. space/space/space/space/space/space/space/space/router/academy_route.go +16 -0
  28. space/space/space/space/space/space/space/space/router/router.go +1 -1
  29. space/space/space/space/space/space/space/space/services/academy_service.go +75 -11
  30. space/space/space/space/space/space/space/space/services/email_verification_service.go +5 -2
  31. space/space/space/space/space/space/space/space/services/forgot_password_service.go +4 -1
  32. space/space/space/space/space/space/space/space/space/logs/error_log.txt +2 -1
  33. space/space/space/space/space/space/space/space/space/models/response_model.go +9 -6
  34. space/space/space/space/space/space/space/space/space/repositories/academy_repository.go +47 -0
  35. space/space/space/space/space/space/space/space/space/services/academy_service.go +40 -0
  36. space/space/space/space/space/space/space/space/space/services/external_authentication_service.go +1 -0
  37. space/space/space/space/space/space/space/space/space/services/forgot_password_service.go +11 -7
  38. space/space/space/space/space/space/space/space/space/space/space/go.mod +2 -5
  39. space/space/space/space/space/space/space/space/space/space/space/go.sum +17 -13
  40. space/space/space/space/space/space/space/space/space/space/space/space/models/response_model.go +10 -0
  41. space/space/space/space/space/space/space/space/space/space/space/space/services/forgot_password_service.go +7 -3
  42. space/space/space/space/space/space/space/space/space/space/space/space/space/controller/auth/auth_external_controller.go +1 -1
  43. space/space/space/space/space/space/space/space/space/space/space/space/space/controller/auth/auth_forgot_password_controller.go +28 -0
  44. space/space/space/space/space/space/space/space/space/space/space/space/space/controller/email/email_validate_controller.go +0 -1
  45. space/space/space/space/space/space/space/space/space/space/space/space/space/models/request_model.go +9 -4
  46. space/space/space/space/space/space/space/space/space/space/space/space/space/repositories/account_repository.go +2 -4
  47. space/space/space/space/space/space/space/space/space/space/space/space/space/router/auth_route.go +2 -0
  48. space/space/space/space/space/space/space/space/space/space/space/space/space/services/authentication_service.go +2 -1
  49. space/space/space/space/space/space/space/space/space/space/space/space/space/services/email_verification_service.go +5 -1
  50. space/space/space/space/space/space/space/space/space/space/space/space/space/services/external_authentication_service.go +6 -1
controller/academy/academy_contents_controller.go CHANGED
@@ -9,7 +9,7 @@ import (
9
 
10
  func ContentList(c *gin.Context) {
11
  academyContent := services.AcademyContentService{}
12
- academyController := controller.Controller[any, models.AcademyMaterial, []models.AcademyContent]{
13
  Service: &academyContent.Service,
14
  }
15
  academyController.Service.Constructor.Slug = c.Param("slug_material")
 
9
 
10
  func ContentList(c *gin.Context) {
11
  academyContent := services.AcademyContentService{}
12
+ academyController := controller.Controller[any, models.AcademyMaterial, models.AcademyContent]{
13
  Service: &academyContent.Service,
14
  }
15
  academyController.Service.Constructor.Slug = c.Param("slug_material")
models/database_orm_model.go CHANGED
@@ -71,9 +71,11 @@ type Academy struct {
71
  ID uint `gorm:"primaryKey" json:"id"`
72
  UUID uuid.UUID `gorm:"type:uuid" json:"uuid"`
73
  Title string `json:"title"`
74
- Slug string `json:"slug"`
75
  TotalMaterial int `json:"total_material"`
76
  CompletedMaterial int `json:"completed_material"`
 
 
77
  Description string `json:"description"`
78
  }
79
 
@@ -82,7 +84,7 @@ type AcademyMaterial struct {
82
  UUID uuid.UUID `gorm:"type:uuid" json:"uuid"`
83
  AcademyID uint `json:"academy_id"`
84
  Title string `json:"title"`
85
- Slug string `json:"slug"`
86
  IsCompleted bool `json:"is_completed"`
87
  Description string `json:"description"`
88
  }
@@ -98,7 +100,7 @@ type AcademyContent struct {
98
  type OptionCategory struct {
99
  ID uint `gorm:"primaryKey" json:"id"`
100
  OptionName string `json:"option_name"`
101
- OptionSlug string `json:"option_slug"`
102
  }
103
 
104
  type OptionValues struct {
 
71
  ID uint `gorm:"primaryKey" json:"id"`
72
  UUID uuid.UUID `gorm:"type:uuid" json:"uuid"`
73
  Title string `json:"title"`
74
+ Slug string `json:"slug" gorm:"uniqueIndex" `
75
  TotalMaterial int `json:"total_material"`
76
  CompletedMaterial int `json:"completed_material"`
77
+ IsCompletedRead bool `json:"is_read"`
78
+ IsPassedExam bool `json:"is_exam"`
79
  Description string `json:"description"`
80
  }
81
 
 
84
  UUID uuid.UUID `gorm:"type:uuid" json:"uuid"`
85
  AcademyID uint `json:"academy_id"`
86
  Title string `json:"title"`
87
+ Slug string `json:"slug" gorm:"uniqueIndex"`
88
  IsCompleted bool `json:"is_completed"`
89
  Description string `json:"description"`
90
  }
 
100
  type OptionCategory struct {
101
  ID uint `gorm:"primaryKey" json:"id"`
102
  OptionName string `json:"option_name"`
103
+ OptionSlug string `json:"option_slug" gorm:"uniqueIndex"`
104
  }
105
 
106
  type OptionValues struct {
models/response_model.go CHANGED
@@ -33,7 +33,7 @@ type UserProfileResponse struct {
33
 
34
  type AcademyMaterialResponse struct {
35
  Materials AcademyMaterial
36
- Contents []AcademyContent
37
  }
38
  type AcademyResponse struct {
39
  Academy Academy `json:"academy"`
 
33
 
34
  type AcademyMaterialResponse struct {
35
  Materials AcademyMaterial
36
+ Contents AcademyContent
37
  }
38
  type AcademyResponse struct {
39
  Academy Academy `json:"academy"`
repositories/academy_repository.go CHANGED
@@ -35,13 +35,13 @@ func GetAllAcademyMaterialsByAcademyID(acaddemyId uint) Repository[models.Academ
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
  }
 
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
  }
services/academy_service.go CHANGED
@@ -1,6 +1,8 @@
1
  package services
2
 
3
  import (
 
 
4
  "api.qobiltu.id/models"
5
  "api.qobiltu.id/repositories"
6
  "github.com/gosimple/slug"
@@ -20,12 +22,13 @@ type AcademyMaterialService struct {
20
  }
21
 
22
  type AcademyContentService struct {
23
- Service[models.AcademyMaterial, []models.AcademyContent]
24
  }
25
 
26
  func castAcademyMaterials(academyId uint) []models.AcademyMaterialResponse {
27
  var ArrMaterials []models.AcademyMaterialResponse
28
- for _, academyMaterial := range repositories.GetAllAcademyMaterialsByAcademyID(academyId).Result {
 
29
  ArrMaterials = append(ArrMaterials, models.AcademyMaterialResponse{
30
  Materials: academyMaterial,
31
  Contents: repositories.GetAllAcademyContentsByMaterialID(academyMaterial.ID).Result,
@@ -78,7 +81,7 @@ func (s *CreateAcademyService) Create() {
78
  s.Error = createdMaterial.RowsError
79
  return
80
  }
81
- for _, content := range material.Contents {
82
  content.UUID = uuid.NewV4()
83
  content.AcademyMaterialID = createdMaterial.Result.ID
84
  createdContent := repositories.CreateAcademyContent(content)
@@ -98,9 +101,15 @@ func (s *CreateAcademyService) Create() {
98
  }
99
 
100
  func (s *AcademyMaterialService) Retrieve() {
101
- academyId := repositories.GetAcademyDataBySlug(s.Constructor.Slug).Result.ID
102
- academyMaterialRepo := repositories.GetAllAcademyMaterialsByAcademyID(academyId)
103
- s.Error = academyMaterialRepo.RowsError
 
 
 
 
 
 
104
  if academyMaterialRepo.NoRecord {
105
  s.Exception.DataNotFound = true
106
  s.Exception.Message = "There is no Academy Material with given ID"
@@ -110,9 +119,15 @@ func (s *AcademyMaterialService) Retrieve() {
110
  }
111
 
112
  func (s *AcademyContentService) Retrieve() {
113
- academyMaterialId := repositories.GetAcademyMaterialBySlug(s.Constructor.Slug).Result.ID
114
- academyContentRepo := repositories.GetAllAcademyContentsByMaterialID(academyMaterialId)
115
- s.Error = academyContentRepo.RowsError
 
 
 
 
 
 
116
  if academyContentRepo.NoRecord {
117
  s.Exception.DataNotFound = true
118
  s.Exception.Message = "There is no Academy Contents with given Material ID"
 
1
  package services
2
 
3
  import (
4
+ "errors"
5
+
6
  "api.qobiltu.id/models"
7
  "api.qobiltu.id/repositories"
8
  "github.com/gosimple/slug"
 
22
  }
23
 
24
  type AcademyContentService struct {
25
+ Service[models.AcademyMaterial, models.AcademyContent]
26
  }
27
 
28
  func castAcademyMaterials(academyId uint) []models.AcademyMaterialResponse {
29
  var ArrMaterials []models.AcademyMaterialResponse
30
+ academyMaterialsRepo := repositories.GetAllAcademyMaterialsByAcademyID(academyId)
31
+ for _, academyMaterial := range academyMaterialsRepo.Result {
32
  ArrMaterials = append(ArrMaterials, models.AcademyMaterialResponse{
33
  Materials: academyMaterial,
34
  Contents: repositories.GetAllAcademyContentsByMaterialID(academyMaterial.ID).Result,
 
81
  s.Error = createdMaterial.RowsError
82
  return
83
  }
84
+ for _, content := range []models.AcademyContent{material.Contents} {
85
  content.UUID = uuid.NewV4()
86
  content.AcademyMaterialID = createdMaterial.Result.ID
87
  createdContent := repositories.CreateAcademyContent(content)
 
101
  }
102
 
103
  func (s *AcademyMaterialService) Retrieve() {
104
+ academyRepo := repositories.GetAcademyDataBySlug(s.Constructor.Slug)
105
+ if academyRepo.NoRecord {
106
+ s.Exception.DataNotFound = true
107
+ s.Exception.Message = "There is no Academy found with given Slug!"
108
+ return
109
+ }
110
+ s.Error = academyRepo.RowsError
111
+ academyMaterialRepo := repositories.GetAllAcademyMaterialsByAcademyID(academyRepo.Result.ID)
112
+ s.Error = errors.Join(s.Error, academyMaterialRepo.RowsError)
113
  if academyMaterialRepo.NoRecord {
114
  s.Exception.DataNotFound = true
115
  s.Exception.Message = "There is no Academy Material with given ID"
 
119
  }
120
 
121
  func (s *AcademyContentService) Retrieve() {
122
+ academyMaterialRepo := repositories.GetAcademyMaterialBySlug(s.Constructor.Slug)
123
+ s.Error = academyMaterialRepo.RowsError
124
+ if academyMaterialRepo.NoRecord {
125
+ s.Exception.DataNotFound = true
126
+ s.Exception.Message = "There is no Academy Material with given Slug"
127
+ return
128
+ }
129
+ academyContentRepo := repositories.GetAllAcademyContentsByMaterialID(academyMaterialRepo.Result.ID)
130
+ s.Error = errors.Join(s.Error, academyContentRepo.RowsError)
131
  if academyContentRepo.NoRecord {
132
  s.Exception.DataNotFound = true
133
  s.Exception.Message = "There is no Academy Contents with given Material ID"
services/register_service.go CHANGED
@@ -2,6 +2,7 @@ package services
2
 
3
  import (
4
  "errors"
 
5
 
6
  "api.qobiltu.id/models"
7
  "api.qobiltu.id/repositories"
@@ -13,10 +14,49 @@ type RegisterService struct {
13
  Service[models.Account, models.Account]
14
  }
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  func (s *RegisterService) Create() {
17
- if len(s.Constructor.Password) < 8 {
18
- s.Exception.InvalidPasswordLength = true
19
- s.Exception.Message = "Password must have at least 8 characters!"
20
  return
21
  }
22
  hashed_password, err_hash := HashPassword(s.Constructor.Password)
 
2
 
3
  import (
4
  "errors"
5
+ "unicode"
6
 
7
  "api.qobiltu.id/models"
8
  "api.qobiltu.id/repositories"
 
14
  Service[models.Account, models.Account]
15
  }
16
 
17
+ func ValidatePassword(password string) models.Exception {
18
+ var (
19
+ hasMinLen = false
20
+ hasUpper = false
21
+ hasLower = false
22
+ hasNumber = false
23
+ hasSpecial = false
24
+ )
25
+
26
+ if len(password) >= 8 {
27
+ hasMinLen = true
28
+ }
29
+
30
+ for _, char := range password {
31
+ switch {
32
+ case unicode.IsUpper(char):
33
+ hasUpper = true
34
+ break
35
+ case unicode.IsLower(char):
36
+ hasLower = true
37
+ break
38
+ case unicode.IsDigit(char):
39
+ hasNumber = true
40
+ break
41
+ case unicode.IsPunct(char) || unicode.IsSymbol(char):
42
+ hasSpecial = true
43
+ break
44
+ }
45
+ }
46
+ approve := hasMinLen && hasUpper && hasLower && hasNumber && hasSpecial
47
+ if !approve {
48
+ return models.Exception{
49
+ BadRequest: true,
50
+ Message: "Password must contain at least 8 characters, including uppercase, lowercase, number, and special character!",
51
+ }
52
+ }
53
+ return models.Exception{}
54
+ }
55
+
56
  func (s *RegisterService) Create() {
57
+ validatePassword := ValidatePassword(s.Constructor.Password)
58
+ if validatePassword.BadRequest {
59
+ s.Exception = validatePassword
60
  return
61
  }
62
  hashed_password, err_hash := HashPassword(s.Constructor.Password)
space/controller/academy/academy_contents_controller.go ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ContentList(c *gin.Context) {
11
+ academyContent := services.AcademyContentService{}
12
+ academyController := controller.Controller[any, models.AcademyMaterial, []models.AcademyContent]{
13
+ Service: &academyContent.Service,
14
+ }
15
+ academyController.Service.Constructor.Slug = c.Param("slug_material")
16
+ academyContent.Retrieve()
17
+ academyController.Response(c)
18
+
19
+ }
space/controller/academy/academy_controller.go CHANGED
@@ -9,7 +9,7 @@ import (
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")
 
9
 
10
  func List(c *gin.Context) {
11
  academy := services.AcademyService{}
12
+ academyController := controller.Controller[any, models.Academy, []models.Academy]{
13
  Service: &academy.Service,
14
  }
15
  academyController.Service.Constructor.Slug = c.Param("slug")
space/controller/academy/academy_materials_controller.go ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 MaterialsList(c *gin.Context) {
11
+ academyMaterial := services.AcademyMaterialService{}
12
+ academyController := controller.Controller[any, models.Academy, []models.AcademyMaterial]{
13
+ Service: &academyMaterial.Service,
14
+ }
15
+ academyController.Service.Constructor.Slug = c.Param("slug")
16
+ academyMaterial.Retrieve()
17
+ academyController.Response(c)
18
+
19
+ }
space/models/database_orm_model.go CHANGED
@@ -68,11 +68,13 @@ type ForgotPassword struct {
68
  }
69
 
70
  type Academy struct {
71
- ID uint `gorm:"primaryKey" json:"id"`
72
- UUID uuid.UUID `gorm:"type:uuid" json:"uuid"`
73
- Title string `json:"title"`
74
- Slug string `json:"slug"`
75
- Description string `json:"description"`
 
 
76
  }
77
 
78
  type AcademyMaterial struct {
@@ -81,6 +83,7 @@ type AcademyMaterial struct {
81
  AcademyID uint `json:"academy_id"`
82
  Title string `json:"title"`
83
  Slug string `json:"slug"`
 
84
  Description string `json:"description"`
85
  }
86
 
 
68
  }
69
 
70
  type Academy struct {
71
+ ID uint `gorm:"primaryKey" json:"id"`
72
+ UUID uuid.UUID `gorm:"type:uuid" json:"uuid"`
73
+ Title string `json:"title"`
74
+ Slug string `json:"slug"`
75
+ TotalMaterial int `json:"total_material"`
76
+ CompletedMaterial int `json:"completed_material"`
77
+ Description string `json:"description"`
78
  }
79
 
80
  type AcademyMaterial struct {
 
83
  AcademyID uint `json:"academy_id"`
84
  Title string `json:"title"`
85
  Slug string `json:"slug"`
86
+ IsCompleted bool `json:"is_completed"`
87
  Description string `json:"description"`
88
  }
89
 
space/repositories/academy_repository.go CHANGED
@@ -71,3 +71,14 @@ func CreateAcademyContent(academyContent models.AcademyContent) Repository[model
71
  Create(repo)
72
  return *repo
73
  }
 
 
 
 
 
 
 
 
 
 
 
 
71
  Create(repo)
72
  return *repo
73
  }
74
+
75
+ func GetAcademyMaterialBySlug(slug string) Repository[models.AcademyMaterial, models.AcademyMaterial] {
76
+ repo := Construct[models.AcademyMaterial, models.AcademyMaterial](
77
+ models.AcademyMaterial{Slug: slug},
78
+ )
79
+ repo.Transactions(
80
+ WhereGivenConstructor[models.AcademyMaterial, models.AcademyMaterial],
81
+ Find[models.AcademyMaterial, models.AcademyMaterial],
82
+ )
83
+ return *repo
84
+ }
space/router/academy_route.go CHANGED
@@ -9,7 +9,8 @@ import (
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
  }
 
9
  func AcademyRoute(router *gin.Engine) {
10
  routerGroup := router.Group("/api/v1/academy")
11
  {
12
+ routerGroup.GET("/:slug", middleware.AuthUser, AcademyController.MaterialsList)
13
+ routerGroup.GET("/:slug/:slug_material", middleware.AuthUser, AcademyController.ContentList)
14
  routerGroup.GET("/list", middleware.AuthUser, AcademyController.List)
15
  routerGroup.POST("/create", middleware.AuthUser, AcademyController.Create)
16
  }
space/services/academy_service.go CHANGED
@@ -8,13 +8,21 @@ import (
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 {
@@ -35,27 +43,13 @@ func (s *AcademyService) Retrieve() {
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
  }
@@ -102,3 +96,27 @@ func (s *CreateAcademyService) Create() {
102
  s.Result = models.AllAcademyResponse{Academies: ArrAcademy}
103
 
104
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  )
9
 
10
  type AcademyService struct {
11
+ Service[models.Academy, []models.Academy]
12
  }
13
 
14
  type CreateAcademyService struct {
15
  Service[models.AllAcademyResponse, models.AllAcademyResponse]
16
  }
17
 
18
+ type AcademyMaterialService struct {
19
+ Service[models.Academy, []models.AcademyMaterial]
20
+ }
21
+
22
+ type AcademyContentService struct {
23
+ Service[models.AcademyMaterial, []models.AcademyContent]
24
+ }
25
+
26
  func castAcademyMaterials(academyId uint) []models.AcademyMaterialResponse {
27
  var ArrMaterials []models.AcademyMaterialResponse
28
  for _, academyMaterial := range repositories.GetAllAcademyMaterialsByAcademyID(academyId).Result {
 
43
  return
44
  }
45
 
46
+ s.Result = []models.Academy{
47
+ AcademyRepo.Result,
 
 
 
 
 
48
  }
49
  } else {
50
  AcademyRepo := repositories.GetAllAcademy()
51
  s.Error = AcademyRepo.RowsError
52
+ s.Result = AcademyRepo.Result
 
 
 
 
 
 
 
 
 
53
  }
54
 
55
  }
 
96
  s.Result = models.AllAcademyResponse{Academies: ArrAcademy}
97
 
98
  }
99
+
100
+ func (s *AcademyMaterialService) Retrieve() {
101
+ academyId := repositories.GetAcademyDataBySlug(s.Constructor.Slug).Result.ID
102
+ academyMaterialRepo := repositories.GetAllAcademyMaterialsByAcademyID(academyId)
103
+ s.Error = academyMaterialRepo.RowsError
104
+ if academyMaterialRepo.NoRecord {
105
+ s.Exception.DataNotFound = true
106
+ s.Exception.Message = "There is no Academy Material with given ID"
107
+ return
108
+ }
109
+ s.Result = academyMaterialRepo.Result
110
+ }
111
+
112
+ func (s *AcademyContentService) Retrieve() {
113
+ academyMaterialId := repositories.GetAcademyMaterialBySlug(s.Constructor.Slug).Result.ID
114
+ academyContentRepo := repositories.GetAllAcademyContentsByMaterialID(academyMaterialId)
115
+ s.Error = academyContentRepo.RowsError
116
+ if academyContentRepo.NoRecord {
117
+ s.Exception.DataNotFound = true
118
+ s.Exception.Message = "There is no Academy Contents with given Material ID"
119
+ return
120
+ }
121
+ s.Result = academyContentRepo.Result
122
+ }
space/services/jwt_service.go CHANGED
@@ -20,7 +20,7 @@ func GenerateToken(user *models.Account) (string, error) {
20
  RegisteredClaims: jwt.RegisteredClaims{
21
  ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)), // Token berlaku 24 jam
22
  IssuedAt: jwt.NewNumericDate(time.Now()),
23
- Issuer: "qobiltu.id",
24
  },
25
  }
26
 
 
20
  RegisteredClaims: jwt.RegisteredClaims{
21
  ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24)), // Token berlaku 24 jam
22
  IssuedAt: jwt.NewNumericDate(time.Now()),
23
+ Issuer: "apqobiltu.id",
24
  },
25
  }
26
 
space/services/service.go CHANGED
@@ -16,6 +16,9 @@ type (
16
  Authenticate()
17
  Authorize()
18
  }
 
 
 
19
  Service[TConstructor any, TResult any] struct {
20
  Constructor TConstructor
21
  Result TResult
 
16
  Authenticate()
17
  Authorize()
18
  }
19
+ IService interface {
20
+ Implements()
21
+ }
22
  Service[TConstructor any, TResult any] struct {
23
  Constructor TConstructor
24
  Result TResult
space/space/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/space/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/space/space/logs/error_log.txt CHANGED
@@ -1 +1,2 @@
1
-
 
 
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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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{