diff --git a/app/database/entity/article_approvals.entity.go b/app/database/entity/article_approvals.entity.go new file mode 100644 index 0000000..33c3856 --- /dev/null +++ b/app/database/entity/article_approvals.entity.go @@ -0,0 +1,13 @@ +package entity + +import "time" + +type ArticleApprovals struct { + ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"` + ArticleId uint `json:"article_id" gorm:"type:int4"` + ApprovalBy uint `json:"approval_by" gorm:"type:int4"` + StatusId int `json:"status_id" gorm:"type:int4"` + Message string `json:"message" gorm:"type:varchar"` + ApprovalAtLevel int `json:"approval_at_level" gorm:"type:int4"` + CreatedAt time.Time `json:"created_at" gorm:"default:now()"` +} diff --git a/app/module/article_approvals/article_approvals.module.go b/app/module/article_approvals/article_approvals.module.go new file mode 100644 index 0000000..5d6445d --- /dev/null +++ b/app/module/article_approvals/article_approvals.module.go @@ -0,0 +1,53 @@ +package article_approvals + +import ( + "github.com/gofiber/fiber/v2" + "go-humas-be/app/module/article_approvals/controller" + "go-humas-be/app/module/article_approvals/repository" + "go-humas-be/app/module/article_approvals/service" + "go.uber.org/fx" +) + +// struct of ArticleApprovalsRouter +type ArticleApprovalsRouter struct { + App fiber.Router + Controller *controller.Controller +} + +// register bulky of ArticleApprovals module +var NewArticleApprovalsModule = fx.Options( + // register repository of ArticleApprovals module + fx.Provide(repository.NewArticleApprovalsRepository), + + // register service of ArticleApprovals module + fx.Provide(service.NewArticleApprovalsService), + + // register controller of ArticleApprovals module + fx.Provide(controller.NewController), + + // register router of ArticleApprovals module + fx.Provide(NewArticleApprovalsRouter), +) + +// init ArticleApprovalsRouter +func NewArticleApprovalsRouter(fiber *fiber.App, controller *controller.Controller) *ArticleApprovalsRouter { + return &ArticleApprovalsRouter{ + App: fiber, + Controller: controller, + } +} + +// register routes of ArticleApprovals module +func (_i *ArticleApprovalsRouter) RegisterArticleApprovalsRoutes() { + // define controllers + articleApprovalsController := _i.Controller.ArticleApprovals + + // define routes + _i.App.Route("/article-approvals", func(router fiber.Router) { + router.Get("/", articleApprovalsController.All) + router.Get("/:id", articleApprovalsController.Show) + router.Post("/", articleApprovalsController.Save) + router.Put("/:id", articleApprovalsController.Update) + router.Delete("/:id", articleApprovalsController.Delete) + }) +} diff --git a/app/module/article_approvals/controller/article_approvals.controller.go b/app/module/article_approvals/controller/article_approvals.controller.go new file mode 100644 index 0000000..d66f25a --- /dev/null +++ b/app/module/article_approvals/controller/article_approvals.controller.go @@ -0,0 +1,196 @@ +package controller + +import ( + "github.com/gofiber/fiber/v2" + "github.com/rs/zerolog" + "go-humas-be/app/module/article_approvals/request" + "go-humas-be/app/module/article_approvals/service" + "go-humas-be/utils/paginator" + "strconv" + + utilRes "go-humas-be/utils/response" + utilVal "go-humas-be/utils/validator" +) + +type articleApprovalsController struct { + articleApprovalsService service.ArticleApprovalsService + Log zerolog.Logger +} + +type ArticleApprovalsController interface { + All(c *fiber.Ctx) error + Show(c *fiber.Ctx) error + Save(c *fiber.Ctx) error + Update(c *fiber.Ctx) error + Delete(c *fiber.Ctx) error +} + +func NewArticleApprovalsController(articleApprovalsService service.ArticleApprovalsService, log zerolog.Logger) ArticleApprovalsController { + return &articleApprovalsController{ + articleApprovalsService: articleApprovalsService, + Log: log, + } +} + +// All get all ArticleApprovals +// @Summary Get all ArticleApprovals +// @Description API for getting all ArticleApprovals +// @Tags ArticleApprovals +// @Security Bearer +// @Param req query request.ArticleApprovalsQueryRequest false "query parameters" +// @Param req query paginator.Pagination false "pagination parameters" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /article-approvals [get] +func (_i *articleApprovalsController) All(c *fiber.Ctx) error { + paginate, err := paginator.Paginate(c) + if err != nil { + return err + } + + reqContext := request.ArticleApprovalsQueryRequestContext{ + ArticleId: c.Query("articleId"), + ApprovalBy: c.Query("approvalBy"), + StatusId: c.Query("statusId"), + Message: c.Query("message"), + ApprovalAtLevel: c.Query("approvalAtLevel"), + } + req := reqContext.ToParamRequest() + req.Pagination = paginate + + articleApprovalsData, paging, err := _i.articleApprovalsService.All(req) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"ArticleApprovals list successfully retrieved"}, + Data: articleApprovalsData, + Meta: paging, + }) +} + +// Show get one ArticleApprovals +// @Summary Get one ArticleApprovals +// @Description API for getting one ArticleApprovals +// @Tags ArticleApprovals +// @Security Bearer +// @Param id path int true "ArticleApprovals ID" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /article-approvals/{id} [get] +func (_i *articleApprovalsController) Show(c *fiber.Ctx) error { + id, err := strconv.ParseUint(c.Params("id"), 10, 0) + if err != nil { + return err + } + + articleApprovalsData, err := _i.articleApprovalsService.Show(uint(id)) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"ArticleApprovals successfully retrieved"}, + Data: articleApprovalsData, + }) +} + +// Save create ArticleApprovals +// @Summary Create ArticleApprovals +// @Description API for create ArticleApprovals +// @Tags ArticleApprovals +// @Security Bearer +// @Param Authorization header string true "Insert your access token" default(Bearer ) +// @Param payload body request.ArticleApprovalsCreateRequest true "Required payload" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /article-approvals [post] +func (_i *articleApprovalsController) Save(c *fiber.Ctx) error { + req := new(request.ArticleApprovalsCreateRequest) + if err := utilVal.ParseAndValidate(c, req); err != nil { + return err + } + + authToken := c.Get("Authorization") + dataResult, err := _i.articleApprovalsService.Save(*req, authToken) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"ArticleApprovals successfully created"}, + Data: dataResult, + }) +} + +// Update update ArticleApprovals +// @Summary update ArticleApprovals +// @Description API for update ArticleApprovals +// @Tags ArticleApprovals +// @Security Bearer +// @Param payload body request.ArticleApprovalsUpdateRequest true "Required payload" +// @Param id path int true "ArticleApprovals ID" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /article-approvals/{id} [put] +func (_i *articleApprovalsController) Update(c *fiber.Ctx) error { + id, err := strconv.ParseUint(c.Params("id"), 10, 0) + if err != nil { + return err + } + + req := new(request.ArticleApprovalsUpdateRequest) + if err := utilVal.ParseAndValidate(c, req); err != nil { + return err + } + + err = _i.articleApprovalsService.Update(uint(id), *req) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"ArticleApprovals successfully updated"}, + }) +} + +// Delete delete ArticleApprovals +// @Summary delete ArticleApprovals +// @Description API for delete ArticleApprovals +// @Tags ArticleApprovals +// @Security Bearer +// @Param id path int true "ArticleApprovals ID" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /article-approvals/{id} [delete] +func (_i *articleApprovalsController) Delete(c *fiber.Ctx) error { + id, err := strconv.ParseUint(c.Params("id"), 10, 0) + if err != nil { + return err + } + + err = _i.articleApprovalsService.Delete(uint(id)) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"ArticleApprovals successfully deleted"}, + }) +} diff --git a/app/module/article_approvals/controller/controller.go b/app/module/article_approvals/controller/controller.go new file mode 100644 index 0000000..08ae49c --- /dev/null +++ b/app/module/article_approvals/controller/controller.go @@ -0,0 +1,16 @@ +package controller + +import ( + "github.com/rs/zerolog" + "go-humas-be/app/module/article_approvals/service" +) + +type Controller struct { + ArticleApprovals ArticleApprovalsController +} + +func NewController(ArticleApprovalsService service.ArticleApprovalsService, log zerolog.Logger) *Controller { + return &Controller{ + ArticleApprovals: NewArticleApprovalsController(ArticleApprovalsService, log), + } +} diff --git a/app/module/article_approvals/mapper/article_approvals.mapper.go b/app/module/article_approvals/mapper/article_approvals.mapper.go new file mode 100644 index 0000000..2333f17 --- /dev/null +++ b/app/module/article_approvals/mapper/article_approvals.mapper.go @@ -0,0 +1,21 @@ +package mapper + +import ( + "go-humas-be/app/database/entity" + res "go-humas-be/app/module/article_approvals/response" +) + +func ArticleApprovalsResponseMapper(articleApprovalsReq *entity.ArticleApprovals) (articleApprovalsRes *res.ArticleApprovalsResponse) { + if articleApprovalsReq != nil { + articleApprovalsRes = &res.ArticleApprovalsResponse{ + ID: articleApprovalsReq.ID, + ArticleId: articleApprovalsReq.ArticleId, + ApprovalBy: articleApprovalsReq.ApprovalBy, + StatusId: articleApprovalsReq.StatusId, + Message: articleApprovalsReq.Message, + ApprovalAtLevel: articleApprovalsReq.ApprovalAtLevel, + CreatedAt: articleApprovalsReq.CreatedAt, + } + } + return articleApprovalsRes +} diff --git a/app/module/article_approvals/repository/article_approvals.repository.go b/app/module/article_approvals/repository/article_approvals.repository.go new file mode 100644 index 0000000..44aa3f6 --- /dev/null +++ b/app/module/article_approvals/repository/article_approvals.repository.go @@ -0,0 +1,99 @@ +package repository + +import ( + "fmt" + "github.com/rs/zerolog" + "go-humas-be/app/database" + "go-humas-be/app/database/entity" + "go-humas-be/app/module/article_approvals/request" + "go-humas-be/utils/paginator" + "strings" +) + +type articleApprovalsRepository struct { + DB *database.Database + Log zerolog.Logger +} + +// ArticleApprovalsRepository define interface of IArticleApprovalsRepository +type ArticleApprovalsRepository interface { + GetAll(req request.ArticleApprovalsQueryRequest) (articleApprovalss []*entity.ArticleApprovals, paging paginator.Pagination, err error) + FindOne(id uint) (articleApprovals *entity.ArticleApprovals, err error) + Create(articleApprovals *entity.ArticleApprovals) (articleApprovalsReturn *entity.ArticleApprovals, err error) + Update(id uint, articleApprovals *entity.ArticleApprovals) (err error) + Delete(id uint) (err error) +} + +func NewArticleApprovalsRepository(db *database.Database, logger zerolog.Logger) ArticleApprovalsRepository { + return &articleApprovalsRepository{ + DB: db, + Log: logger, + } +} + +// implement interface of IArticleApprovalsRepository +func (_i *articleApprovalsRepository) GetAll(req request.ArticleApprovalsQueryRequest) (articleApprovalss []*entity.ArticleApprovals, paging paginator.Pagination, err error) { + var count int64 + + query := _i.DB.DB.Model(&entity.ArticleApprovals{}) + if req.ArticleId != nil { + query = query.Where("article_id = ?", req.ArticleId) + } + if req.ApprovalBy != nil { + query = query.Where("approval_by = ?", req.ApprovalBy) + } + if req.StatusId != nil { + query = query.Where("status_id = ?", req.StatusId) + } + if req.Message != nil && *req.Message != "" { + message := strings.ToLower(*req.Message) + query = query.Where("LOWER(message) LIKE ?", "%"+strings.ToLower(message)+"%") + } + if req.ApprovalAtLevel != nil { + query = query.Where("approval_at_level = ?", req.ApprovalAtLevel) + } + query.Count(&count) + + if req.Pagination.SortBy != "" { + direction := "ASC" + if req.Pagination.Sort == "desc" { + direction = "DESC" + } + query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction)) + } + + req.Pagination.Count = count + req.Pagination = paginator.Paging(req.Pagination) + + err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&articleApprovalss).Error + if err != nil { + return + } + + paging = *req.Pagination + + return +} + +func (_i *articleApprovalsRepository) FindOne(id uint) (articleApprovals *entity.ArticleApprovals, err error) { + if err := _i.DB.DB.First(&articleApprovals, id).Error; err != nil { + return nil, err + } + + return articleApprovals, nil +} + +func (_i *articleApprovalsRepository) Create(articleApprovals *entity.ArticleApprovals) (articleApprovalsReturn *entity.ArticleApprovals, err error) { + result := _i.DB.DB.Create(articleApprovals) + return articleApprovals, result.Error +} + +func (_i *articleApprovalsRepository) Update(id uint, articleApprovals *entity.ArticleApprovals) (err error) { + return _i.DB.DB.Model(&entity.ArticleApprovals{}). + Where(&entity.ArticleApprovals{ID: id}). + Updates(articleApprovals).Error +} + +func (_i *articleApprovalsRepository) Delete(id uint) error { + return _i.DB.DB.Delete(&entity.ArticleApprovals{}, id).Error +} diff --git a/app/module/article_approvals/request/article_approvals.request.go b/app/module/article_approvals/request/article_approvals.request.go new file mode 100644 index 0000000..fbd959c --- /dev/null +++ b/app/module/article_approvals/request/article_approvals.request.go @@ -0,0 +1,92 @@ +package request + +import ( + "go-humas-be/app/database/entity" + "go-humas-be/utils/paginator" + "strconv" +) + +type ArticleApprovalsGeneric interface { + ToEntity() +} + +type ArticleApprovalsQueryRequest struct { + ArticleId *int `json:"articleId"` + ApprovalBy *int `json:"approvalBy"` + StatusId *int `json:"statusId"` + Message *string `json:"message"` + ApprovalAtLevel *int `json:"approvalAtLevel"` + Pagination *paginator.Pagination `json:"pagination"` +} + +type ArticleApprovalsCreateRequest struct { + ArticleId uint `json:"articleId" validate:"required"` + StatusId int `json:"statusId" validate:"required"` + Message string `json:"message" validate:"required"` +} + +func (req ArticleApprovalsCreateRequest) ToEntity() *entity.ArticleApprovals { + return &entity.ArticleApprovals{ + ArticleId: req.ArticleId, + StatusId: req.StatusId, + Message: req.Message, + } +} + +type ArticleApprovalsUpdateRequest struct { + ID uint `json:"id" validate:"required"` + ArticleId uint `json:"articleId" validate:"required"` + StatusId int `json:"statusId" validate:"required"` + Message string `json:"message" validate:"required"` +} + +func (req ArticleApprovalsUpdateRequest) ToEntity() *entity.ArticleApprovals { + return &entity.ArticleApprovals{ + ID: req.ID, + ArticleId: req.ArticleId, + StatusId: req.StatusId, + Message: req.Message, + } +} + +type ArticleApprovalsQueryRequestContext struct { + ArticleId string `json:"articleId"` + ApprovalBy string `json:"approvalBy"` + StatusId string `json:"statusId"` + Message string `json:"message"` + ApprovalAtLevel string `json:"approvalAtLevel"` +} + +func (req ArticleApprovalsQueryRequestContext) ToParamRequest() ArticleApprovalsQueryRequest { + var request ArticleApprovalsQueryRequest + + if articleIdStr := req.ArticleId; articleIdStr != "" { + articleId, err := strconv.Atoi(articleIdStr) + if err == nil { + request.ArticleId = &articleId + } + } + if approvalByStr := req.ApprovalBy; approvalByStr != "" { + approvalBy, err := strconv.Atoi(approvalByStr) + if err == nil { + request.ApprovalBy = &approvalBy + } + } + if statusIdStr := req.StatusId; statusIdStr != "" { + statusId, err := strconv.Atoi(statusIdStr) + if err == nil { + request.StatusId = &statusId + } + } + if message := req.Message; message != "" { + request.Message = &message + } + if approvalAtLevelStr := req.ApprovalAtLevel; approvalAtLevelStr != "" { + approvalAtLevel, err := strconv.Atoi(approvalAtLevelStr) + if err == nil { + request.ApprovalAtLevel = &approvalAtLevel + } + } + + return request +} diff --git a/app/module/article_approvals/response/article_approvals.response.go b/app/module/article_approvals/response/article_approvals.response.go new file mode 100644 index 0000000..1206920 --- /dev/null +++ b/app/module/article_approvals/response/article_approvals.response.go @@ -0,0 +1,13 @@ +package response + +import "time" + +type ArticleApprovalsResponse struct { + ID uint `json:"id"` + ArticleId uint `json:"articleId"` + ApprovalBy uint `json:"approvalBy"` + StatusId int `json:"statusId"` + Message string `json:"message"` + ApprovalAtLevel int `json:"approvalAtLevel"` + CreatedAt time.Time `json:"createdAt"` +} diff --git a/app/module/article_approvals/service/article_approvals.service.go b/app/module/article_approvals/service/article_approvals.service.go new file mode 100644 index 0000000..3052404 --- /dev/null +++ b/app/module/article_approvals/service/article_approvals.service.go @@ -0,0 +1,95 @@ +package service + +import ( + "github.com/rs/zerolog" + "go-humas-be/app/database/entity" + "go-humas-be/app/module/article_approvals/mapper" + "go-humas-be/app/module/article_approvals/repository" + "go-humas-be/app/module/article_approvals/request" + "go-humas-be/app/module/article_approvals/response" + articlesService "go-humas-be/app/module/articles/service" + usersRepository "go-humas-be/app/module/users/repository" + "go-humas-be/utils/paginator" + + utilSvc "go-humas-be/utils/service" +) + +// ArticleApprovalsService +type articleApprovalsService struct { + Repo repository.ArticleApprovalsRepository + UsersRepo usersRepository.UsersRepository + ArticlesService articlesService.ArticlesService + Log zerolog.Logger +} + +// ArticleApprovalsService define interface of IArticleApprovalsService +type ArticleApprovalsService interface { + All(req request.ArticleApprovalsQueryRequest) (articleApprovals []*response.ArticleApprovalsResponse, paging paginator.Pagination, err error) + Show(id uint) (articleApprovals *response.ArticleApprovalsResponse, err error) + Save(req request.ArticleApprovalsCreateRequest, authToken string) (articleApprovals *entity.ArticleApprovals, err error) + Update(id uint, req request.ArticleApprovalsUpdateRequest) (err error) + Delete(id uint) error +} + +// NewArticleApprovalsService init ArticleApprovalsService +func NewArticleApprovalsService(repo repository.ArticleApprovalsRepository, log zerolog.Logger, usersRepo usersRepository.UsersRepository, articlesSvc articlesService.ArticlesService) ArticleApprovalsService { + + return &articleApprovalsService{ + Repo: repo, + Log: log, + UsersRepo: usersRepo, + ArticlesService: articlesSvc, + } +} + +// All implement interface of ArticleApprovalsService +func (_i *articleApprovalsService) All(req request.ArticleApprovalsQueryRequest) (articleApprovalss []*response.ArticleApprovalsResponse, paging paginator.Pagination, err error) { + results, paging, err := _i.Repo.GetAll(req) + if err != nil { + return + } + + for _, result := range results { + articleApprovalss = append(articleApprovalss, mapper.ArticleApprovalsResponseMapper(result)) + } + + return +} + +func (_i *articleApprovalsService) Show(id uint) (articleApprovals *response.ArticleApprovalsResponse, err error) { + result, err := _i.Repo.FindOne(id) + if err != nil { + return nil, err + } + + return mapper.ArticleApprovalsResponseMapper(result), nil +} + +func (_i *articleApprovalsService) Save(req request.ArticleApprovalsCreateRequest, authToken string) (articleApprovals *entity.ArticleApprovals, err error) { + _i.Log.Info().Interface("data", req).Msg("") + + newReq := req.ToEntity() + + createdBy := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken) + newReq.ApprovalBy = createdBy.ID + newReq.ApprovalAtLevel = createdBy.UserLevel.LevelNumber + + approvalByUserLevelId := createdBy.UserLevelId + approvalParentLevelId := createdBy.UserLevel.ParentLevelId + + err = _i.ArticlesService.UpdateApproval(newReq.ArticleId, newReq.StatusId, int(approvalByUserLevelId), newReq.ApprovalAtLevel, *approvalParentLevelId) + if err != nil { + return nil, err + } + + return _i.Repo.Create(newReq) +} + +func (_i *articleApprovalsService) Update(id uint, req request.ArticleApprovalsUpdateRequest) (err error) { + _i.Log.Info().Interface("data", req).Msg("") + return _i.Repo.Update(id, req.ToEntity()) +} + +func (_i *articleApprovalsService) Delete(id uint) error { + return _i.Repo.Delete(id) +}