mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
feat(BE): approval_workflow, adjusment project_flocks, common, and migration
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
common "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/dto"
|
||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/validations"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/response"
|
||||
)
|
||||
|
||||
type ApprovalController struct {
|
||||
ApprovalService common.ApprovalService
|
||||
}
|
||||
|
||||
func NewApprovalController(approvalService common.ApprovalService) *ApprovalController {
|
||||
return &ApprovalController{
|
||||
ApprovalService: approvalService,
|
||||
}
|
||||
}
|
||||
|
||||
func (u *ApprovalController) GetAll(c *fiber.Ctx) error {
|
||||
moduleName := strings.TrimSpace(c.Query("module_name", ""))
|
||||
if moduleName == "" {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "`module_name` is required")
|
||||
}
|
||||
|
||||
moduleIDParam := strings.TrimSpace(c.Query("module_id", ""))
|
||||
var moduleID *uint
|
||||
if moduleIDParam != "" {
|
||||
value, err := strconv.ParseUint(moduleIDParam, 10, 64)
|
||||
if err != nil || value == 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "module_id must be a positive integer")
|
||||
}
|
||||
id := uint(value)
|
||||
moduleID = &id
|
||||
}
|
||||
|
||||
groupByStep := c.QueryBool("group_step_number", false)
|
||||
|
||||
page := c.QueryInt("page", 1)
|
||||
limit := c.QueryInt("limit", 10)
|
||||
search := strings.TrimSpace(c.Query("search", ""))
|
||||
|
||||
query := &validation.Query{
|
||||
ModuleName: moduleName,
|
||||
ModuleId: moduleID,
|
||||
GroupByStep: groupByStep,
|
||||
Page: page,
|
||||
Limit: limit,
|
||||
Search: search,
|
||||
}
|
||||
|
||||
records, totalResults, err := u.ApprovalService.List(
|
||||
c.Context(),
|
||||
query.ModuleName,
|
||||
query.ModuleId,
|
||||
query.Page,
|
||||
query.Limit,
|
||||
query.Search,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if query.GroupByStep {
|
||||
data := dto.ToApprovalGroupDTOs(records)
|
||||
return c.Status(fiber.StatusOK).
|
||||
JSON(response.SuccessWithPaginate[dto.ApprovalGroupDTO]{
|
||||
Code: fiber.StatusOK,
|
||||
Status: "success",
|
||||
Message: "Get All approvals successfully",
|
||||
Meta: response.Meta{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
|
||||
TotalResults: totalResults,
|
||||
},
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
flat := dto.ToApprovalDTOs(records)
|
||||
return c.Status(fiber.StatusOK).
|
||||
JSON(response.SuccessWithPaginate[dto.ApprovalBaseDTO]{
|
||||
Code: fiber.StatusOK,
|
||||
Status: "success",
|
||||
Message: "Get All approvals successfully",
|
||||
Meta: response.Meta{
|
||||
Page: query.Page,
|
||||
Limit: query.Limit,
|
||||
TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))),
|
||||
TotalResults: totalResults,
|
||||
},
|
||||
Data: flat,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||
approvalutils "gitlab.com/mbugroup/lti-api.git/internal/utils/approvals"
|
||||
)
|
||||
|
||||
type ApprovalBaseDTO struct {
|
||||
StepNumber uint16 `json:"step_number"`
|
||||
StepName string `json:"step_name"`
|
||||
Action *string `json:"action"`
|
||||
Notes *string `json:"notes"`
|
||||
ActionBy userDTO.UserBaseDTO `json:"action_by"`
|
||||
ActionAt time.Time `json:"action_at"`
|
||||
}
|
||||
|
||||
type ApprovalGroupDTO struct {
|
||||
StepNumber uint16 `json:"step_number"`
|
||||
StepName string `json:"step_name"`
|
||||
Approvals []ApprovalBaseDTO `json:"approvals"`
|
||||
}
|
||||
|
||||
func ToApprovalDTO(e entity.Approval) ApprovalBaseDTO {
|
||||
dto := ApprovalBaseDTO{
|
||||
Notes: e.Notes,
|
||||
}
|
||||
|
||||
if e.StepNumber > 0 {
|
||||
stepCopy := uint16(e.StepNumber)
|
||||
dto.StepNumber = stepCopy
|
||||
}
|
||||
|
||||
stepName := strings.TrimSpace(e.StepName)
|
||||
if stepName == "" && e.ApprovableType != "" && e.StepNumber > 0 {
|
||||
if label, ok := approvalutils.ApprovalStepName(approvalutils.ApprovalWorkflowKey(e.ApprovableType), approvalutils.ApprovalStep(e.StepNumber)); ok {
|
||||
stepName = label
|
||||
}
|
||||
}
|
||||
dto.StepName = stepName
|
||||
|
||||
if e.Action != nil {
|
||||
value := strings.TrimSpace(string(*e.Action))
|
||||
if value != "" {
|
||||
valueCopy := value
|
||||
dto.Action = &valueCopy
|
||||
}
|
||||
}
|
||||
|
||||
if e.ActionUser != nil && e.ActionUser.Id != 0 {
|
||||
user := userDTO.ToUserBaseDTO(*e.ActionUser)
|
||||
dto.ActionBy = user
|
||||
} else if e.ActionBy != nil && *e.ActionBy != 0 {
|
||||
dto.ActionBy = userDTO.UserBaseDTO{
|
||||
Id: *e.ActionBy,
|
||||
IdUser: int64(*e.ActionBy),
|
||||
}
|
||||
}
|
||||
|
||||
if !e.ActionAt.IsZero() {
|
||||
at := e.ActionAt
|
||||
dto.ActionAt = at
|
||||
}
|
||||
|
||||
return dto
|
||||
}
|
||||
|
||||
func ToApprovalDTOs(items []entity.Approval) []ApprovalBaseDTO {
|
||||
result := make([]ApprovalBaseDTO, len(items))
|
||||
for i, item := range items {
|
||||
result[i] = ToApprovalDTO(item)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func ToApprovalGroupDTOs(items []entity.Approval) []ApprovalGroupDTO {
|
||||
if len(items) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
type groupAccumulator struct {
|
||||
StepName string
|
||||
Approvals []ApprovalBaseDTO
|
||||
}
|
||||
|
||||
groups := make(map[uint16]*groupAccumulator)
|
||||
order := make([]uint16, 0)
|
||||
for _, item := range items {
|
||||
step := item.StepNumber
|
||||
acc, exists := groups[step]
|
||||
if !exists {
|
||||
stepName := strings.TrimSpace(item.StepName)
|
||||
if stepName == "" && item.ApprovableType != "" && item.StepNumber > 0 {
|
||||
if label, ok := approvalutils.ApprovalStepName(approvalutils.ApprovalWorkflowKey(item.ApprovableType), approvalutils.ApprovalStep(item.StepNumber)); ok {
|
||||
stepName = label
|
||||
}
|
||||
}
|
||||
acc = &groupAccumulator{StepName: stepName}
|
||||
groups[step] = acc
|
||||
order = append(order, step)
|
||||
}
|
||||
acc.Approvals = append(acc.Approvals, ToApprovalDTO(item))
|
||||
}
|
||||
|
||||
sort.Slice(order, func(i, j int) bool { return order[i] < order[j] })
|
||||
|
||||
result := make([]ApprovalGroupDTO, len(order))
|
||||
for i, step := range order {
|
||||
acc := groups[step]
|
||||
result[i] = ApprovalGroupDTO{
|
||||
StepNumber: step,
|
||||
StepName: acc.StepName,
|
||||
Approvals: acc.Approvals,
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package approvals
|
||||
|
||||
import (
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"gorm.io/gorm"
|
||||
|
||||
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
|
||||
rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories"
|
||||
sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
|
||||
)
|
||||
|
||||
type ApprovalModule struct{}
|
||||
|
||||
func (ApprovalModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *validator.Validate) {
|
||||
approvalRepo := commonRepo.NewApprovalRepository(db)
|
||||
userRepo := rUser.NewUserRepository(db)
|
||||
|
||||
approvalService := commonSvc.NewApprovalService(approvalRepo)
|
||||
userService := sUser.NewUserService(userRepo, validate)
|
||||
|
||||
ApprovalRoutes(router, userService, approvalService)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package approvals
|
||||
|
||||
import (
|
||||
// m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
common "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
controller "gitlab.com/mbugroup/lti-api.git/internal/modules/approvals/controllers"
|
||||
user "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
|
||||
)
|
||||
|
||||
func ApprovalRoutes(v1 fiber.Router, u user.UserService, s common.ApprovalService) {
|
||||
_ = u
|
||||
ctrl := controller.NewApprovalController(s)
|
||||
|
||||
route := v1.Group("/approvals")
|
||||
|
||||
route.Get("/", ctrl.GetAll)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package validation
|
||||
|
||||
type Query struct {
|
||||
ModuleName string `json:"module_name" validate:"required_strict"`
|
||||
ModuleId *uint `json:"module_id,omitempty" validate:"omitempty,gt=0"`
|
||||
GroupByStep bool `json:"group_by_step"`
|
||||
Page int `query:"page" validate:"omitempty,number,min=1"`
|
||||
Limit int `query:"limit" validate:"omitempty,number,min=1,max=100,gt=0"`
|
||||
Search string `query:"search" validate:"omitempty,max=50"`
|
||||
}
|
||||
Reference in New Issue
Block a user