lifedebugger commited on
Commit
fcff7ce
·
1 Parent(s): 32ac45b

Deploy files from GitHub repository

Browse files
controllers/academy_controller.go ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package controllers
2
+
3
+ import (
4
+ "abdanhafidz.com/go-boilerplate/models/dto"
5
+ "abdanhafidz.com/go-boilerplate/services"
6
+
7
+ "github.com/gin-gonic/gin"
8
+ "github.com/google/uuid"
9
+ )
10
+
11
+ type AcademyController interface {
12
+ CreateAcademy(ctx *gin.Context)
13
+ GetAcademy(ctx *gin.Context)
14
+ GetAcademyDetail(ctx *gin.Context)
15
+ ListAcademies(ctx *gin.Context)
16
+ UpdateAcademy(ctx *gin.Context)
17
+ DeleteAcademy(ctx *gin.Context)
18
+
19
+ CreateMaterial(ctx *gin.Context)
20
+ CreateContent(ctx *gin.Context)
21
+ }
22
+
23
+ type academyController struct {
24
+ academyService services.AcademyService
25
+ }
26
+
27
+ func NewAcademyController(academyService services.AcademyService) AcademyController {
28
+ return &academyController{academyService}
29
+ }
30
+
31
+ func (c *academyController) CreateAcademy(ctx *gin.Context) {
32
+ req := RequestJSON[dto.CreateAcademyRequest](ctx)
33
+
34
+ res, err := c.academyService.CreateAcademy(ctx.Request.Context(), req)
35
+ ResponseJSON(ctx, req, res, err)
36
+ }
37
+
38
+ func (c *academyController) GetAcademy(ctx *gin.Context) {
39
+ id, _ := uuid.Parse(ctx.Param("id"))
40
+ res, err := c.academyService.GetAcademy(ctx.Request.Context(), id)
41
+ ResponseJSON(ctx, gin.H{"id": id}, res, err)
42
+ }
43
+
44
+ func (c *academyController) GetAcademyDetail(ctx *gin.Context) {
45
+ id, _ := uuid.Parse(ctx.Param("id"))
46
+ res, err := c.academyService.GetAcademyDetail(ctx.Request.Context(), id)
47
+ ResponseJSON(ctx, gin.H{"id": id}, res, err)
48
+ }
49
+
50
+ func (c *academyController) ListAcademies(ctx *gin.Context) {
51
+ res, err := c.academyService.ListAcademies(ctx.Request.Context())
52
+ ResponseJSON(ctx, gin.H{}, res, err)
53
+ }
54
+
55
+ func (c *academyController) UpdateAcademy(ctx *gin.Context) {
56
+ id, _ := uuid.Parse(ctx.Param("id"))
57
+ req := RequestJSON[dto.UpdateAcademyRequest](ctx)
58
+ res, err := c.academyService.UpdateAcademy(ctx.Request.Context(), id, req)
59
+ ResponseJSON(ctx, req, res, err)
60
+ }
61
+
62
+ func (c *academyController) DeleteAcademy(ctx *gin.Context) {
63
+ id, _ := uuid.Parse(ctx.Param("id"))
64
+ err := c.academyService.DeleteAcademy(ctx.Request.Context(), id)
65
+
66
+ ResponseJSON(ctx, gin.H{"id": id}, gin.H{"deleted": true}, err)
67
+ }
68
+
69
+ func (c *academyController) CreateMaterial(ctx *gin.Context) {
70
+ req := RequestJSON[dto.CreateMaterialRequest](ctx)
71
+
72
+ res, err := c.academyService.CreateMaterial(ctx.Request.Context(), req)
73
+ ResponseJSON(ctx, req, res, err)
74
+ }
75
+
76
+ func (c *academyController) CreateContent(ctx *gin.Context) {
77
+ req := RequestJSON[dto.CreateContentRequest](ctx)
78
+
79
+ res, err := c.academyService.CreateContent(ctx.Request.Context(), req)
80
+ ResponseJSON(ctx, req, res, err)
81
+ }
models/dto/academy_dto.go ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package dto
2
+
3
+ import "github.com/google/uuid"
4
+
5
+ type CreateAcademyRequest struct {
6
+ Title string `json:"title" binding:"required"`
7
+ Slug string `json:"slug"`
8
+ Description string `json:"description"`
9
+ }
10
+
11
+ type UpdateAcademyRequest struct {
12
+ Title string `json:"title"`
13
+ Slug string `json:"slug"`
14
+ Description string `json:"description"`
15
+ }
16
+
17
+ type CreateMaterialRequest struct {
18
+ AcademyId uuid.UUID `json:"academy_id" binding:"required"`
19
+ Title string `json:"title" binding:"required"`
20
+ Slug string `json:"slug"`
21
+ Description string `json:"description"`
22
+ }
23
+
24
+ type CreateContentRequest struct {
25
+ AcademyMaterialId uuid.UUID `json:"academy_material_id" binding:"required"`
26
+ Title string `json:"title" binding:"required"`
27
+ Contents string `json:"contents"`
28
+ Order uint `json:"order"`
29
+ }
models/entity/entity.go CHANGED
@@ -171,8 +171,8 @@ type Academy struct {
171
  }
172
 
173
  type AcademyMaterial struct {
174
- ID uuid.UUID `gorm:"primaryKey" json:"id"`
175
- AcademyId uint `json:"academy_id"`
176
  Title string `json:"title"`
177
  Slug string `json:"slug"`
178
  Description string `json:"description"`
@@ -182,25 +182,14 @@ type AcademyContent struct {
182
  Id uuid.UUID `gorm:"primaryKey" json:"id"`
183
  Title string `json:"title"`
184
  Order uint `json:"order"`
185
- AcademyMaterialId uint `json:"academy_material_id"`
186
  Contents string `json:"contents"`
187
  }
188
 
189
- type OptionCategory struct {
190
- Id uint `gorm:"primaryKey" json:"id"`
191
- OptionName string `json:"option_name"`
192
- OptionSlug string `json:"option_slug"`
193
- }
194
-
195
- type OptionValues struct {
196
- Id uint `gorm:"primaryKey" json:"id"`
197
- OptionCategoryId uint `json:"option_category_id"`
198
- OptionValue string `json:"option_value"`
199
- }
200
  type AcademyMaterialProgress struct {
201
  Id uuid.UUID `gorm:"primaryKey" json:"id"`
202
  AccountId uint `json:"account_id"`
203
- AcademyMaterialId uint `json:"academy_material_id"`
204
  Progress uint `json:"progress"`
205
  }
206
 
@@ -210,6 +199,18 @@ type AcademyContentProgress struct {
210
  AcademyId uuid.UUID `json:"academy_id"`
211
  }
212
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  type RegionProvince struct {
214
  Id uint `json:"id"`
215
  Name string `json:"name"`
 
171
  }
172
 
173
  type AcademyMaterial struct {
174
+ Id uuid.UUID `gorm:"primaryKey" json:"id"`
175
+ AcademyId uuid.UUID `json:"academy_id"`
176
  Title string `json:"title"`
177
  Slug string `json:"slug"`
178
  Description string `json:"description"`
 
182
  Id uuid.UUID `gorm:"primaryKey" json:"id"`
183
  Title string `json:"title"`
184
  Order uint `json:"order"`
185
+ AcademyMaterialId uuid.UUID `json:"academy_material_id"`
186
  Contents string `json:"contents"`
187
  }
188
 
 
 
 
 
 
 
 
 
 
 
 
189
  type AcademyMaterialProgress struct {
190
  Id uuid.UUID `gorm:"primaryKey" json:"id"`
191
  AccountId uint `json:"account_id"`
192
+ AcademyMaterialId uuid.UUID `json:"academy_material_id"`
193
  Progress uint `json:"progress"`
194
  }
195
 
 
199
  AcademyId uuid.UUID `json:"academy_id"`
200
  }
201
 
202
+ type OptionCategory struct {
203
+ Id uint `gorm:"primaryKey" json:"id"`
204
+ OptionName string `json:"option_name"`
205
+ OptionSlug string `json:"option_slug"`
206
+ }
207
+
208
+ type OptionValues struct {
209
+ Id uint `gorm:"primaryKey" json:"id"`
210
+ OptionCategoryId uint `json:"option_category_id"`
211
+ OptionValue string `json:"option_value"`
212
+ }
213
+
214
  type RegionProvince struct {
215
  Id uint `json:"id"`
216
  Name string `json:"name"`
provider/controller_provider.go CHANGED
@@ -12,6 +12,7 @@ type ControllerProvider interface {
12
  ProvideForgotPasswordController() controllers.ForgotPasswordController
13
  ProvideOptionController() controllers.OptionController
14
  ProvideRegionController() controllers.RegionController
 
15
  }
16
 
17
  type controllerProvider struct {
@@ -22,6 +23,7 @@ type controllerProvider struct {
22
  forgotPasswordController controllers.ForgotPasswordController
23
  optionController controllers.OptionController
24
  regionController controllers.RegionController
 
25
  }
26
 
27
  func NewControllerProvider(servicesProvider ServicesProvider) ControllerProvider {
@@ -33,7 +35,7 @@ func NewControllerProvider(servicesProvider ServicesProvider) ControllerProvider
33
  forgotPasswordController := controllers.NewForgotPasswordController(servicesProvider.ProvideForgotPasswordService())
34
  optionController := controllers.NewOptionController(servicesProvider.ProvideOptionService())
35
  regionController := controllers.NewRegionController(servicesProvider.ProvideRegionService())
36
-
37
  return &controllerProvider{
38
  accountDetailController: accountDetailController,
39
  authenticationController: authenticationController,
@@ -42,6 +44,7 @@ func NewControllerProvider(servicesProvider ServicesProvider) ControllerProvider
42
  forgotPasswordController: forgotPasswordController,
43
  optionController: optionController,
44
  regionController: regionController,
 
45
  }
46
  }
47
 
@@ -74,3 +77,7 @@ func (c *controllerProvider) ProvideOptionController() controllers.OptionControl
74
  func (c *controllerProvider) ProvideRegionController() controllers.RegionController {
75
  return c.regionController
76
  }
 
 
 
 
 
12
  ProvideForgotPasswordController() controllers.ForgotPasswordController
13
  ProvideOptionController() controllers.OptionController
14
  ProvideRegionController() controllers.RegionController
15
+ ProvideAcademyController() controllers.AcademyController
16
  }
17
 
18
  type controllerProvider struct {
 
23
  forgotPasswordController controllers.ForgotPasswordController
24
  optionController controllers.OptionController
25
  regionController controllers.RegionController
26
+ academyController controllers.AcademyController
27
  }
28
 
29
  func NewControllerProvider(servicesProvider ServicesProvider) ControllerProvider {
 
35
  forgotPasswordController := controllers.NewForgotPasswordController(servicesProvider.ProvideForgotPasswordService())
36
  optionController := controllers.NewOptionController(servicesProvider.ProvideOptionService())
37
  regionController := controllers.NewRegionController(servicesProvider.ProvideRegionService())
38
+ academyController := controllers.NewAcademyController(servicesProvider.ProvideAcademyService())
39
  return &controllerProvider{
40
  accountDetailController: accountDetailController,
41
  authenticationController: authenticationController,
 
44
  forgotPasswordController: forgotPasswordController,
45
  optionController: optionController,
46
  regionController: regionController,
47
+ academyController: academyController,
48
  }
49
  }
50
 
 
77
  func (c *controllerProvider) ProvideRegionController() controllers.RegionController {
78
  return c.regionController
79
  }
80
+
81
+ func (c *controllerProvider) ProvideAcademyController() controllers.AcademyController {
82
+ return c.academyController
83
+ }
provider/repositories_provider.go CHANGED
@@ -15,6 +15,7 @@ type RepositoriesProvider interface {
15
  ProvideForgotPasswordRepository() repositories.ForgotPasswordRepository
16
  ProvideOptionRepository() repositories.OptionRepository
17
  ProvideRegionRepository() repositories.RegionRepository
 
18
  }
19
 
20
  type repositoriesProvider struct {
@@ -28,6 +29,7 @@ type repositoriesProvider struct {
28
  forgotPasswordRepository repositories.ForgotPasswordRepository
29
  optionRepository repositories.OptionRepository
30
  regionRepository repositories.RegionRepository
 
31
  }
32
 
33
  // NewRepositoriesProvider akan membuat semua repository dan inject konfigurasi database-nya.
@@ -45,8 +47,8 @@ func NewRepositoriesProvider(cfg ConfigProvider) RepositoriesProvider {
45
  forgotPasswordRepo := repositories.NewForgotPasswordRepository(db)
46
  optionRepo := repositories.NewOptionRepository(db)
47
  regionRepo := repositories.NewRegionRepository(db)
 
48
 
49
-
50
  return &repositoriesProvider{
51
  accountRepository: accountRepo,
52
  accountDetailRepository: accountDetailRepo,
@@ -58,6 +60,7 @@ func NewRepositoriesProvider(cfg ConfigProvider) RepositoriesProvider {
58
  forgotPasswordRepository: forgotPasswordRepo,
59
  optionRepository: optionRepo,
60
  regionRepository: regionRepo,
 
61
  }
62
  }
63
 
@@ -102,3 +105,7 @@ func (r *repositoriesProvider) ProvideOptionRepository() repositories.OptionRepo
102
  func (r *repositoriesProvider) ProvideRegionRepository() repositories.RegionRepository {
103
  return r.regionRepository
104
  }
 
 
 
 
 
15
  ProvideForgotPasswordRepository() repositories.ForgotPasswordRepository
16
  ProvideOptionRepository() repositories.OptionRepository
17
  ProvideRegionRepository() repositories.RegionRepository
18
+ ProvideAcademyRepository() repositories.AcademyRepository
19
  }
20
 
21
  type repositoriesProvider struct {
 
29
  forgotPasswordRepository repositories.ForgotPasswordRepository
30
  optionRepository repositories.OptionRepository
31
  regionRepository repositories.RegionRepository
32
+ academyRepository repositories.AcademyRepository
33
  }
34
 
35
  // NewRepositoriesProvider akan membuat semua repository dan inject konfigurasi database-nya.
 
47
  forgotPasswordRepo := repositories.NewForgotPasswordRepository(db)
48
  optionRepo := repositories.NewOptionRepository(db)
49
  regionRepo := repositories.NewRegionRepository(db)
50
+ academyRepo := repositories.NewAcademyRepository(db)
51
 
 
52
  return &repositoriesProvider{
53
  accountRepository: accountRepo,
54
  accountDetailRepository: accountDetailRepo,
 
60
  forgotPasswordRepository: forgotPasswordRepo,
61
  optionRepository: optionRepo,
62
  regionRepository: regionRepo,
63
+ academyRepository: academyRepo,
64
  }
65
  }
66
 
 
105
  func (r *repositoriesProvider) ProvideRegionRepository() repositories.RegionRepository {
106
  return r.regionRepository
107
  }
108
+
109
+ func (r *repositoriesProvider) ProvideAcademyRepository() repositories.AcademyRepository {
110
+ return r.academyRepository
111
+ }
provider/services_provider.go CHANGED
@@ -12,6 +12,7 @@ type ServicesProvider interface {
12
  ProvideJWTService() services.JWTService
13
  ProvideOptionService() services.OptionService
14
  ProvideRegionService() services.RegionService
 
15
  }
16
 
17
  type servicesProvider struct {
@@ -22,6 +23,7 @@ type servicesProvider struct {
22
  jwtService services.JWTService
23
  optionService services.OptionService
24
  regionService services.RegionService
 
25
  }
26
 
27
  // Konstruktor utama yang menginisialisasi semua service
@@ -33,6 +35,7 @@ func NewServicesProvider(repoProvider RepositoriesProvider, configProvider Confi
33
  forgotPasswordService := services.NewForgotPasswordService(jwtService, repoProvider.ProvideAccountRepository(), repoProvider.ProvideForgotPasswordRepository())
34
  optionService := services.NewOptionService(repoProvider.ProvideOptionRepository())
35
  regionService := services.NewRegionService(repoProvider.ProvideRegionRepository())
 
36
  return &servicesProvider{
37
  accountService: accountService,
38
  emailVerificationService: emailVerificationService,
@@ -41,6 +44,7 @@ func NewServicesProvider(repoProvider RepositoriesProvider, configProvider Confi
41
  jwtService: jwtService,
42
  optionService: optionService,
43
  regionService: regionService,
 
44
  }
45
  }
46
 
@@ -72,3 +76,7 @@ func (s *servicesProvider) ProvideOptionService() services.OptionService {
72
  func (s *servicesProvider) ProvideRegionService() services.RegionService {
73
  return s.regionService
74
  }
 
 
 
 
 
12
  ProvideJWTService() services.JWTService
13
  ProvideOptionService() services.OptionService
14
  ProvideRegionService() services.RegionService
15
+ ProvideAcademyService() services.AcademyService
16
  }
17
 
18
  type servicesProvider struct {
 
23
  jwtService services.JWTService
24
  optionService services.OptionService
25
  regionService services.RegionService
26
+ academyService services.AcademyService
27
  }
28
 
29
  // Konstruktor utama yang menginisialisasi semua service
 
35
  forgotPasswordService := services.NewForgotPasswordService(jwtService, repoProvider.ProvideAccountRepository(), repoProvider.ProvideForgotPasswordRepository())
36
  optionService := services.NewOptionService(repoProvider.ProvideOptionRepository())
37
  regionService := services.NewRegionService(repoProvider.ProvideRegionRepository())
38
+ academyService := services.NewAcademyService(repoProvider.ProvideAcademyRepository())
39
  return &servicesProvider{
40
  accountService: accountService,
41
  emailVerificationService: emailVerificationService,
 
44
  jwtService: jwtService,
45
  optionService: optionService,
46
  regionService: regionService,
47
+ academyService: academyService,
48
  }
49
  }
50
 
 
76
  func (s *servicesProvider) ProvideRegionService() services.RegionService {
77
  return s.regionService
78
  }
79
+
80
+ func (s *servicesProvider) ProvideAcademyService() services.AcademyService {
81
+ return s.academyService
82
+ }
repositories/academy_repository.go CHANGED
@@ -17,207 +17,169 @@ type AcademyRepository interface {
17
  UpdateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error)
18
  DeleteAcademy(ctx context.Context, id uuid.UUID) error
19
 
 
 
20
  // Material
21
  CreateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error)
22
  GetMaterialByID(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error)
23
  GetMaterialBySlug(ctx context.Context, slug string) (entity.AcademyMaterial, error)
24
- ListMaterialsByAcademyID(ctx context.Context, academyId uint) ([]entity.AcademyMaterial, error)
25
  UpdateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error)
26
  DeleteMaterial(ctx context.Context, id uuid.UUID) error
27
 
 
 
28
  // Content
29
  CreateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
30
  GetContentByID(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error)
31
- ListContentsByMaterialID(ctx context.Context, materialId uint) ([]entity.AcademyContent, error)
32
  UpdateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
33
  DeleteContent(ctx context.Context, id uuid.UUID) error
34
 
35
  // Progress
36
  UpsertMaterialProgress(ctx context.Context, p entity.AcademyMaterialProgress) (entity.AcademyMaterialProgress, error)
37
- GetMaterialProgress(ctx context.Context, accountId uint, materialId uint) (entity.AcademyMaterialProgress, error)
38
 
39
  UpsertContentProgress(ctx context.Context, p entity.AcademyContentProgress) (entity.AcademyContentProgress, error)
40
  GetContentProgress(ctx context.Context, accountId uuid.UUID, academyId uuid.UUID) (entity.AcademyContentProgress, error)
41
  }
42
 
43
- type academyRepository struct {
44
- db *gorm.DB
45
- }
46
 
47
  func NewAcademyRepository(db *gorm.DB) AcademyRepository {
48
  return &academyRepository{db: db}
49
  }
50
 
51
- // Academy
52
  func (r *academyRepository) CreateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error) {
53
- if err := r.db.WithContext(ctx).Create(&a).Error; err != nil {
54
- return entity.Academy{}, err
55
- }
56
- return a, nil
57
  }
58
 
59
  func (r *academyRepository) GetAcademyByID(ctx context.Context, id uuid.UUID) (entity.Academy, error) {
60
  var a entity.Academy
61
- if err := r.db.WithContext(ctx).First(&a, "id = ?", id).Error; err != nil {
62
- return entity.Academy{}, err
63
- }
64
- return a, nil
65
  }
66
 
67
  func (r *academyRepository) GetAcademyBySlug(ctx context.Context, slug string) (entity.Academy, error) {
68
  var a entity.Academy
69
- if err := r.db.WithContext(ctx).First(&a, "slug = ?", slug).Error; err != nil {
70
- return entity.Academy{}, err
71
- }
72
- return a, nil
73
  }
74
 
75
  func (r *academyRepository) ListAcademy(ctx context.Context) ([]entity.Academy, error) {
76
  var list []entity.Academy
77
- if err := r.db.WithContext(ctx).Find(&list).Error; err != nil {
78
- return nil, err
79
- }
80
- return list, nil
81
  }
82
 
83
  func (r *academyRepository) UpdateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error) {
84
- if err := r.db.WithContext(ctx).Save(&a).Error; err != nil {
85
- return entity.Academy{}, err
86
- }
87
- return a, nil
88
  }
89
 
90
  func (r *academyRepository) DeleteAcademy(ctx context.Context, id uuid.UUID) error {
91
  return r.db.WithContext(ctx).Delete(&entity.Academy{}, "id = ?", id).Error
92
  }
93
 
94
- // Material
95
- func (r *academyRepository) CreateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error) {
96
- if err := r.db.WithContext(ctx).Create(&m).Error; err != nil {
97
- return entity.AcademyMaterial{}, err
 
98
  }
99
- return m, nil
 
 
 
 
 
 
 
100
  }
101
 
102
  func (r *academyRepository) GetMaterialByID(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error) {
103
  var m entity.AcademyMaterial
104
- if err := r.db.WithContext(ctx).First(&m, "id = ?", id).Error; err != nil {
105
- return entity.AcademyMaterial{}, err
106
- }
107
- return m, nil
108
  }
109
 
110
  func (r *academyRepository) GetMaterialBySlug(ctx context.Context, slug string) (entity.AcademyMaterial, error) {
111
  var m entity.AcademyMaterial
112
- if err := r.db.WithContext(ctx).First(&m, "slug = ?", slug).Error; err != nil {
113
- return entity.AcademyMaterial{}, err
114
- }
115
- return m, nil
116
  }
117
 
118
- func (r *academyRepository) ListMaterialsByAcademyID(ctx context.Context, academyId uint) ([]entity.AcademyMaterial, error) {
119
  var list []entity.AcademyMaterial
120
- if err := r.db.WithContext(ctx).Where("academy_id = ?", academyId).Find(&list).Error; err != nil {
121
- return nil, err
122
- }
123
- return list, nil
124
  }
125
 
126
  func (r *academyRepository) UpdateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error) {
127
- if err := r.db.WithContext(ctx).Save(&m).Error; err != nil {
128
- return entity.AcademyMaterial{}, err
129
- }
130
- return m, nil
131
  }
132
 
133
  func (r *academyRepository) DeleteMaterial(ctx context.Context, id uuid.UUID) error {
134
  return r.db.WithContext(ctx).Delete(&entity.AcademyMaterial{}, "id = ?", id).Error
135
  }
136
 
137
- // Content
138
- func (r *academyRepository) CreateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error) {
139
- if err := r.db.WithContext(ctx).Create(&c).Error; err != nil {
140
- return entity.AcademyContent{}, err
 
141
  }
142
- return c, nil
 
 
 
 
 
 
 
143
  }
144
 
145
  func (r *academyRepository) GetContentByID(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error) {
146
  var c entity.AcademyContent
147
- if err := r.db.WithContext(ctx).First(&c, "id = ?", id).Error; err != nil {
148
- return entity.AcademyContent{}, err
149
- }
150
- return c, nil
151
  }
152
 
153
- func (r *academyRepository) ListContentsByMaterialID(ctx context.Context, materialId uint) ([]entity.AcademyContent, error) {
154
  var list []entity.AcademyContent
155
- if err := r.db.WithContext(ctx).Where("academy_material_id = ?", materialId).Order("order ASC").Find(&list).Error; err != nil {
156
- return nil, err
157
- }
158
- return list, nil
159
  }
160
 
161
  func (r *academyRepository) UpdateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error) {
162
- if err := r.db.WithContext(ctx).Save(&c).Error; err != nil {
163
- return entity.AcademyContent{}, err
164
- }
165
- return c, nil
166
  }
167
 
168
  func (r *academyRepository) DeleteContent(ctx context.Context, id uuid.UUID) error {
169
  return r.db.WithContext(ctx).Delete(&entity.AcademyContent{}, "id = ?", id).Error
170
  }
171
 
172
- // Progress
173
  func (r *academyRepository) UpsertMaterialProgress(ctx context.Context, p entity.AcademyMaterialProgress) (entity.AcademyMaterialProgress, error) {
174
  var existing entity.AcademyMaterialProgress
175
  err := r.db.WithContext(ctx).First(&existing, "account_id = ? AND academy_material_id = ?", p.AccountId, p.AcademyMaterialId).Error
176
- if err != nil {
177
- if err == gorm.ErrRecordNotFound {
178
- if err := r.db.WithContext(ctx).Create(&p).Error; err != nil {
179
- return entity.AcademyMaterialProgress{}, err
180
- }
181
- return p, nil
182
- }
183
- return entity.AcademyMaterialProgress{}, err
184
- }
185
- if err := r.db.WithContext(ctx).Model(&existing).Updates(p).Error; err != nil {
186
- return entity.AcademyMaterialProgress{}, err
187
  }
188
- return existing, nil
 
189
  }
190
 
191
- func (r *academyRepository) GetMaterialProgress(ctx context.Context, accountId uint, materialId uint) (entity.AcademyMaterialProgress, error) {
192
- var res entity.AcademyMaterialProgress
193
- if err := r.db.WithContext(ctx).First(&res, "account_id = ? AND academy_material_id = ?", accountId, materialId).Error; err != nil {
194
- return entity.AcademyMaterialProgress{}, err
195
- }
196
- return res, nil
197
  }
198
 
199
  func (r *academyRepository) UpsertContentProgress(ctx context.Context, p entity.AcademyContentProgress) (entity.AcademyContentProgress, error) {
200
  var existing entity.AcademyContentProgress
201
  err := r.db.WithContext(ctx).First(&existing, "account_id = ? AND academy_id = ?", p.AccountId, p.AcademyId).Error
202
- if err != nil {
203
- if err == gorm.ErrRecordNotFound {
204
- if err := r.db.WithContext(ctx).Create(&p).Error; err != nil {
205
- return entity.AcademyContentProgress{}, err
206
- }
207
- return p, nil
208
- }
209
- return entity.AcademyContentProgress{}, err
210
- }
211
- if err := r.db.WithContext(ctx).Model(&existing).Updates(p).Error; err != nil {
212
- return entity.AcademyContentProgress{}, err
213
  }
214
- return existing, nil
 
215
  }
216
 
217
  func (r *academyRepository) GetContentProgress(ctx context.Context, accountId uuid.UUID, academyId uuid.UUID) (entity.AcademyContentProgress, error) {
218
- var res entity.AcademyContentProgress
219
- if err := r.db.WithContext(ctx).First(&res, "account_id = ? AND academy_id = ?", accountId, academyId).Error; err != nil {
220
- return entity.AcademyContentProgress{}, err
221
- }
222
- return res, nil
223
  }
 
17
  UpdateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error)
18
  DeleteAcademy(ctx context.Context, id uuid.UUID) error
19
 
20
+ GetAcademyWithMaterials(ctx context.Context, id uuid.UUID) (entity.Academy, []entity.AcademyMaterial, error)
21
+
22
  // Material
23
  CreateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error)
24
  GetMaterialByID(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error)
25
  GetMaterialBySlug(ctx context.Context, slug string) (entity.AcademyMaterial, error)
26
+ ListMaterialsByAcademyID(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyMaterial, error)
27
  UpdateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error)
28
  DeleteMaterial(ctx context.Context, id uuid.UUID) error
29
 
30
+ GetMaterialWithContents(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, []entity.AcademyContent, error)
31
+
32
  // Content
33
  CreateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
34
  GetContentByID(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error)
35
+ ListContentsByMaterialID(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error)
36
  UpdateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error)
37
  DeleteContent(ctx context.Context, id uuid.UUID) error
38
 
39
  // Progress
40
  UpsertMaterialProgress(ctx context.Context, p entity.AcademyMaterialProgress) (entity.AcademyMaterialProgress, error)
41
+ GetMaterialProgress(ctx context.Context, accountId uuid.UUID, materialId uuid.UUID) (entity.AcademyMaterialProgress, error)
42
 
43
  UpsertContentProgress(ctx context.Context, p entity.AcademyContentProgress) (entity.AcademyContentProgress, error)
44
  GetContentProgress(ctx context.Context, accountId uuid.UUID, academyId uuid.UUID) (entity.AcademyContentProgress, error)
45
  }
46
 
47
+ type academyRepository struct{ db *gorm.DB }
 
 
48
 
49
  func NewAcademyRepository(db *gorm.DB) AcademyRepository {
50
  return &academyRepository{db: db}
51
  }
52
 
53
+ // ========== ACADEMY ==========
54
  func (r *academyRepository) CreateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error) {
55
+ return a, r.db.WithContext(ctx).Create(&a).Error
 
 
 
56
  }
57
 
58
  func (r *academyRepository) GetAcademyByID(ctx context.Context, id uuid.UUID) (entity.Academy, error) {
59
  var a entity.Academy
60
+ return a, r.db.WithContext(ctx).First(&a, "id = ?", id).Error
 
 
 
61
  }
62
 
63
  func (r *academyRepository) GetAcademyBySlug(ctx context.Context, slug string) (entity.Academy, error) {
64
  var a entity.Academy
65
+ return a, r.db.WithContext(ctx).First(&a, "slug = ?", slug).Error
 
 
 
66
  }
67
 
68
  func (r *academyRepository) ListAcademy(ctx context.Context) ([]entity.Academy, error) {
69
  var list []entity.Academy
70
+ return list, r.db.WithContext(ctx).Find(&list).Error
 
 
 
71
  }
72
 
73
  func (r *academyRepository) UpdateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error) {
74
+ return a, r.db.WithContext(ctx).Save(&a).Error
 
 
 
75
  }
76
 
77
  func (r *academyRepository) DeleteAcademy(ctx context.Context, id uuid.UUID) error {
78
  return r.db.WithContext(ctx).Delete(&entity.Academy{}, "id = ?", id).Error
79
  }
80
 
81
+ func (r *academyRepository) GetAcademyWithMaterials(ctx context.Context, id uuid.UUID) (entity.Academy, []entity.AcademyMaterial, error) {
82
+ var a entity.Academy
83
+ err := r.db.WithContext(ctx).First(&a, "id = ?", id).Error
84
+ if err != nil {
85
+ return entity.Academy{}, nil, err
86
  }
87
+
88
+ var m []entity.AcademyMaterial
89
+ return a, m, r.db.WithContext(ctx).Where("academy_id = ?", id).Find(&m).Error
90
+ }
91
+
92
+ // ========== MATERIAL ==========
93
+ func (r *academyRepository) CreateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error) {
94
+ return m, r.db.WithContext(ctx).Create(&m).Error
95
  }
96
 
97
  func (r *academyRepository) GetMaterialByID(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error) {
98
  var m entity.AcademyMaterial
99
+ return m, r.db.WithContext(ctx).First(&m, "id = ?", id).Error
 
 
 
100
  }
101
 
102
  func (r *academyRepository) GetMaterialBySlug(ctx context.Context, slug string) (entity.AcademyMaterial, error) {
103
  var m entity.AcademyMaterial
104
+ return m, r.db.WithContext(ctx).First(&m, "slug = ?", slug).Error
 
 
 
105
  }
106
 
107
+ func (r *academyRepository) ListMaterialsByAcademyID(ctx context.Context, academyId uuid.UUID) ([]entity.AcademyMaterial, error) {
108
  var list []entity.AcademyMaterial
109
+ return list, r.db.WithContext(ctx).Where("academy_id = ?", academyId).Find(&list).Error
 
 
 
110
  }
111
 
112
  func (r *academyRepository) UpdateMaterial(ctx context.Context, m entity.AcademyMaterial) (entity.AcademyMaterial, error) {
113
+ return m, r.db.WithContext(ctx).Save(&m).Error
 
 
 
114
  }
115
 
116
  func (r *academyRepository) DeleteMaterial(ctx context.Context, id uuid.UUID) error {
117
  return r.db.WithContext(ctx).Delete(&entity.AcademyMaterial{}, "id = ?", id).Error
118
  }
119
 
120
+ func (r *academyRepository) GetMaterialWithContents(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, []entity.AcademyContent, error) {
121
+ var m entity.AcademyMaterial
122
+ err := r.db.WithContext(ctx).First(&m, "id = ?", id).Error
123
+ if err != nil {
124
+ return entity.AcademyMaterial{}, nil, err
125
  }
126
+
127
+ var c []entity.AcademyContent
128
+ return m, c, r.db.WithContext(ctx).Where("academy_material_id = ?", id).Order("order asc").Find(&c).Error
129
+ }
130
+
131
+ // ========== CONTENT ==========
132
+ func (r *academyRepository) CreateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error) {
133
+ return c, r.db.WithContext(ctx).Create(&c).Error
134
  }
135
 
136
  func (r *academyRepository) GetContentByID(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error) {
137
  var c entity.AcademyContent
138
+ return c, r.db.WithContext(ctx).First(&c, "id = ?", id).Error
 
 
 
139
  }
140
 
141
+ func (r *academyRepository) ListContentsByMaterialID(ctx context.Context, materialId uuid.UUID) ([]entity.AcademyContent, error) {
142
  var list []entity.AcademyContent
143
+ return list, r.db.WithContext(ctx).Where("academy_material_id = ?", materialId).Order("order asc").Find(&list).Error
 
 
 
144
  }
145
 
146
  func (r *academyRepository) UpdateContent(ctx context.Context, c entity.AcademyContent) (entity.AcademyContent, error) {
147
+ return c, r.db.WithContext(ctx).Save(&c).Error
 
 
 
148
  }
149
 
150
  func (r *academyRepository) DeleteContent(ctx context.Context, id uuid.UUID) error {
151
  return r.db.WithContext(ctx).Delete(&entity.AcademyContent{}, "id = ?", id).Error
152
  }
153
 
154
+ // ========== PROGRESS ==========
155
  func (r *academyRepository) UpsertMaterialProgress(ctx context.Context, p entity.AcademyMaterialProgress) (entity.AcademyMaterialProgress, error) {
156
  var existing entity.AcademyMaterialProgress
157
  err := r.db.WithContext(ctx).First(&existing, "account_id = ? AND academy_material_id = ?", p.AccountId, p.AcademyMaterialId).Error
158
+
159
+ if err == gorm.ErrRecordNotFound {
160
+ return p, r.db.WithContext(ctx).Create(&p).Error
 
 
 
 
 
 
 
 
161
  }
162
+
163
+ return p, r.db.WithContext(ctx).Model(&existing).Updates(p).Error
164
  }
165
 
166
+ func (r *academyRepository) GetMaterialProgress(ctx context.Context, accountId uuid.UUID, materialId uuid.UUID) (entity.AcademyMaterialProgress, error) {
167
+ var p entity.AcademyMaterialProgress
168
+ return p, r.db.WithContext(ctx).First(&p, "account_id = ? AND academy_material_id = ?", accountId, materialId).Error
 
 
 
169
  }
170
 
171
  func (r *academyRepository) UpsertContentProgress(ctx context.Context, p entity.AcademyContentProgress) (entity.AcademyContentProgress, error) {
172
  var existing entity.AcademyContentProgress
173
  err := r.db.WithContext(ctx).First(&existing, "account_id = ? AND academy_id = ?", p.AccountId, p.AcademyId).Error
174
+
175
+ if err == gorm.ErrRecordNotFound {
176
+ return p, r.db.WithContext(ctx).Create(&p).Error
 
 
 
 
 
 
 
 
177
  }
178
+
179
+ return p, r.db.WithContext(ctx).Model(&existing).Updates(p).Error
180
  }
181
 
182
  func (r *academyRepository) GetContentProgress(ctx context.Context, accountId uuid.UUID, academyId uuid.UUID) (entity.AcademyContentProgress, error) {
183
+ var p entity.AcademyContentProgress
184
+ return p, r.db.WithContext(ctx).First(&p, "account_id = ? AND academy_id = ?", accountId, academyId).Error
 
 
 
185
  }
router/academy_router.go ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package router
2
+
3
+ import (
4
+ "abdanhafidz.com/go-boilerplate/provider"
5
+ "github.com/gin-gonic/gin"
6
+ )
7
+
8
+ func AcademyRouter(router *gin.Engine, middleware provider.MiddlewareProvider, controller provider.ControllerProvider) {
9
+ academyController := controller.ProvideAcademyController()
10
+ authenticationMiddleware := middleware.ProvideAuthenticationMiddleware()
11
+ routerGroup := router.Group("/api/v1/academies")
12
+ {
13
+
14
+ routerGroup.GET("/", academyController.ListAcademies)
15
+ routerGroup.POST("/", authenticationMiddleware.VerifyAccount, academyController.CreateAcademy)
16
+ routerGroup.PUT("/:id", authenticationMiddleware.VerifyAccount, academyController.UpdateAcademy)
17
+ routerGroup.DELETE("/:id", authenticationMiddleware.VerifyAccount, academyController.DeleteAcademy)
18
+ routerGroup.GET("/:id", academyController.GetAcademy)
19
+ routerGroup.GET("/:id/detail", academyController.GetAcademyDetail)
20
+ routerGroup.POST("/materials", authenticationMiddleware.VerifyAccount, academyController.CreateMaterial)
21
+ routerGroup.POST("/contents", authenticationMiddleware.VerifyAccount, academyController.CreateContent)
22
+ }
23
+ }
router/email_router.go CHANGED
@@ -5,7 +5,7 @@ import (
5
  "github.com/gin-gonic/gin"
6
  )
7
 
8
- func EmailVerificationRoute(router *gin.Engine, controller provider.ControllerProvider) {
9
  emailVerificationController := controller.ProvideEmailVerificationController()
10
  routerGroup := router.Group("/api/v1/email")
11
  {
 
5
  "github.com/gin-gonic/gin"
6
  )
7
 
8
+ func EmailVerificationRouter(router *gin.Engine, controller provider.ControllerProvider) {
9
  emailVerificationController := controller.ProvideEmailVerificationController()
10
  routerGroup := router.Group("/api/v1/email")
11
  {
router/router.go CHANGED
@@ -8,8 +8,9 @@ func RunRouter(appProvider provider.AppProvider) {
8
  router, controller, config, middleware := appProvider.ProvideRouter(), appProvider.ProvideControllers(), appProvider.ProvideConfig(), appProvider.ProvideMiddlewares()
9
  AuthenticationRouter(router, middleware, controller)
10
  AccountDetailRouter(router, middleware, controller)
11
- EmailVerificationRoute(router, controller)
12
  EventRouter(router, middleware, controller)
13
  OptionsRouter(router, controller)
 
14
  router.Run(config.ProvideEnvConfig().GetTCPAddress())
15
  }
 
8
  router, controller, config, middleware := appProvider.ProvideRouter(), appProvider.ProvideControllers(), appProvider.ProvideConfig(), appProvider.ProvideMiddlewares()
9
  AuthenticationRouter(router, middleware, controller)
10
  AccountDetailRouter(router, middleware, controller)
11
+ EmailVerificationRouter(router, controller)
12
  EventRouter(router, middleware, controller)
13
  OptionsRouter(router, controller)
14
+ AcademyRouter(router, middleware, controller)
15
  router.Run(config.ProvideEnvConfig().GetTCPAddress())
16
  }
services/academy_service.go ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package services
2
+
3
+ import (
4
+ "context"
5
+ "errors"
6
+ "strings"
7
+
8
+ "abdanhafidz.com/go-boilerplate/models/dto"
9
+ entity "abdanhafidz.com/go-boilerplate/models/entity"
10
+ "abdanhafidz.com/go-boilerplate/repositories"
11
+ "github.com/google/uuid"
12
+ "github.com/gosimple/slug"
13
+ )
14
+
15
+ type AcademyService interface {
16
+ // Academy
17
+ CreateAcademy(ctx context.Context, req dto.CreateAcademyRequest) (entity.Academy, error)
18
+ GetAcademy(ctx context.Context, id uuid.UUID) (entity.Academy, error)
19
+ ListAcademies(ctx context.Context) ([]entity.Academy, error)
20
+ GetAcademyDetail(ctx context.Context, id uuid.UUID) (entity.Academy, error)
21
+ UpdateAcademy(ctx context.Context, id uuid.UUID, req dto.UpdateAcademyRequest) (entity.Academy, error)
22
+ DeleteAcademy(ctx context.Context, id uuid.UUID) error
23
+
24
+ // Material
25
+ CreateMaterial(ctx context.Context, req dto.CreateMaterialRequest) (entity.AcademyMaterial, error)
26
+
27
+ // Content
28
+ CreateContent(ctx context.Context, req dto.CreateContentRequest) (entity.AcademyContent, error)
29
+ }
30
+ type academyService struct {
31
+ repo repositories.AcademyRepository
32
+ }
33
+
34
+ func NewAcademyService(repo repositories.AcademyRepository) AcademyService {
35
+ return &academyService{repo: repo}
36
+ }
37
+
38
+ //
39
+ // ===== Academy =====
40
+ //
41
+
42
+ func (s *academyService) CreateAcademy(ctx context.Context, req dto.CreateAcademyRequest) (entity.Academy, error) {
43
+ if strings.TrimSpace(req.Title) == "" {
44
+ return entity.Academy{}, errors.New("title required")
45
+ }
46
+
47
+ slugVal := req.Slug
48
+ if slugVal == "" {
49
+ slugVal = slug.Make(req.Title)
50
+ }
51
+
52
+ if _, err := s.repo.GetAcademyBySlug(ctx, slugVal); err == nil {
53
+ return entity.Academy{}, errors.New("slug already exists")
54
+ }
55
+
56
+ a := entity.Academy{
57
+ Title: req.Title,
58
+ Slug: slugVal,
59
+ Description: req.Description,
60
+ }
61
+
62
+ return s.repo.CreateAcademy(ctx, a)
63
+ }
64
+
65
+ func (s *academyService) GetAcademy(ctx context.Context, id uuid.UUID) (entity.Academy, error) {
66
+ return s.repo.GetAcademyByID(ctx, id)
67
+ }
68
+
69
+ func (s *academyService) ListAcademies(ctx context.Context) ([]entity.Academy, error) {
70
+ return s.repo.ListAcademy(ctx)
71
+ }
72
+
73
+ func (s *academyService) GetAcademyDetail(ctx context.Context, id uuid.UUID) (entity.Academy, error) {
74
+ a, _, err := s.repo.GetAcademyWithMaterials(ctx, id)
75
+ return a, err
76
+ }
77
+
78
+ func (s *academyService) UpdateAcademy(ctx context.Context, id uuid.UUID, req dto.UpdateAcademyRequest) (entity.Academy, error) {
79
+ existing, err := s.repo.GetAcademyByID(ctx, id)
80
+ if err != nil {
81
+ return entity.Academy{}, errors.New("academy not found")
82
+ }
83
+
84
+ if req.Title != "" {
85
+ existing.Title = req.Title
86
+ }
87
+ if req.Description != "" {
88
+ existing.Description = req.Description
89
+ }
90
+
91
+ if req.Slug != "" {
92
+ existing.Slug = req.Slug
93
+ } else {
94
+ existing.Slug = slug.Make(existing.Title)
95
+ }
96
+
97
+ return s.repo.UpdateAcademy(ctx, existing)
98
+ }
99
+
100
+ func (s *academyService) DeleteAcademy(ctx context.Context, id uuid.UUID) error {
101
+ _, mats, err := s.repo.GetAcademyWithMaterials(ctx, id)
102
+ if err != nil {
103
+ return errors.New("academy not found")
104
+ }
105
+ if len(mats) > 0 {
106
+ return errors.New("cannot delete academy with materials")
107
+ }
108
+ return s.repo.DeleteAcademy(ctx, id)
109
+ }
110
+
111
+ //
112
+ // ===== Material =====
113
+ //
114
+
115
+ func (s *academyService) CreateMaterial(ctx context.Context, req dto.CreateMaterialRequest) (entity.AcademyMaterial, error) {
116
+ if req.AcademyId == uuid.Nil {
117
+ return entity.AcademyMaterial{}, errors.New("academy_id required")
118
+ }
119
+ if _, err := s.repo.GetAcademyByID(ctx, req.AcademyId); err != nil {
120
+ return entity.AcademyMaterial{}, errors.New("academy not found")
121
+ }
122
+
123
+ slugVal := req.Slug
124
+ if slugVal == "" {
125
+ slugVal = slug.Make(req.Title)
126
+ }
127
+
128
+ m := entity.AcademyMaterial{
129
+ AcademyId: req.AcademyId,
130
+ Title: req.Title,
131
+ Slug: slugVal,
132
+ Description: req.Description,
133
+ }
134
+
135
+ return s.repo.CreateMaterial(ctx, m)
136
+ }
137
+
138
+ //
139
+ // ===== Content =====
140
+ //
141
+
142
+ func (s *academyService) CreateContent(ctx context.Context, req dto.CreateContentRequest) (entity.AcademyContent, error) {
143
+ if req.AcademyMaterialId == uuid.Nil {
144
+ return entity.AcademyContent{}, errors.New("academy_material_id required")
145
+ }
146
+
147
+ if _, err := s.repo.GetMaterialByID(ctx, req.AcademyMaterialId); err != nil {
148
+ return entity.AcademyContent{}, errors.New("material not found")
149
+ }
150
+
151
+ // auto order last++
152
+ list, _ := s.repo.ListContentsByMaterialID(ctx, req.AcademyMaterialId)
153
+ order := req.Order
154
+ if order == 0 {
155
+ order = uint(len(list) + 1)
156
+ }
157
+
158
+ c := entity.AcademyContent{
159
+ AcademyMaterialId: req.AcademyMaterialId,
160
+ Title: req.Title,
161
+ Contents: req.Contents,
162
+ Order: order,
163
+ }
164
+
165
+ return s.repo.CreateContent(ctx, c)
166
+ }
services/external_auth_service.go CHANGED
@@ -2,10 +2,13 @@ package services
2
 
3
  import (
4
  "context"
 
5
 
6
  "abdanhafidz.com/go-boilerplate/models/dto"
 
7
  "abdanhafidz.com/go-boilerplate/repositories"
8
  "google.golang.org/api/idtoken"
 
9
  )
10
 
11
  type ExternalAuthService interface {
@@ -14,36 +17,36 @@ type ExternalAuthService interface {
14
 
15
  type externalAuthService struct {
16
  jwtService JWTService
17
- accountRepo repositories.AccountRepository
18
  externalAuthRepo repositories.ExternalAuthRepository
19
  }
20
 
21
- func NewExternalAuthService(jwtService JWTService, accountRepo repositories.AccountRepository, externalAuthRepo repositories.ExternalAuthRepository) ExternalAuthService {
22
  return &externalAuthService{
23
  jwtService: jwtService,
24
- accountRepo: accountRepo,
25
  externalAuthRepo: externalAuthRepo,
26
  }
27
  }
28
 
29
  func (s *externalAuthService) GoogleAuth(ctx context.Context, idToken string) (dto.AuthenticatedUser, error) {
30
- _, err := s.externalAuthRepo.GetByOauthId(ctx, idToken)
31
-
32
- if err != nil {
33
- return dto.AuthenticatedUser{}, err
34
- }
35
-
36
- payload, err := idtoken.Validate(context.Background(), idToken, "")
37
 
38
- if err != nil {
39
- return dto.AuthenticatedUser{}, err
40
- }
 
 
 
41
 
 
42
  email := payload.Claims["email"].(string)
 
43
 
44
- acc, err := s.accountRepo.GetAccountByEmail(ctx, email)
 
 
45
 
46
- if err != nil {
47
  return dto.AuthenticatedUser{}, err
48
  }
49
 
 
2
 
3
  import (
4
  "context"
5
+ "errors"
6
 
7
  "abdanhafidz.com/go-boilerplate/models/dto"
8
+ entity "abdanhafidz.com/go-boilerplate/models/entity"
9
  "abdanhafidz.com/go-boilerplate/repositories"
10
  "google.golang.org/api/idtoken"
11
+ "gorm.io/gorm"
12
  )
13
 
14
  type ExternalAuthService interface {
 
17
 
18
  type externalAuthService struct {
19
  jwtService JWTService
20
+ accountService AccountService
21
  externalAuthRepo repositories.ExternalAuthRepository
22
  }
23
 
24
+ func NewExternalAuthService(jwtService JWTService, accountService AccountService, externalAuthRepo repositories.ExternalAuthRepository) ExternalAuthService {
25
  return &externalAuthService{
26
  jwtService: jwtService,
27
+ accountService: accountService,
28
  externalAuthRepo: externalAuthRepo,
29
  }
30
  }
31
 
32
  func (s *externalAuthService) GoogleAuth(ctx context.Context, idToken string) (dto.AuthenticatedUser, error) {
 
 
 
 
 
 
 
33
 
34
+ var (
35
+ acc entity.Account
36
+ errAcc error
37
+ )
38
+ _, err := s.externalAuthRepo.GetByOauthId(ctx, idToken)
39
+ payload, _ := idtoken.Validate(context.Background(), idToken, "")
40
 
41
+ name := payload.Claims["name"].(string)
42
  email := payload.Claims["email"].(string)
43
+ password := payload.Claims["sub"].(string)
44
 
45
+ if errors.Is(err, gorm.ErrRecordNotFound) {
46
+ acc, errAcc = s.accountService.Create(ctx, name, email, name, password)
47
+ }
48
 
49
+ if errAcc != nil {
50
  return dto.AuthenticatedUser{}, err
51
  }
52