diff --git a/app/database/entity/ppid_data_categories.entity.go b/app/database/entity/ppid_data_categories.entity.go index c61437e..f0c4b37 100644 --- a/app/database/entity/ppid_data_categories.entity.go +++ b/app/database/entity/ppid_data_categories.entity.go @@ -7,6 +7,7 @@ type PpidDataCategories struct { Title string `json:"title" gorm:"type:varchar"` Description string `json:"description" gorm:"type:varchar"` Slug string `json:"slug" gorm:"type:varchar"` + ParentId *uint `json:"parent_id" gorm:"type:int4"` ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"` IsActive *bool `json:"is_active" gorm:"type:bool;default:true"` CreatedAt time.Time `json:"created_at" gorm:"default:now()"` diff --git a/app/go-humas-be.exe b/app/go-humas-be.exe new file mode 100644 index 0000000..1fc8f85 Binary files /dev/null and b/app/go-humas-be.exe differ diff --git a/app/module/ppid_data_categories/controller/ppid_data_categories.controller.go b/app/module/ppid_data_categories/controller/ppid_data_categories.controller.go index fe71b8f..380ac68 100644 --- a/app/module/ppid_data_categories/controller/ppid_data_categories.controller.go +++ b/app/module/ppid_data_categories/controller/ppid_data_categories.controller.go @@ -18,6 +18,7 @@ type ppidDataCategoriesController struct { type PpidDataCategoriesController interface { All(c *fiber.Ctx) error Show(c *fiber.Ctx) error + ShowBySlug(c *fiber.Ctx) error Save(c *fiber.Ctx) error SaveThumbnail(c *fiber.Ctx) error Update(c *fiber.Ctx) error @@ -52,6 +53,8 @@ func (_i *ppidDataCategoriesController) All(c *fiber.Ctx) error { reqContext := request.PpidDataCategoriesQueryRequestContext{ Title: c.Query("title"), Description: c.Query("description"), + ParentId: c.Query("parentId"), + IsOnlyTop: c.Query("isOnlyTop"), } req := reqContext.ToParamRequest() req.Pagination = paginate @@ -98,6 +101,32 @@ func (_i *ppidDataCategoriesController) Show(c *fiber.Ctx) error { }) } +// ShowBySlug PpidDataCategories +// @Summary Get one PpidDataCategories +// @Description API for getting one PpidDataCategories +// @Tags PPID Categories +// @Security Bearer +// @Param slug path string true "PpidDataCategories Slug" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /ppid-data-categories/slug/{slug} [get] +func (_i *ppidDataCategoriesController) ShowBySlug(c *fiber.Ctx) error { + slug := c.Params("slug") + + ppidDataCategoriesData, err := _i.ppidDataCategoriesService.ShowBySlug(slug) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"PpidDataCategories successfully retrieved"}, + Data: ppidDataCategoriesData, + }) +} + // Save PpidDataCategories // @Summary Create PpidDataCategories // @Description API for create PpidDataCategories diff --git a/app/module/ppid_data_categories/mapper/ppid_data_categories.mapper.go b/app/module/ppid_data_categories/mapper/ppid_data_categories.mapper.go index 7ecdff2..9c676f4 100644 --- a/app/module/ppid_data_categories/mapper/ppid_data_categories.mapper.go +++ b/app/module/ppid_data_categories/mapper/ppid_data_categories.mapper.go @@ -6,8 +6,13 @@ import ( "strconv" ) -func PpidDataCategoriesResponseMapper(ppidDataCategoriesReq *entity.PpidDataCategories) (ppidDataCategoriesRes *res.PpidDataCategoriesResponse) { +func PpidDataCategoriesResponseMapper(ppidDataCategoriesReq *entity.PpidDataCategories, childPpidDataCategoriesReq []*entity.PpidDataCategories) (ppidDataCategoriesRes *res.PpidDataCategoriesResponse) { if ppidDataCategoriesReq != nil { + var childPpidDataCategoriesRes []*res.PpidDataCategoriesResponse + for _, item := range childPpidDataCategoriesReq { + childPpidDataCategoriesRes = append(childPpidDataCategoriesRes, PpidDataCategoriesResponseMapper(item, nil)) + } + ppidDataCategoriesRes = &res.PpidDataCategoriesResponse{ ID: ppidDataCategoriesReq.ID, Title: ppidDataCategoriesReq.Title, @@ -17,6 +22,8 @@ func PpidDataCategoriesResponseMapper(ppidDataCategoriesReq *entity.PpidDataCate IsActive: ppidDataCategoriesReq.IsActive, CreatedAt: ppidDataCategoriesReq.CreatedAt, UpdatedAt: ppidDataCategoriesReq.UpdatedAt, + + Children: childPpidDataCategoriesRes, } } return ppidDataCategoriesRes diff --git a/app/module/ppid_data_categories/ppid_data_categories.module.go b/app/module/ppid_data_categories/ppid_data_categories.module.go index 2f94ada..b0ee88e 100644 --- a/app/module/ppid_data_categories/ppid_data_categories.module.go +++ b/app/module/ppid_data_categories/ppid_data_categories.module.go @@ -46,6 +46,7 @@ func (_i *PpidDataCategoriesRouter) RegisterPpidDataCategoriesRoutes() { _i.App.Route("/ppid-data-categories", func(router fiber.Router) { router.Get("/", ppidDataCategoriesController.All) router.Get("/:id", ppidDataCategoriesController.Show) + router.Get("/slug/:slug", ppidDataCategoriesController.ShowBySlug) router.Post("/", ppidDataCategoriesController.Save) router.Put("/:id", ppidDataCategoriesController.Update) router.Post("/thumbnail/:id", ppidDataCategoriesController.SaveThumbnail) diff --git a/app/module/ppid_data_categories/repository/ppid_data_categories.repository.go b/app/module/ppid_data_categories/repository/ppid_data_categories.repository.go index cf639eb..9b83068 100644 --- a/app/module/ppid_data_categories/repository/ppid_data_categories.repository.go +++ b/app/module/ppid_data_categories/repository/ppid_data_categories.repository.go @@ -2,29 +2,35 @@ package repository import ( "fmt" + "github.com/rs/zerolog" "go-humas-be/app/database" "go-humas-be/app/database/entity" "go-humas-be/app/module/ppid_data_categories/request" "go-humas-be/utils/paginator" "strings" + "time" ) type ppidDataCategoriesRepository struct { - DB *database.Database + DB *database.Database + Log zerolog.Logger } // PpidDataCategoriesRepository define interface of IPpidDataCategoriesRepository type PpidDataCategoriesRepository interface { GetAll(req request.PpidDataCategoriesQueryRequest) (ppidDataCategoriess []*entity.PpidDataCategories, paging paginator.Pagination, err error) + GetAllNonPage(req request.PpidDataCategoriesQueryRequest) (ppidDataCategoriess []*entity.PpidDataCategories, paging paginator.Pagination, err error) FindOne(id uint) (ppidDataCategories *entity.PpidDataCategories, err error) + FindOneBySlug(slug string) (ppidDataCategories *entity.PpidDataCategories, err error) Create(ppidDataCategories *entity.PpidDataCategories) (err error) Update(id uint, ppidDataCategories *entity.PpidDataCategories) (err error) Delete(id uint) (err error) } -func NewPpidDataCategoriesRepository(db *database.Database) PpidDataCategoriesRepository { +func NewPpidDataCategoriesRepository(db *database.Database, logger zerolog.Logger) PpidDataCategoriesRepository { return &ppidDataCategoriesRepository{ - DB: db, + DB: db, + Log: logger, } } @@ -32,6 +38,10 @@ func NewPpidDataCategoriesRepository(db *database.Database) PpidDataCategoriesRe func (_i *ppidDataCategoriesRepository) GetAll(req request.PpidDataCategoriesQueryRequest) (ppidDataCategoriess []*entity.PpidDataCategories, paging paginator.Pagination, err error) { var count int64 + _i.Log.Info().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service:GetAll", "Interface:ppidDataCategoriesRepository"). + Interface("req", req).Msg("") + query := _i.DB.DB.Model(&entity.PpidDataCategories{}) query = query.Where("is_active = ?", true) @@ -43,6 +53,14 @@ func (_i *ppidDataCategoriesRepository) GetAll(req request.PpidDataCategoriesQue description := strings.ToLower(*req.Description) query = query.Where("LOWER(description) LIKE ?", "%"+strings.ToLower(description)+"%") } + if req.ParentId != nil { + query = query.Where("parent_id = ?", req.ParentId) + } + if req.IsOnlyTop != nil { + if *req.IsOnlyTop == true { + query = query.Where("parent_id IS NULL") + } + } query.Count(&count) if req.Pagination.SortBy != "" { @@ -66,6 +84,43 @@ func (_i *ppidDataCategoriesRepository) GetAll(req request.PpidDataCategoriesQue return } +// implement interface of IPpidDataCategoriesRepository +func (_i *ppidDataCategoriesRepository) GetAllNonPage(req request.PpidDataCategoriesQueryRequest) (ppidDataCategoriess []*entity.PpidDataCategories, paging paginator.Pagination, err error) { + var count int64 + + _i.Log.Info().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service:GetAll", "Interface:ppidDataCategoriesRepository"). + Interface("req", req).Msg("") + + query := _i.DB.DB.Model(&entity.PpidDataCategories{}) + query = query.Where("is_active = ?", true) + + if req.Title != nil && *req.Title != "" { + title := strings.ToLower(*req.Title) + query = query.Where("LOWER(title) LIKE ?", "%"+strings.ToLower(title)+"%") + } + if req.Description != nil && *req.Description != "" { + description := strings.ToLower(*req.Description) + query = query.Where("LOWER(description) LIKE ?", "%"+strings.ToLower(description)+"%") + } + if req.ParentId != nil { + query = query.Where("parent_id = ?", req.ParentId) + } + if req.IsOnlyTop != nil { + if *req.IsOnlyTop == true { + query = query.Where("parent_id IS NULL") + } + } + query.Count(&count) + + err = query.Find(&ppidDataCategoriess).Error + if err != nil { + return + } + + return +} + func (_i *ppidDataCategoriesRepository) FindOne(id uint) (ppidDataCategories *entity.PpidDataCategories, err error) { if err := _i.DB.DB.First(&ppidDataCategories, id).Error; err != nil { return nil, err @@ -74,6 +129,14 @@ func (_i *ppidDataCategoriesRepository) FindOne(id uint) (ppidDataCategories *en return ppidDataCategories, nil } +func (_i *ppidDataCategoriesRepository) FindOneBySlug(slug string) (ppidDataCategories *entity.PpidDataCategories, err error) { + if err := _i.DB.DB.Where("slug = ?", slug).First(&ppidDataCategories).Error; err != nil { + return nil, err + } + + return ppidDataCategories, nil +} + func (_i *ppidDataCategoriesRepository) Create(ppidDataCategories *entity.PpidDataCategories) (err error) { return _i.DB.DB.Create(ppidDataCategories).Error } diff --git a/app/module/ppid_data_categories/request/ppid_data_categories.request.go b/app/module/ppid_data_categories/request/ppid_data_categories.request.go index 9a1a555..82dac19 100644 --- a/app/module/ppid_data_categories/request/ppid_data_categories.request.go +++ b/app/module/ppid_data_categories/request/ppid_data_categories.request.go @@ -3,6 +3,7 @@ package request import ( "go-humas-be/app/database/entity" "go-humas-be/utils/paginator" + "strconv" "time" ) @@ -13,47 +14,51 @@ type PpidDataCategoriesGeneric interface { type PpidDataCategoriesQueryRequest struct { Title *string `json:"title"` Description *string `json:"description"` + IsOnlyTop *bool `json:"isOnlyTop"` + ParentId *uint `json:"parentId"` Pagination *paginator.Pagination `json:"pagination"` } type PpidDataCategoriesCreateRequest struct { - Title string `json:"title" validate:"required"` - Description string `json:"description" validate:"required"` - Slug string `json:"slug" validate:"required"` - ThumbnailPath *string `json:"thumbnailPath"` + Title string `json:"title" validate:"required"` + Description string `json:"description" validate:"required"` + Slug string `json:"slug" validate:"required"` + ParentId *uint `json:"parentId"` } func (req PpidDataCategoriesCreateRequest) ToEntity() *entity.PpidDataCategories { return &entity.PpidDataCategories{ - Title: req.Title, - Description: req.Description, - Slug: req.Slug, - ThumbnailPath: req.ThumbnailPath, + Title: req.Title, + Description: req.Description, + Slug: req.Slug, + ParentId: req.ParentId, } } type PpidDataCategoriesUpdateRequest struct { - ID uint `json:"id" validate:"required"` - Title string `json:"title" validate:"required"` - Description string `json:"description" validate:"required"` - Slug string `json:"slug" validate:"required"` - ThumbnailPath *string `json:"thumbnailPath"` + ID uint `json:"id" validate:"required"` + Title string `json:"title" validate:"required"` + Description string `json:"description" validate:"required"` + Slug string `json:"slug" validate:"required"` + ParentId *uint `json:"parentId"` } func (req PpidDataCategoriesUpdateRequest) ToEntity() *entity.PpidDataCategories { return &entity.PpidDataCategories{ - ID: req.ID, - Title: req.Title, - Description: req.Description, - Slug: req.Slug, - ThumbnailPath: req.ThumbnailPath, - UpdatedAt: time.Now(), + ID: req.ID, + Title: req.Title, + Description: req.Description, + Slug: req.Slug, + ParentId: req.ParentId, + UpdatedAt: time.Now(), } } type PpidDataCategoriesQueryRequestContext struct { Title string `json:"title"` Description string `json:"description"` + IsOnlyTop string `json:"isOnlyTop"` + ParentId string `json:"parentId"` } func (req PpidDataCategoriesQueryRequestContext) ToParamRequest() PpidDataCategoriesQueryRequest { @@ -65,6 +70,18 @@ func (req PpidDataCategoriesQueryRequestContext) ToParamRequest() PpidDataCatego if description := req.Description; description != "" { request.Description = &description } + if parentIdStr := req.ParentId; parentIdStr != "" { + parentId, err := strconv.ParseUint(parentIdStr, 10, 0) + if err == nil { + *request.ParentId = uint(parentId) + } + } + if isOnlyTopStr := req.IsOnlyTop; isOnlyTopStr != "" { + isOnlyTop, err := strconv.ParseBool(isOnlyTopStr) + if err == nil { + request.IsOnlyTop = &isOnlyTop + } + } return request } diff --git a/app/module/ppid_data_categories/response/ppid_data_categories.response.go b/app/module/ppid_data_categories/response/ppid_data_categories.response.go index 79db88c..d90726f 100644 --- a/app/module/ppid_data_categories/response/ppid_data_categories.response.go +++ b/app/module/ppid_data_categories/response/ppid_data_categories.response.go @@ -11,4 +11,6 @@ type PpidDataCategoriesResponse struct { IsActive *bool `json:"isActive"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` + + Children []*PpidDataCategoriesResponse `json:"children"` } diff --git a/app/module/ppid_data_categories/service/ppid_data_categories.service.go b/app/module/ppid_data_categories/service/ppid_data_categories.service.go index d98e4b7..5074799 100644 --- a/app/module/ppid_data_categories/service/ppid_data_categories.service.go +++ b/app/module/ppid_data_categories/service/ppid_data_categories.service.go @@ -32,6 +32,7 @@ type ppidDataCategoriesService struct { type PpidDataCategoriesService interface { All(req request.PpidDataCategoriesQueryRequest) (ppidDataCategories []*response.PpidDataCategoriesResponse, paging paginator.Pagination, err error) Show(id uint) (ppidDataCategories *response.PpidDataCategoriesResponse, err error) + ShowBySlug(slug string) (ppidDataCategories *response.PpidDataCategoriesResponse, err error) Save(req request.PpidDataCategoriesCreateRequest) (err error) SaveThumbnail(c *fiber.Ctx) (err error) Update(id uint, req request.PpidDataCategoriesUpdateRequest) (err error) @@ -57,7 +58,7 @@ func (_i *ppidDataCategoriesService) All(req request.PpidDataCategoriesQueryRequ } for _, result := range results { - ppidDataCategoriess = append(ppidDataCategoriess, mapper.PpidDataCategoriesResponseMapper(result)) + ppidDataCategoriess = append(ppidDataCategoriess, mapper.PpidDataCategoriesResponseMapper(result, nil)) } return @@ -69,7 +70,34 @@ func (_i *ppidDataCategoriesService) Show(id uint) (ppidDataCategories *response return nil, err } - return mapper.PpidDataCategoriesResponseMapper(result), nil + req := request.PpidDataCategoriesQueryRequest{ + ParentId: &result.ID, + } + _i.Log.Info().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service:Show", "Interface:ppidDataCategoriesService"). + Interface("req", req).Msg("") + + subResult, _, _ := _i.Repo.GetAllNonPage(req) + + _i.Log.Info().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service:Show", "Interface:ppidDataCategoriesService"). + Interface("res", subResult).Msg("") + + return mapper.PpidDataCategoriesResponseMapper(result, subResult), nil +} + +func (_i *ppidDataCategoriesService) ShowBySlug(slug string) (ppidDataCategories *response.PpidDataCategoriesResponse, err error) { + result, err := _i.Repo.FindOneBySlug(slug) + if err != nil { + return nil, err + } + + req := request.PpidDataCategoriesQueryRequest{ + ParentId: result.ParentId, + } + subResult, _, _ := _i.Repo.GetAll(req) + + return mapper.PpidDataCategoriesResponseMapper(result, subResult), nil } func (_i *ppidDataCategoriesService) Save(req request.PpidDataCategoriesCreateRequest) (err error) { diff --git a/config/toml/config.toml b/config/toml/config.toml index 5c1ea67..44d16d6 100644 --- a/config/toml/config.toml +++ b/config/toml/config.toml @@ -9,7 +9,7 @@ production = false [db.postgres] dsn = "postgresql://humas_polri:P@ssw0rd.1@103.82.242.92:5432/humas_polri" # ://:@:/ -migrate = true +migrate = false seed = false [logger] diff --git a/docs/swagger/docs.go b/docs/swagger/docs.go index d18b900..6549925 100644 --- a/docs/swagger/docs.go +++ b/docs/swagger/docs.go @@ -3638,6 +3638,16 @@ const docTemplate = `{ "name": "description", "in": "query" }, + { + "type": "boolean", + "name": "isOnlyTop", + "in": "query" + }, + { + "type": "integer", + "name": "parentId", + "in": "query" + }, { "type": "string", "name": "title", @@ -3761,6 +3771,55 @@ const docTemplate = `{ } } }, + "/ppid-data-categories/slug/{slug}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one PpidDataCategories", + "tags": [ + "PPID Categories" + ], + "summary": "Get one PpidDataCategories", + "parameters": [ + { + "type": "string", + "description": "PpidDataCategories Slug", + "name": "slug", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/ppid-data-categories/thumbnail/viewer/{id}": { "get": { "security": [ @@ -6922,10 +6981,10 @@ const docTemplate = `{ "description": { "type": "string" }, - "slug": { - "type": "string" + "parentId": { + "type": "integer" }, - "thumbnailPath": { + "slug": { "type": "string" }, "title": { @@ -6948,10 +7007,10 @@ const docTemplate = `{ "id": { "type": "integer" }, - "slug": { - "type": "string" + "parentId": { + "type": "integer" }, - "thumbnailPath": { + "slug": { "type": "string" }, "title": { diff --git a/docs/swagger/swagger.json b/docs/swagger/swagger.json index cb53610..8237f63 100644 --- a/docs/swagger/swagger.json +++ b/docs/swagger/swagger.json @@ -3627,6 +3627,16 @@ "name": "description", "in": "query" }, + { + "type": "boolean", + "name": "isOnlyTop", + "in": "query" + }, + { + "type": "integer", + "name": "parentId", + "in": "query" + }, { "type": "string", "name": "title", @@ -3750,6 +3760,55 @@ } } }, + "/ppid-data-categories/slug/{slug}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one PpidDataCategories", + "tags": [ + "PPID Categories" + ], + "summary": "Get one PpidDataCategories", + "parameters": [ + { + "type": "string", + "description": "PpidDataCategories Slug", + "name": "slug", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/ppid-data-categories/thumbnail/viewer/{id}": { "get": { "security": [ @@ -6911,10 +6970,10 @@ "description": { "type": "string" }, - "slug": { - "type": "string" + "parentId": { + "type": "integer" }, - "thumbnailPath": { + "slug": { "type": "string" }, "title": { @@ -6937,10 +6996,10 @@ "id": { "type": "integer" }, - "slug": { - "type": "string" + "parentId": { + "type": "integer" }, - "thumbnailPath": { + "slug": { "type": "string" }, "title": { diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 477f2eb..d78dcf5 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -258,10 +258,10 @@ definitions: properties: description: type: string + parentId: + type: integer slug: type: string - thumbnailPath: - type: string title: type: string required: @@ -275,10 +275,10 @@ definitions: type: string id: type: integer + parentId: + type: integer slug: type: string - thumbnailPath: - type: string title: type: string required: @@ -2926,6 +2926,12 @@ paths: - in: query name: description type: string + - in: query + name: isOnlyTop + type: boolean + - in: query + name: parentId + type: integer - in: query name: title type: string @@ -3103,6 +3109,37 @@ paths: summary: Update PpidDataCategories tags: - PPID Categories + /ppid-data-categories/slug/{slug}: + get: + description: API for getting one PpidDataCategories + parameters: + - description: PpidDataCategories Slug + in: path + name: slug + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get one PpidDataCategories + tags: + - PPID Categories /ppid-data-categories/thumbnail/{id}: post: description: API for Upload PpidDataCategories Thumbnail