Spaces:
Runtime error
Runtime error
Commit ·
fcff7ce
1
Parent(s): 32ac45b
Deploy files from GitHub repository
Browse files- controllers/academy_controller.go +81 -0
- models/dto/academy_dto.go +29 -0
- models/entity/entity.go +16 -15
- provider/controller_provider.go +8 -1
- provider/repositories_provider.go +8 -1
- provider/services_provider.go +8 -0
- repositories/academy_repository.go +65 -103
- router/academy_router.go +23 -0
- router/email_router.go +1 -1
- router/router.go +2 -1
- services/academy_service.go +166 -0
- services/external_auth_service.go +18 -15
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 |
-
|
| 175 |
-
AcademyId
|
| 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
|
| 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
|
| 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
|
| 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
|
| 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
|
| 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 |
-
//
|
| 52 |
func (r *academyRepository) CreateAcademy(ctx context.Context, a entity.Academy) (entity.Academy, error) {
|
| 53 |
-
|
| 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 |
-
|
| 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 |
-
|
| 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 |
-
|
| 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 |
-
|
| 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 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
|
|
|
| 98 |
}
|
| 99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 100 |
}
|
| 101 |
|
| 102 |
func (r *academyRepository) GetMaterialByID(ctx context.Context, id uuid.UUID) (entity.AcademyMaterial, error) {
|
| 103 |
var m entity.AcademyMaterial
|
| 104 |
-
|
| 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 |
-
|
| 113 |
-
return entity.AcademyMaterial{}, err
|
| 114 |
-
}
|
| 115 |
-
return m, nil
|
| 116 |
}
|
| 117 |
|
| 118 |
-
func (r *academyRepository) ListMaterialsByAcademyID(ctx context.Context, academyId
|
| 119 |
var list []entity.AcademyMaterial
|
| 120 |
-
|
| 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 |
-
|
| 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 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
|
|
|
| 141 |
}
|
| 142 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
}
|
| 144 |
|
| 145 |
func (r *academyRepository) GetContentByID(ctx context.Context, id uuid.UUID) (entity.AcademyContent, error) {
|
| 146 |
var c entity.AcademyContent
|
| 147 |
-
|
| 148 |
-
return entity.AcademyContent{}, err
|
| 149 |
-
}
|
| 150 |
-
return c, nil
|
| 151 |
}
|
| 152 |
|
| 153 |
-
func (r *academyRepository) ListContentsByMaterialID(ctx context.Context, materialId
|
| 154 |
var list []entity.AcademyContent
|
| 155 |
-
|
| 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 |
-
|
| 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 |
-
//
|
| 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 |
-
|
| 177 |
-
|
| 178 |
-
|
| 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 |
-
|
|
|
|
| 189 |
}
|
| 190 |
|
| 191 |
-
func (r *academyRepository) GetMaterialProgress(ctx context.Context, accountId
|
| 192 |
-
var
|
| 193 |
-
|
| 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 |
-
|
| 203 |
-
|
| 204 |
-
|
| 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 |
-
|
|
|
|
| 215 |
}
|
| 216 |
|
| 217 |
func (r *academyRepository) GetContentProgress(ctx context.Context, accountId uuid.UUID, academyId uuid.UUID) (entity.AcademyContentProgress, error) {
|
| 218 |
-
var
|
| 219 |
-
|
| 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
|
| 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 |
-
|
| 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 |
-
|
| 18 |
externalAuthRepo repositories.ExternalAuthRepository
|
| 19 |
}
|
| 20 |
|
| 21 |
-
func NewExternalAuthService(jwtService JWTService,
|
| 22 |
return &externalAuthService{
|
| 23 |
jwtService: jwtService,
|
| 24 |
-
|
| 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 |
-
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
|
|
|
| 41 |
|
|
|
|
| 42 |
email := payload.Claims["email"].(string)
|
|
|
|
| 43 |
|
| 44 |
-
|
|
|
|
|
|
|
| 45 |
|
| 46 |
-
if
|
| 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 |
|