feat: add menu & action module, update fixing, etc
This commit is contained in:
parent
a98517f4be
commit
bcb6326877
|
|
@ -0,0 +1,27 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MenuActions menyimpan actions yang tersedia di setiap menu
|
||||
// Contoh: Menu "Content Management" punya actions: view, create, edit, delete, approve, export
|
||||
type MenuActions struct {
|
||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||
MenuId uint `json:"menu_id" gorm:"type:int4;not null"`
|
||||
ActionCode string `json:"action_code" gorm:"type:varchar(50);not null"` // 'view', 'create', 'edit', 'delete', 'approve', 'export'
|
||||
ActionName string `json:"action_name" gorm:"type:varchar(255);not null"` // 'View Content', 'Create Content', etc.
|
||||
Description *string `json:"description" gorm:"type:text"`
|
||||
PathUrl *string `json:"path_url" gorm:"type:varchar(255)"` // Optional: untuk routing frontend
|
||||
HttpMethod *string `json:"http_method" gorm:"type:varchar(10)"` // Optional: 'GET', 'POST', 'PUT', 'DELETE'
|
||||
Position *int `json:"position" gorm:"type:int4"`
|
||||
ClientId *uuid.UUID `json:"client_id" gorm:"type:UUID"`
|
||||
IsActive *bool `json:"is_active" gorm:"type:bool;default:true"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
|
||||
// Relations
|
||||
Menu *MasterMenus `json:"menu,omitempty" gorm:"foreignKey:MenuId"`
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UserLevelMenuAccesses mengatur akses user_level ke menu tertentu
|
||||
// Contoh: UserLevel "Admin Pusat" bisa akses semua menu, "Editor" hanya bisa akses "Content Management"
|
||||
type UserLevelMenuAccesses struct {
|
||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||
UserLevelId uint `json:"user_level_id" gorm:"type:int4;not null"`
|
||||
MenuId uint `json:"menu_id" gorm:"type:int4;not null"`
|
||||
CanAccess bool `json:"can_access" gorm:"type:bool;default:true"` // Apakah boleh akses menu ini
|
||||
ClientId *uuid.UUID `json:"client_id" gorm:"type:UUID"`
|
||||
IsActive *bool `json:"is_active" gorm:"type:bool;default:true"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
|
||||
// Relations
|
||||
UserLevel *UserLevels `json:"user_level,omitempty" gorm:"foreignKey:UserLevelId"`
|
||||
Menu *MasterMenus `json:"menu,omitempty" gorm:"foreignKey:MenuId"`
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"time"
|
||||
)
|
||||
|
||||
// UserLevelMenuActionAccesses mengatur akses user_level ke action tertentu di dalam menu
|
||||
// Contoh: UserLevel "Creator" di menu "Content Management" hanya bisa create dan edit, tidak bisa delete
|
||||
type UserLevelMenuActionAccesses struct {
|
||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||
UserLevelId uint `json:"user_level_id" gorm:"type:int4;not null"`
|
||||
MenuId uint `json:"menu_id" gorm:"type:int4;not null"`
|
||||
ActionCode string `json:"action_code" gorm:"type:varchar(50);not null"` // 'view', 'create', 'edit', 'delete', etc.
|
||||
CanAccess bool `json:"can_access" gorm:"type:bool;default:true"` // Apakah boleh melakukan action ini
|
||||
ClientId *uuid.UUID `json:"client_id" gorm:"type:UUID"`
|
||||
IsActive *bool `json:"is_active" gorm:"type:bool;default:true"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
|
||||
// Relations
|
||||
UserLevel *UserLevels `json:"user_level,omitempty" gorm:"foreignKey:UserLevelId"`
|
||||
Menu *MasterMenus `json:"menu,omitempty" gorm:"foreignKey:MenuId"`
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +127,9 @@ func Models() []interface{} {
|
|||
entity.MagazineFiles{},
|
||||
entity.MasterMenus{},
|
||||
entity.MasterModules{},
|
||||
entity.MenuActions{}, // New: Menu actions (view, create, edit, delete, etc)
|
||||
entity.UserLevelMenuAccesses{}, // New: User level menu access control
|
||||
entity.UserLevelMenuActionAccesses{}, // New: User level menu action access control
|
||||
entity.MasterStatuses{},
|
||||
entity.MasterApprovalStatuses{},
|
||||
entity.Provinces{},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,169 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/database"
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type MenuActionAccessMiddleware struct {
|
||||
DB *database.Database
|
||||
}
|
||||
|
||||
func NewMenuActionAccessMiddleware(db *database.Database) *MenuActionAccessMiddleware {
|
||||
return &MenuActionAccessMiddleware{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
// CheckMenuAccess middleware untuk validasi akses user_level ke menu tertentu
|
||||
func (m *MenuActionAccessMiddleware) CheckMenuAccess(menuId uint) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Get user from context
|
||||
userCtx := c.Locals("user")
|
||||
if userCtx == nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 401,
|
||||
"messages": []string{"User tidak terautentikasi"},
|
||||
})
|
||||
}
|
||||
|
||||
user, ok := userCtx.(*entity.Users)
|
||||
if !ok || user == nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 401,
|
||||
"messages": []string{"User tidak valid"},
|
||||
})
|
||||
}
|
||||
|
||||
// Get user role untuk mendapatkan user_level_id
|
||||
var userRole entity.UserRoles
|
||||
if err := m.DB.DB.Where("id = ?", user.UserRoleId).First(&userRole).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 500,
|
||||
"messages": []string{"Error mendapatkan user role"},
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
userLevelId := userRole.UserLevelId
|
||||
|
||||
// Check akses user_level ke menu
|
||||
var access entity.UserLevelMenuAccesses
|
||||
err := m.DB.DB.Where(
|
||||
"user_level_id = ? AND menu_id = ? AND is_active = ? AND can_access = ?",
|
||||
userLevelId,
|
||||
menuId,
|
||||
true,
|
||||
true,
|
||||
).First(&access).Error
|
||||
|
||||
if err != nil {
|
||||
// Jika tidak ada record, berarti tidak ada akses
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 403,
|
||||
"messages": []string{"Anda tidak memiliki akses ke menu ini"},
|
||||
"user_level_id": userLevelId,
|
||||
"menu_id": menuId,
|
||||
})
|
||||
}
|
||||
|
||||
// Set menu ke context
|
||||
c.Locals("menu_id", menuId)
|
||||
c.Locals("user_level_id", userLevelId)
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// CheckMenuActionAccess middleware untuk validasi akses user_level ke action tertentu di dalam menu
|
||||
func (m *MenuActionAccessMiddleware) CheckMenuActionAccess(menuId uint, actionCode string) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Get user from context
|
||||
userCtx := c.Locals("user")
|
||||
if userCtx == nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 401,
|
||||
"messages": []string{"User tidak terautentikasi"},
|
||||
})
|
||||
}
|
||||
|
||||
user, ok := userCtx.(*entity.Users)
|
||||
if !ok || user == nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 401,
|
||||
"messages": []string{"User tidak valid"},
|
||||
})
|
||||
}
|
||||
|
||||
// Get user role untuk mendapatkan user_level_id
|
||||
var userRole entity.UserRoles
|
||||
if err := m.DB.DB.Where("id = ?", user.UserRoleId).First(&userRole).Error; err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 500,
|
||||
"messages": []string{"Error mendapatkan user role"},
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
userLevelId := userRole.UserLevelId
|
||||
|
||||
// First, check if user has access to the menu
|
||||
var menuAccess entity.UserLevelMenuAccesses
|
||||
err := m.DB.DB.Where(
|
||||
"user_level_id = ? AND menu_id = ? AND is_active = ? AND can_access = ?",
|
||||
userLevelId,
|
||||
menuId,
|
||||
true,
|
||||
true,
|
||||
).First(&menuAccess).Error
|
||||
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 403,
|
||||
"messages": []string{"Anda tidak memiliki akses ke menu ini"},
|
||||
"user_level_id": userLevelId,
|
||||
"menu_id": menuId,
|
||||
})
|
||||
}
|
||||
|
||||
// Then, check if user has access to the specific action
|
||||
var actionAccess entity.UserLevelMenuActionAccesses
|
||||
err = m.DB.DB.Where(
|
||||
"user_level_id = ? AND menu_id = ? AND action_code = ? AND is_active = ? AND can_access = ?",
|
||||
userLevelId,
|
||||
menuId,
|
||||
actionCode,
|
||||
true,
|
||||
true,
|
||||
).First(&actionAccess).Error
|
||||
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 403,
|
||||
"messages": []string{"Anda tidak memiliki akses untuk melakukan action ini"},
|
||||
"user_level_id": userLevelId,
|
||||
"menu_id": menuId,
|
||||
"action_code": actionCode,
|
||||
})
|
||||
}
|
||||
|
||||
// Set to context
|
||||
c.Locals("menu_id", menuId)
|
||||
c.Locals("action_code", actionCode)
|
||||
c.Locals("user_level_id", userLevelId)
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -13,6 +13,7 @@ func MasterMenusResponseMapper(masterMenusReq *entity.MasterMenus) (masterMenusR
|
|||
Description: masterMenusReq.Description,
|
||||
ModuleId: masterMenusReq.ModuleId,
|
||||
ParentMenuId: masterMenusReq.ParentMenuId,
|
||||
Group: masterMenusReq.Group,
|
||||
Icon: masterMenusReq.Icon,
|
||||
Position: masterMenusReq.Position,
|
||||
StatusId: masterMenusReq.StatusId,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import (
|
|||
"netidhub-saas-be/app/module/master_menus/request"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type masterMenusRepository struct {
|
||||
|
|
@ -87,6 +89,10 @@ func (_i *masterMenusRepository) FindOne(id uint) (masterMenus *entity.MasterMen
|
|||
func (_i *masterMenusRepository) FindLastMenuPosition() (position *int, err error) {
|
||||
var masterMenus *entity.MasterMenus
|
||||
if err := _i.DB.DB.Where("position IS NOT NULL").Order(fmt.Sprintf("%s %s", "position", "DESC")).First(&masterMenus).Error; err != nil {
|
||||
// If no record found, return nil without error (it's expected when no menus exist yet)
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,18 +23,22 @@ type MasterMenusQueryRequest struct {
|
|||
type MasterMenusCreateRequest struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Description string `json:"description" validate:"required"`
|
||||
ModuleId int `json:"moduleId" validate:"required"`
|
||||
ModuleId *int `json:"moduleId,omitempty"`
|
||||
Group string `json:"group" validate:"required"`
|
||||
StatusId int `json:"statusId" validate:"required"`
|
||||
ParentMenuId *int `json:"parentMenuId"`
|
||||
Icon *string `json:"icon"`
|
||||
ParentMenuId *int `json:"parentMenuId,omitempty"`
|
||||
Icon *string `json:"icon,omitempty"`
|
||||
}
|
||||
|
||||
func (req MasterMenusCreateRequest) ToEntity() *entity.MasterMenus {
|
||||
moduleId := 0
|
||||
if req.ModuleId != nil {
|
||||
moduleId = *req.ModuleId
|
||||
}
|
||||
return &entity.MasterMenus{
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
ModuleId: req.ModuleId,
|
||||
ModuleId: moduleId,
|
||||
ParentMenuId: req.ParentMenuId,
|
||||
Icon: req.Icon,
|
||||
Group: req.Group,
|
||||
|
|
@ -46,20 +50,24 @@ type MasterMenusUpdateRequest struct {
|
|||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Description string `json:"description" validate:"required"`
|
||||
ModuleId int `json:"moduleId" validate:"required"`
|
||||
ModuleId *int `json:"moduleId,omitempty"`
|
||||
Group string `json:"group" validate:"required"`
|
||||
StatusId int `json:"statusId" validate:"required"`
|
||||
ParentMenuId *int `json:"parentMenuId"`
|
||||
Icon *string `json:"icon"`
|
||||
ParentMenuId *int `json:"parentMenuId,omitempty"`
|
||||
Icon *string `json:"icon,omitempty"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
func (req MasterMenusUpdateRequest) ToEntity() *entity.MasterMenus {
|
||||
moduleId := 0
|
||||
if req.ModuleId != nil {
|
||||
moduleId = *req.ModuleId
|
||||
}
|
||||
return &entity.MasterMenus{
|
||||
ID: req.ID,
|
||||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
ModuleId: req.ModuleId,
|
||||
ModuleId: moduleId,
|
||||
ParentMenuId: req.ParentMenuId,
|
||||
Icon: req.Icon,
|
||||
Group: req.Group,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ type MasterMenusResponse struct {
|
|||
Description string `json:"description"`
|
||||
ModuleId int `json:"module_id"`
|
||||
ParentMenuId *int `json:"parent_menu_id"`
|
||||
Group string `json:"group"`
|
||||
Icon *string `json:"icon"`
|
||||
Position *int `json:"position"`
|
||||
StatusId int `json:"status_id"`
|
||||
|
|
|
|||
|
|
@ -60,14 +60,19 @@ func (_i *masterMenusService) Save(req request.MasterMenusCreateRequest) (err er
|
|||
_i.Log.Info().Interface("data", req).Msg("")
|
||||
|
||||
newReq := req.ToEntity()
|
||||
var latestPosition, _ = _i.Repo.FindLastMenuPosition()
|
||||
latestPosition, err := _i.Repo.FindLastMenuPosition()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*latestPosition = *latestPosition + 1
|
||||
|
||||
if latestPosition != nil {
|
||||
newReq.Position = latestPosition
|
||||
// If no menu with position exists, start with position 1
|
||||
position := 1
|
||||
newReq.Position = &position
|
||||
} else if latestPosition != nil {
|
||||
// Increment the latest position
|
||||
newPosition := *latestPosition + 1
|
||||
newReq.Position = &newPosition
|
||||
} else {
|
||||
// Fallback: set position to 1
|
||||
position := 1
|
||||
newReq.Position = &position
|
||||
}
|
||||
|
||||
return _i.Repo.Create(newReq)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ func MasterModulesResponseMapper(masterModulesReq *entity.MasterModules) (master
|
|||
Name: masterModulesReq.Name,
|
||||
Description: masterModulesReq.Description,
|
||||
PathUrl: masterModulesReq.PathUrl,
|
||||
ActionType: masterModulesReq.ActionType,
|
||||
StatusId: masterModulesReq.StatusId,
|
||||
IsActive: masterModulesReq.IsActive,
|
||||
CreatedAt: masterModulesReq.CreatedAt,
|
||||
|
|
|
|||
|
|
@ -19,10 +19,12 @@ type MasterModulesQueryRequest struct {
|
|||
}
|
||||
|
||||
type MasterModulesCreateRequest struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Description string `json:"description" validate:"required"`
|
||||
PathUrl string `json:"pathUrl" validate:"required"`
|
||||
StatusId int `json:"statusId" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Description string `json:"description" validate:"required"`
|
||||
PathUrl string `json:"pathUrl" validate:"required"`
|
||||
ActionType *string `json:"actionType"`
|
||||
StatusId int `json:"statusId" validate:"required"`
|
||||
MenuIds []int `json:"menuIds"` // Optional: untuk langsung assign ke menu saat create
|
||||
}
|
||||
|
||||
func (req MasterModulesCreateRequest) ToEntity() *entity.MasterModules {
|
||||
|
|
@ -30,16 +32,19 @@ func (req MasterModulesCreateRequest) ToEntity() *entity.MasterModules {
|
|||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
PathUrl: req.PathUrl,
|
||||
ActionType: req.ActionType,
|
||||
StatusId: req.StatusId,
|
||||
}
|
||||
}
|
||||
|
||||
type MasterModulesUpdateRequest struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Description string `json:"description" validate:"required"`
|
||||
PathUrl string `json:"pathUrl" validate:"required"`
|
||||
StatusId int `json:"statusId" validate:"required"`
|
||||
ID uint `json:"id" validate:"required"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Description string `json:"description" validate:"required"`
|
||||
PathUrl string `json:"pathUrl" validate:"required"`
|
||||
ActionType *string `json:"actionType"`
|
||||
StatusId int `json:"statusId" validate:"required"`
|
||||
MenuIds []int `json:"menuIds"` // Optional: untuk update relasi dengan menu
|
||||
}
|
||||
|
||||
func (req MasterModulesUpdateRequest) ToEntity() *entity.MasterModules {
|
||||
|
|
@ -48,6 +53,7 @@ func (req MasterModulesUpdateRequest) ToEntity() *entity.MasterModules {
|
|||
Name: req.Name,
|
||||
Description: req.Description,
|
||||
PathUrl: req.PathUrl,
|
||||
ActionType: req.ActionType,
|
||||
StatusId: req.StatusId,
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ type MasterModulesResponse struct {
|
|||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
PathUrl string `json:"path_url"`
|
||||
ActionType *string `json:"action_type"`
|
||||
StatusId int `json:"status_id"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/module/menu_actions/service"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
MenuActions MenuActionsController
|
||||
}
|
||||
|
||||
func NewController(menuActionsService service.MenuActionsService) *Controller {
|
||||
return &Controller{
|
||||
MenuActions: NewMenuActionsController(menuActionsService),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/module/menu_actions/request"
|
||||
"netidhub-saas-be/app/module/menu_actions/service"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
utilRes "netidhub-saas-be/utils/response"
|
||||
utilVal "netidhub-saas-be/utils/validator"
|
||||
)
|
||||
|
||||
type menuActionsController struct {
|
||||
menuActionsService service.MenuActionsService
|
||||
}
|
||||
|
||||
type MenuActionsController interface {
|
||||
All(c *fiber.Ctx) error
|
||||
GetByMenuId(c *fiber.Ctx) error
|
||||
Show(c *fiber.Ctx) error
|
||||
Save(c *fiber.Ctx) error
|
||||
SaveBatch(c *fiber.Ctx) error
|
||||
Update(c *fiber.Ctx) error
|
||||
Delete(c *fiber.Ctx) error
|
||||
}
|
||||
|
||||
func NewMenuActionsController(menuActionsService service.MenuActionsService) MenuActionsController {
|
||||
return &menuActionsController{
|
||||
menuActionsService: menuActionsService,
|
||||
}
|
||||
}
|
||||
|
||||
// All MenuActions
|
||||
// @Summary Get all MenuActions
|
||||
// @Description API for getting all MenuActions
|
||||
// @Tags MenuActions
|
||||
// @Security Bearer
|
||||
// @Param menu_id query int false "Menu ID"
|
||||
// @Param action_code query string false "Action Code"
|
||||
// @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 /menu-actions [get]
|
||||
func (_i *menuActionsController) All(c *fiber.Ctx) error {
|
||||
paginate, err := paginator.Paginate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := request.MenuActionsQueryRequest{
|
||||
Pagination: paginate,
|
||||
}
|
||||
|
||||
if menuId := c.Query("menu_id"); menuId != "" {
|
||||
id, _ := strconv.ParseUint(menuId, 10, 0)
|
||||
menuIdUint := uint(id)
|
||||
req.MenuId = &menuIdUint
|
||||
}
|
||||
|
||||
if actionCode := c.Query("action_code"); actionCode != "" {
|
||||
req.ActionCode = &actionCode
|
||||
}
|
||||
|
||||
menuActionsData, paging, err := _i.menuActionsService.All(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"MenuActions list successfully retrieved"},
|
||||
Data: menuActionsData,
|
||||
Meta: paging,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByMenuId get MenuActions by Menu ID
|
||||
// @Summary Get MenuActions by Menu ID
|
||||
// @Description API for getting MenuActions by Menu ID
|
||||
// @Tags MenuActions
|
||||
// @Security Bearer
|
||||
// @Param menu_id path int true "Menu ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /menu-actions/menu/{menu_id} [get]
|
||||
func (_i *menuActionsController) GetByMenuId(c *fiber.Ctx) error {
|
||||
menuId, err := strconv.ParseUint(c.Params("menu_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
menuActionsData, err := _i.menuActionsService.GetByMenuId(uint(menuId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"MenuActions by menu successfully retrieved"},
|
||||
Data: menuActionsData,
|
||||
})
|
||||
}
|
||||
|
||||
// Show get one MenuAction
|
||||
// @Summary Get one MenuAction
|
||||
// @Description API for getting one MenuAction
|
||||
// @Tags MenuActions
|
||||
// @Security Bearer
|
||||
// @Param id path int true "MenuAction ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /menu-actions/{id} [get]
|
||||
func (_i *menuActionsController) Show(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
menuActionData, err := _i.menuActionsService.Show(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"MenuAction successfully retrieved"},
|
||||
Data: menuActionData,
|
||||
})
|
||||
}
|
||||
|
||||
// Save create MenuAction
|
||||
// @Summary Create MenuAction
|
||||
// @Description API for create MenuAction
|
||||
// @Tags MenuActions
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param payload body request.MenuActionsCreateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /menu-actions [post]
|
||||
func (_i *menuActionsController) Save(c *fiber.Ctx) error {
|
||||
req := new(request.MenuActionsCreateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := _i.menuActionsService.Save(*req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"MenuAction successfully created"},
|
||||
})
|
||||
}
|
||||
|
||||
// SaveBatch create MenuActions batch
|
||||
// @Summary Create MenuActions batch
|
||||
// @Description API for create MenuActions batch
|
||||
// @Tags MenuActions
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param payload body request.MenuActionsBatchCreateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /menu-actions/batch [post]
|
||||
func (_i *menuActionsController) SaveBatch(c *fiber.Ctx) error {
|
||||
req := new(request.MenuActionsBatchCreateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := _i.menuActionsService.SaveBatch(*req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"MenuActions batch successfully created"},
|
||||
})
|
||||
}
|
||||
|
||||
// Update MenuAction
|
||||
// @Summary Update MenuAction
|
||||
// @Description API for update MenuAction
|
||||
// @Tags MenuActions
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param id path int true "MenuAction ID"
|
||||
// @Param payload body request.MenuActionsUpdateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /menu-actions/{id} [put]
|
||||
func (_i *menuActionsController) Update(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := new(request.MenuActionsUpdateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = _i.menuActionsService.Update(uint(id), *req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"MenuAction successfully updated"},
|
||||
})
|
||||
}
|
||||
|
||||
// Delete MenuAction
|
||||
// @Summary Delete MenuAction
|
||||
// @Description API for delete MenuAction
|
||||
// @Tags MenuActions
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param id path int true "MenuAction ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /menu-actions/{id} [delete]
|
||||
func (_i *menuActionsController) Delete(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = _i.menuActionsService.Delete(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"MenuAction successfully deleted"},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package mapper
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
res "netidhub-saas-be/app/module/menu_actions/response"
|
||||
)
|
||||
|
||||
func MenuActionsResponseMapper(menuActionReq *entity.MenuActions) (menuActionRes *res.MenuActionsResponse) {
|
||||
if menuActionReq != nil {
|
||||
menuActionRes = &res.MenuActionsResponse{
|
||||
ID: menuActionReq.ID,
|
||||
MenuId: menuActionReq.MenuId,
|
||||
ActionCode: menuActionReq.ActionCode,
|
||||
ActionName: menuActionReq.ActionName,
|
||||
Description: menuActionReq.Description,
|
||||
PathUrl: menuActionReq.PathUrl,
|
||||
HttpMethod: menuActionReq.HttpMethod,
|
||||
Position: menuActionReq.Position,
|
||||
IsActive: menuActionReq.IsActive,
|
||||
CreatedAt: menuActionReq.CreatedAt,
|
||||
UpdatedAt: menuActionReq.UpdatedAt,
|
||||
}
|
||||
}
|
||||
return menuActionRes
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package menu_actions
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/fx"
|
||||
"netidhub-saas-be/app/module/menu_actions/controller"
|
||||
"netidhub-saas-be/app/module/menu_actions/repository"
|
||||
"netidhub-saas-be/app/module/menu_actions/service"
|
||||
)
|
||||
|
||||
// struct of MenuActionsRouter
|
||||
type MenuActionsRouter struct {
|
||||
App fiber.Router
|
||||
Controller *controller.Controller
|
||||
}
|
||||
|
||||
// register bulky of MenuActions module
|
||||
var NewMenuActionsModule = fx.Options(
|
||||
// register repository of MenuActions module
|
||||
fx.Provide(repository.NewMenuActionsRepository),
|
||||
|
||||
// register service of MenuActions module
|
||||
fx.Provide(service.NewMenuActionsService),
|
||||
|
||||
// register controller of MenuActions module
|
||||
fx.Provide(controller.NewController),
|
||||
|
||||
// register router of MenuActions module
|
||||
fx.Provide(NewMenuActionsRouter),
|
||||
)
|
||||
|
||||
// init MenuActionsRouter
|
||||
func NewMenuActionsRouter(fiber *fiber.App, controller *controller.Controller) *MenuActionsRouter {
|
||||
return &MenuActionsRouter{
|
||||
App: fiber,
|
||||
Controller: controller,
|
||||
}
|
||||
}
|
||||
|
||||
// register routes of MenuActions module
|
||||
func (_i *MenuActionsRouter) RegisterMenuActionsRoutes() {
|
||||
// define controllers
|
||||
menuActionsController := _i.Controller.MenuActions
|
||||
|
||||
// define routes
|
||||
_i.App.Route("/menu-actions", func(router fiber.Router) {
|
||||
router.Get("/", menuActionsController.All)
|
||||
router.Get("/:id", menuActionsController.Show)
|
||||
router.Get("/menu/:menu_id", menuActionsController.GetByMenuId)
|
||||
router.Post("/", menuActionsController.Save)
|
||||
router.Post("/batch", menuActionsController.SaveBatch)
|
||||
router.Put("/:id", menuActionsController.Update)
|
||||
router.Delete("/:id", menuActionsController.Delete)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"netidhub-saas-be/app/database"
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
"netidhub-saas-be/app/module/menu_actions/request"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
)
|
||||
|
||||
type menuActionsRepository struct {
|
||||
DB *database.Database
|
||||
}
|
||||
|
||||
// MenuActionsRepository define interface of IMenuActionsRepository
|
||||
type MenuActionsRepository interface {
|
||||
GetAll(req request.MenuActionsQueryRequest) (menuActions []*entity.MenuActions, paging paginator.Pagination, err error)
|
||||
GetByMenuId(menuId uint) (menuActions []*entity.MenuActions, err error)
|
||||
GetByActionCode(menuId uint, actionCode string) (menuAction *entity.MenuActions, err error)
|
||||
FindOne(id uint) (menuAction *entity.MenuActions, err error)
|
||||
Create(menuAction *entity.MenuActions) (err error)
|
||||
CreateBatch(menuActions []*entity.MenuActions) (err error)
|
||||
Update(id uint, menuAction *entity.MenuActions) (err error)
|
||||
Delete(id uint) (err error)
|
||||
DeleteByMenuId(menuId uint) (err error)
|
||||
}
|
||||
|
||||
func NewMenuActionsRepository(db *database.Database) MenuActionsRepository {
|
||||
return &menuActionsRepository{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
// implement interface of IMenuActionsRepository
|
||||
func (_i *menuActionsRepository) GetAll(req request.MenuActionsQueryRequest) (menuActions []*entity.MenuActions, paging paginator.Pagination, err error) {
|
||||
var count int64
|
||||
|
||||
query := _i.DB.DB.Model(&entity.MenuActions{})
|
||||
query = query.Where("is_active = ?", true)
|
||||
|
||||
if req.MenuId != nil {
|
||||
query = query.Where("menu_id = ?", req.MenuId)
|
||||
}
|
||||
if req.ActionCode != nil && *req.ActionCode != "" {
|
||||
query = query.Where("action_code = ?", req.ActionCode)
|
||||
}
|
||||
if req.ClientId != nil {
|
||||
query = query.Where("client_id = ?", req.ClientId)
|
||||
}
|
||||
|
||||
// Preload relations
|
||||
query = query.Preload("Menu")
|
||||
|
||||
query.Count(&count)
|
||||
|
||||
// Apply sorting
|
||||
if req.Pagination.SortBy != "" {
|
||||
direction := "ASC"
|
||||
if req.Pagination.Sort == "desc" {
|
||||
direction = "DESC"
|
||||
}
|
||||
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
||||
} else {
|
||||
query.Order("position ASC")
|
||||
}
|
||||
|
||||
// Apply pagination (manual calculation like articles)
|
||||
page := req.Pagination.Page
|
||||
limit := req.Pagination.Limit
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
offset := (page - 1) * limit
|
||||
err = query.Offset(offset).Limit(limit).Find(&menuActions).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Create pagination response
|
||||
paging = paginator.Pagination{
|
||||
Page: page,
|
||||
Limit: limit,
|
||||
Count: count,
|
||||
TotalPage: int((count + int64(limit) - 1) / int64(limit)),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *menuActionsRepository) GetByMenuId(menuId uint) (menuActions []*entity.MenuActions, err error) {
|
||||
query := _i.DB.DB.Model(&entity.MenuActions{})
|
||||
query = query.Where("menu_id = ? AND is_active = ?", menuId, true)
|
||||
query = query.Preload("Menu")
|
||||
query = query.Order("position ASC")
|
||||
err = query.Find(&menuActions).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *menuActionsRepository) GetByActionCode(menuId uint, actionCode string) (menuAction *entity.MenuActions, err error) {
|
||||
query := _i.DB.DB.Model(&entity.MenuActions{})
|
||||
query = query.Where("menu_id = ? AND action_code = ? AND is_active = ?", menuId, actionCode, true)
|
||||
query = query.Preload("Menu")
|
||||
err = query.First(&menuAction).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *menuActionsRepository) FindOne(id uint) (menuAction *entity.MenuActions, err error) {
|
||||
query := _i.DB.DB.Preload("Menu")
|
||||
if err := query.First(&menuAction, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return menuAction, nil
|
||||
}
|
||||
|
||||
func (_i *menuActionsRepository) Create(menuAction *entity.MenuActions) (err error) {
|
||||
return _i.DB.DB.Create(menuAction).Error
|
||||
}
|
||||
|
||||
func (_i *menuActionsRepository) CreateBatch(menuActions []*entity.MenuActions) (err error) {
|
||||
return _i.DB.DB.Create(&menuActions).Error
|
||||
}
|
||||
|
||||
func (_i *menuActionsRepository) Update(id uint, menuAction *entity.MenuActions) (err error) {
|
||||
return _i.DB.DB.Model(&entity.MenuActions{}).
|
||||
Where(&entity.MenuActions{ID: id}).
|
||||
Updates(menuAction).Error
|
||||
}
|
||||
|
||||
func (_i *menuActionsRepository) Delete(id uint) (err error) {
|
||||
return _i.DB.DB.Delete(&entity.MenuActions{}, id).Error
|
||||
}
|
||||
|
||||
func (_i *menuActionsRepository) DeleteByMenuId(menuId uint) (err error) {
|
||||
return _i.DB.DB.Where("menu_id = ?", menuId).Delete(&entity.MenuActions{}).Error
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package request
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type MenuActionsQueryRequest struct {
|
||||
MenuId *uint `query:"menu_id"`
|
||||
ActionCode *string `query:"action_code"`
|
||||
ClientId *uuid.UUID `query:"client_id"`
|
||||
Pagination *paginator.Pagination `query:"pagination"`
|
||||
}
|
||||
|
||||
type MenuActionsCreateRequest struct {
|
||||
MenuId uint `json:"menuId" validate:"required"`
|
||||
ActionCode string `json:"actionCode" validate:"required"`
|
||||
ActionName string `json:"actionName" validate:"required"`
|
||||
Description *string `json:"description"`
|
||||
PathUrl *string `json:"pathUrl"`
|
||||
HttpMethod *string `json:"httpMethod"`
|
||||
Position *int `json:"position"`
|
||||
ClientId *uuid.UUID `json:"clientId"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
}
|
||||
|
||||
func (req MenuActionsCreateRequest) ToEntity() *entity.MenuActions {
|
||||
return &entity.MenuActions{
|
||||
MenuId: req.MenuId,
|
||||
ActionCode: req.ActionCode,
|
||||
ActionName: req.ActionName,
|
||||
Description: req.Description,
|
||||
PathUrl: req.PathUrl,
|
||||
HttpMethod: req.HttpMethod,
|
||||
Position: req.Position,
|
||||
ClientId: req.ClientId,
|
||||
IsActive: req.IsActive,
|
||||
}
|
||||
}
|
||||
|
||||
type MenuActionsUpdateRequest struct {
|
||||
MenuId uint `json:"menuId"`
|
||||
ActionCode string `json:"actionCode"`
|
||||
ActionName string `json:"actionName" validate:"required"`
|
||||
Description *string `json:"description"`
|
||||
PathUrl *string `json:"pathUrl"`
|
||||
HttpMethod *string `json:"httpMethod"`
|
||||
Position *int `json:"position"`
|
||||
ClientId *uuid.UUID `json:"clientId"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
}
|
||||
|
||||
func (req MenuActionsUpdateRequest) ToEntity() *entity.MenuActions {
|
||||
return &entity.MenuActions{
|
||||
MenuId: req.MenuId,
|
||||
ActionCode: req.ActionCode,
|
||||
ActionName: req.ActionName,
|
||||
Description: req.Description,
|
||||
PathUrl: req.PathUrl,
|
||||
HttpMethod: req.HttpMethod,
|
||||
Position: req.Position,
|
||||
ClientId: req.ClientId,
|
||||
IsActive: req.IsActive,
|
||||
}
|
||||
}
|
||||
|
||||
type MenuActionsBatchCreateRequest struct {
|
||||
MenuId uint `json:"menuId" validate:"required"`
|
||||
ActionCodes []string `json:"actionCodes" validate:"required,min=1"`
|
||||
ClientId *uuid.UUID `json:"clientId"`
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package response
|
||||
|
||||
import "time"
|
||||
|
||||
type MenuActionsResponse struct {
|
||||
ID uint `json:"id"`
|
||||
MenuId uint `json:"menuId"`
|
||||
ActionCode string `json:"actionCode"`
|
||||
ActionName string `json:"actionName"`
|
||||
Description *string `json:"description"`
|
||||
PathUrl *string `json:"pathUrl"`
|
||||
HttpMethod *string `json:"httpMethod"`
|
||||
Position *int `json:"position"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
"netidhub-saas-be/app/module/menu_actions/mapper"
|
||||
"netidhub-saas-be/app/module/menu_actions/repository"
|
||||
"netidhub-saas-be/app/module/menu_actions/request"
|
||||
"netidhub-saas-be/app/module/menu_actions/response"
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
)
|
||||
|
||||
// MenuActionsService
|
||||
type menuActionsService struct {
|
||||
Repo repository.MenuActionsRepository
|
||||
Log zerolog.Logger
|
||||
}
|
||||
|
||||
// MenuActionsService define interface of IMenuActionsService
|
||||
type MenuActionsService interface {
|
||||
All(req request.MenuActionsQueryRequest) (menuActions []*response.MenuActionsResponse, paging paginator.Pagination, err error)
|
||||
GetByMenuId(menuId uint) (menuActions []*response.MenuActionsResponse, err error)
|
||||
Show(id uint) (menuAction *response.MenuActionsResponse, err error)
|
||||
Save(req request.MenuActionsCreateRequest) (err error)
|
||||
SaveBatch(req request.MenuActionsBatchCreateRequest) (err error)
|
||||
Update(id uint, req request.MenuActionsUpdateRequest) (err error)
|
||||
Delete(id uint) error
|
||||
}
|
||||
|
||||
// NewMenuActionsService init MenuActionsService
|
||||
func NewMenuActionsService(repo repository.MenuActionsRepository, log zerolog.Logger) MenuActionsService {
|
||||
return &menuActionsService{
|
||||
Repo: repo,
|
||||
Log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// All implement interface of MenuActionsService
|
||||
func (_i *menuActionsService) All(req request.MenuActionsQueryRequest) (menuActions []*response.MenuActionsResponse, paging paginator.Pagination, err error) {
|
||||
results, paging, err := _i.Repo.GetAll(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
menuActions = append(menuActions, mapper.MenuActionsResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *menuActionsService) GetByMenuId(menuId uint) (menuActions []*response.MenuActionsResponse, err error) {
|
||||
results, err := _i.Repo.GetByMenuId(menuId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
menuActions = append(menuActions, mapper.MenuActionsResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *menuActionsService) Show(id uint) (menuAction *response.MenuActionsResponse, err error) {
|
||||
result, err := _i.Repo.FindOne(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapper.MenuActionsResponseMapper(result), nil
|
||||
}
|
||||
|
||||
func (_i *menuActionsService) Save(req request.MenuActionsCreateRequest) (err error) {
|
||||
_i.Log.Info().Interface("data", req).Msg("Creating menu action")
|
||||
|
||||
isActive := true
|
||||
if req.IsActive != nil {
|
||||
isActive = *req.IsActive
|
||||
}
|
||||
|
||||
menuAction := req.ToEntity()
|
||||
menuAction.IsActive = &isActive
|
||||
|
||||
return _i.Repo.Create(menuAction)
|
||||
}
|
||||
|
||||
func (_i *menuActionsService) SaveBatch(req request.MenuActionsBatchCreateRequest) (err error) {
|
||||
_i.Log.Info().Interface("data", req).Msg("Creating menu actions batch")
|
||||
|
||||
isActive := true
|
||||
var menuActions []*entity.MenuActions
|
||||
|
||||
// Standard action names mapping
|
||||
actionNameMap := map[string]string{
|
||||
"view": "View",
|
||||
"create": "Create",
|
||||
"edit": "Edit",
|
||||
"update": "Update",
|
||||
"delete": "Delete",
|
||||
"approve": "Approve",
|
||||
"reject": "Reject",
|
||||
"export": "Export",
|
||||
"import": "Import",
|
||||
"print": "Print",
|
||||
}
|
||||
|
||||
for idx, actionCode := range req.ActionCodes {
|
||||
position := idx + 1
|
||||
actionName := actionNameMap[actionCode]
|
||||
if actionName == "" {
|
||||
// Capitalize first letter if not in map
|
||||
if len(actionCode) > 0 {
|
||||
actionName = string(actionCode[0]-32) + actionCode[1:]
|
||||
} else {
|
||||
actionName = actionCode
|
||||
}
|
||||
}
|
||||
|
||||
menuAction := &entity.MenuActions{
|
||||
MenuId: req.MenuId,
|
||||
ActionCode: actionCode,
|
||||
ActionName: actionName,
|
||||
Position: &position,
|
||||
ClientId: req.ClientId,
|
||||
IsActive: &isActive,
|
||||
}
|
||||
menuActions = append(menuActions, menuAction)
|
||||
}
|
||||
|
||||
return _i.Repo.CreateBatch(menuActions)
|
||||
}
|
||||
|
||||
func (_i *menuActionsService) Update(id uint, req request.MenuActionsUpdateRequest) (err error) {
|
||||
_i.Log.Info().Interface("data", req).Msg("Updating menu action")
|
||||
|
||||
isActive := true
|
||||
if req.IsActive != nil {
|
||||
isActive = *req.IsActive
|
||||
}
|
||||
|
||||
menuAction := req.ToEntity()
|
||||
menuAction.IsActive = &isActive
|
||||
|
||||
return _i.Repo.Update(id, menuAction)
|
||||
}
|
||||
|
||||
func (_i *menuActionsService) Delete(id uint) error {
|
||||
result, err := _i.Repo.FindOne(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isActive := false
|
||||
result.IsActive = &isActive
|
||||
return _i.Repo.Update(id, result)
|
||||
}
|
||||
|
||||
|
|
@ -54,6 +54,7 @@ func (_i *menuModulesRepository) GetAll(req request.MenuModulesQueryRequest) (me
|
|||
|
||||
query.Count(&count)
|
||||
|
||||
// Apply sorting
|
||||
if req.Pagination.SortBy != "" {
|
||||
direction := "ASC"
|
||||
if req.Pagination.Sort == "desc" {
|
||||
|
|
@ -64,15 +65,29 @@ func (_i *menuModulesRepository) GetAll(req request.MenuModulesQueryRequest) (me
|
|||
query.Order("position ASC")
|
||||
}
|
||||
|
||||
req.Pagination.Count = count
|
||||
req.Pagination = paginator.Paging(req.Pagination)
|
||||
// Apply pagination (manual calculation like articles)
|
||||
page := req.Pagination.Page
|
||||
limit := req.Pagination.Limit
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&menuModules).Error
|
||||
offset := (page - 1) * limit
|
||||
err = query.Offset(offset).Limit(limit).Find(&menuModules).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
paging = *req.Pagination
|
||||
// Create pagination response
|
||||
paging = paginator.Pagination{
|
||||
Page: page,
|
||||
Limit: limit,
|
||||
Count: count,
|
||||
TotalPage: int((count + int64(limit) - 1) / int64(limit)),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
package request
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type MenuModulesQueryRequest struct {
|
||||
MenuId *uint `query:"menu_id"`
|
||||
ModuleId *uint `query:"module_id"`
|
||||
ClientId *uuid.UUID `query:"client_id"`
|
||||
Pagination *paginator.Query `query:"pagination"`
|
||||
MenuId *uint `query:"menu_id"`
|
||||
ModuleId *uint `query:"module_id"`
|
||||
ClientId *uuid.UUID `query:"client_id"`
|
||||
Pagination *paginator.Pagination `query:"pagination"`
|
||||
}
|
||||
|
||||
type MenuModulesCreateRequest struct {
|
||||
|
|
@ -33,4 +34,3 @@ type MenuModulesUpdateRequest struct {
|
|||
ClientId *uuid.UUID `json:"client_id"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/service"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
UserLevelMenuAccesses UserLevelMenuAccessesController
|
||||
}
|
||||
|
||||
func NewController(userLevelMenuAccessesService service.UserLevelMenuAccessesService) *Controller {
|
||||
return &Controller{
|
||||
UserLevelMenuAccesses: NewUserLevelMenuAccessesController(userLevelMenuAccessesService),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/request"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/service"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
utilRes "netidhub-saas-be/utils/response"
|
||||
utilVal "netidhub-saas-be/utils/validator"
|
||||
)
|
||||
|
||||
type userLevelMenuAccessesController struct {
|
||||
userLevelMenuAccessesService service.UserLevelMenuAccessesService
|
||||
}
|
||||
|
||||
type UserLevelMenuAccessesController interface {
|
||||
All(c *fiber.Ctx) error
|
||||
GetByUserLevelId(c *fiber.Ctx) error
|
||||
GetByMenuId(c *fiber.Ctx) error
|
||||
CheckAccess(c *fiber.Ctx) error
|
||||
Show(c *fiber.Ctx) error
|
||||
Save(c *fiber.Ctx) error
|
||||
SaveBatch(c *fiber.Ctx) error
|
||||
Update(c *fiber.Ctx) error
|
||||
Delete(c *fiber.Ctx) error
|
||||
}
|
||||
|
||||
func NewUserLevelMenuAccessesController(userLevelMenuAccessesService service.UserLevelMenuAccessesService) UserLevelMenuAccessesController {
|
||||
return &userLevelMenuAccessesController{
|
||||
userLevelMenuAccessesService: userLevelMenuAccessesService,
|
||||
}
|
||||
}
|
||||
|
||||
// All UserLevelMenuAccesses
|
||||
// @Summary Get all UserLevelMenuAccesses
|
||||
// @Description API for getting all UserLevelMenuAccesses
|
||||
// @Tags UserLevelMenuAccesses
|
||||
// @Security Bearer
|
||||
// @Param user_level_id query int false "User Level ID"
|
||||
// @Param menu_id query int false "Menu ID"
|
||||
// @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 /user-level-menu-accesses [get]
|
||||
func (_i *userLevelMenuAccessesController) All(c *fiber.Ctx) error {
|
||||
paginate, err := paginator.Paginate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := request.UserLevelMenuAccessesQueryRequest{
|
||||
Pagination: paginate,
|
||||
}
|
||||
|
||||
if userLevelId := c.Query("user_level_id"); userLevelId != "" {
|
||||
id, _ := strconv.ParseUint(userLevelId, 10, 0)
|
||||
userLevelIdUint := uint(id)
|
||||
req.UserLevelId = &userLevelIdUint
|
||||
}
|
||||
|
||||
if menuId := c.Query("menu_id"); menuId != "" {
|
||||
id, _ := strconv.ParseUint(menuId, 10, 0)
|
||||
menuIdUint := uint(id)
|
||||
req.MenuId = &menuIdUint
|
||||
}
|
||||
|
||||
accessesData, paging, err := _i.userLevelMenuAccessesService.All(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuAccesses list successfully retrieved"},
|
||||
Data: accessesData,
|
||||
Meta: paging,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByUserLevelId get UserLevelMenuAccesses by User Level ID
|
||||
// @Summary Get UserLevelMenuAccesses by User Level ID
|
||||
// @Description API for getting UserLevelMenuAccesses by User Level ID
|
||||
// @Tags UserLevelMenuAccesses
|
||||
// @Security Bearer
|
||||
// @Param user_level_id path int true "User Level ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-accesses/user-level/{user_level_id} [get]
|
||||
func (_i *userLevelMenuAccessesController) GetByUserLevelId(c *fiber.Ctx) error {
|
||||
userLevelId, err := strconv.ParseUint(c.Params("user_level_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessesData, err := _i.userLevelMenuAccessesService.GetByUserLevelId(uint(userLevelId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuAccesses by user level successfully retrieved"},
|
||||
Data: accessesData,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByMenuId get UserLevelMenuAccesses by Menu ID
|
||||
// @Summary Get UserLevelMenuAccesses by Menu ID
|
||||
// @Description API for getting UserLevelMenuAccesses by Menu ID
|
||||
// @Tags UserLevelMenuAccesses
|
||||
// @Security Bearer
|
||||
// @Param menu_id path int true "Menu ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-accesses/menu/{menu_id} [get]
|
||||
func (_i *userLevelMenuAccessesController) GetByMenuId(c *fiber.Ctx) error {
|
||||
menuId, err := strconv.ParseUint(c.Params("menu_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessesData, err := _i.userLevelMenuAccessesService.GetByMenuId(uint(menuId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuAccesses by menu successfully retrieved"},
|
||||
Data: accessesData,
|
||||
})
|
||||
}
|
||||
|
||||
// CheckAccess check if user level has access to menu
|
||||
// @Summary Check User Level Menu Access
|
||||
// @Description API for checking if user level has access to menu
|
||||
// @Tags UserLevelMenuAccesses
|
||||
// @Security Bearer
|
||||
// @Param user_level_id path int true "User Level ID"
|
||||
// @Param menu_id path int true "Menu ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-accesses/check/{user_level_id}/{menu_id} [get]
|
||||
func (_i *userLevelMenuAccessesController) CheckAccess(c *fiber.Ctx) error {
|
||||
userLevelId, err := strconv.ParseUint(c.Params("user_level_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
menuId, err := strconv.ParseUint(c.Params("menu_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hasAccess, err := _i.userLevelMenuAccessesService.CheckAccess(uint(userLevelId), uint(menuId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Access check completed"},
|
||||
Data: fiber.Map{"has_access": hasAccess},
|
||||
})
|
||||
}
|
||||
|
||||
// Show get one UserLevelMenuAccess
|
||||
// @Summary Get one UserLevelMenuAccess
|
||||
// @Description API for getting one UserLevelMenuAccess
|
||||
// @Tags UserLevelMenuAccesses
|
||||
// @Security Bearer
|
||||
// @Param id path int true "UserLevelMenuAccess ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-accesses/{id} [get]
|
||||
func (_i *userLevelMenuAccessesController) Show(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessData, err := _i.userLevelMenuAccessesService.Show(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuAccess successfully retrieved"},
|
||||
Data: accessData,
|
||||
})
|
||||
}
|
||||
|
||||
// Save create UserLevelMenuAccess
|
||||
// @Summary Create UserLevelMenuAccess
|
||||
// @Description API for create UserLevelMenuAccess
|
||||
// @Tags UserLevelMenuAccesses
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param payload body request.UserLevelMenuAccessesCreateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-accesses [post]
|
||||
func (_i *userLevelMenuAccessesController) Save(c *fiber.Ctx) error {
|
||||
req := new(request.UserLevelMenuAccessesCreateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := _i.userLevelMenuAccessesService.Save(*req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuAccess successfully created"},
|
||||
})
|
||||
}
|
||||
|
||||
// SaveBatch create UserLevelMenuAccesses batch
|
||||
// @Summary Create UserLevelMenuAccesses batch
|
||||
// @Description API for create UserLevelMenuAccesses batch
|
||||
// @Tags UserLevelMenuAccesses
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param payload body request.UserLevelMenuAccessesBatchCreateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-accesses/batch [post]
|
||||
func (_i *userLevelMenuAccessesController) SaveBatch(c *fiber.Ctx) error {
|
||||
req := new(request.UserLevelMenuAccessesBatchCreateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := _i.userLevelMenuAccessesService.SaveBatch(*req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuAccesses batch successfully created"},
|
||||
})
|
||||
}
|
||||
|
||||
// Update UserLevelMenuAccess
|
||||
// @Summary Update UserLevelMenuAccess
|
||||
// @Description API for update UserLevelMenuAccess
|
||||
// @Tags UserLevelMenuAccesses
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param id path int true "UserLevelMenuAccess ID"
|
||||
// @Param payload body request.UserLevelMenuAccessesUpdateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-accesses/{id} [put]
|
||||
func (_i *userLevelMenuAccessesController) Update(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := new(request.UserLevelMenuAccessesUpdateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = _i.userLevelMenuAccessesService.Update(uint(id), *req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuAccess successfully updated"},
|
||||
})
|
||||
}
|
||||
|
||||
// Delete UserLevelMenuAccess
|
||||
// @Summary Delete UserLevelMenuAccess
|
||||
// @Description API for delete UserLevelMenuAccess
|
||||
// @Tags UserLevelMenuAccesses
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param id path int true "UserLevelMenuAccess ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-accesses/{id} [delete]
|
||||
func (_i *userLevelMenuAccessesController) Delete(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = _i.userLevelMenuAccessesService.Delete(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuAccess successfully deleted"},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package mapper
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
res "netidhub-saas-be/app/module/user_level_menu_accesses/response"
|
||||
)
|
||||
|
||||
func UserLevelMenuAccessesResponseMapper(accessReq *entity.UserLevelMenuAccesses) (accessRes *res.UserLevelMenuAccessesResponse) {
|
||||
if accessReq != nil {
|
||||
accessRes = &res.UserLevelMenuAccessesResponse{
|
||||
ID: accessReq.ID,
|
||||
UserLevelId: accessReq.UserLevelId,
|
||||
MenuId: accessReq.MenuId,
|
||||
CanAccess: accessReq.CanAccess,
|
||||
IsActive: accessReq.IsActive,
|
||||
CreatedAt: accessReq.CreatedAt,
|
||||
UpdatedAt: accessReq.UpdatedAt,
|
||||
}
|
||||
}
|
||||
return accessRes
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"netidhub-saas-be/app/database"
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/request"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type userLevelMenuAccessesRepository struct {
|
||||
DB *database.Database
|
||||
}
|
||||
|
||||
// UserLevelMenuAccessesRepository define interface of IUserLevelMenuAccessesRepository
|
||||
type UserLevelMenuAccessesRepository interface {
|
||||
GetAll(req request.UserLevelMenuAccessesQueryRequest) (accesses []*entity.UserLevelMenuAccesses, paging paginator.Pagination, err error)
|
||||
GetByUserLevelId(userLevelId uint) (accesses []*entity.UserLevelMenuAccesses, err error)
|
||||
GetByMenuId(menuId uint) (accesses []*entity.UserLevelMenuAccesses, err error)
|
||||
CheckAccess(userLevelId uint, menuId uint) (hasAccess bool, err error)
|
||||
FindOne(id uint) (access *entity.UserLevelMenuAccesses, err error)
|
||||
Create(access *entity.UserLevelMenuAccesses) (err error)
|
||||
CreateBatch(accesses []*entity.UserLevelMenuAccesses) (err error)
|
||||
Update(id uint, access *entity.UserLevelMenuAccesses) (err error)
|
||||
Delete(id uint) (err error)
|
||||
DeleteByUserLevelId(userLevelId uint) (err error)
|
||||
DeleteByMenuId(menuId uint) (err error)
|
||||
}
|
||||
|
||||
func NewUserLevelMenuAccessesRepository(db *database.Database) UserLevelMenuAccessesRepository {
|
||||
return &userLevelMenuAccessesRepository{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
// implement interface of IUserLevelMenuAccessesRepository
|
||||
func (_i *userLevelMenuAccessesRepository) GetAll(req request.UserLevelMenuAccessesQueryRequest) (accesses []*entity.UserLevelMenuAccesses, paging paginator.Pagination, err error) {
|
||||
var count int64
|
||||
|
||||
query := _i.DB.DB.Model(&entity.UserLevelMenuAccesses{})
|
||||
query = query.Where("is_active = ?", true)
|
||||
|
||||
if req.UserLevelId != nil {
|
||||
query = query.Where("user_level_id = ?", req.UserLevelId)
|
||||
}
|
||||
if req.MenuId != nil {
|
||||
query = query.Where("menu_id = ?", req.MenuId)
|
||||
}
|
||||
if req.ClientId != nil {
|
||||
query = query.Where("client_id = ?", req.ClientId)
|
||||
}
|
||||
if req.CanAccess != nil {
|
||||
query = query.Where("can_access = ?", req.CanAccess)
|
||||
}
|
||||
|
||||
// Preload relations
|
||||
query = query.Preload("UserLevel").Preload("Menu")
|
||||
|
||||
query.Count(&count)
|
||||
|
||||
// Apply sorting
|
||||
if req.Pagination.SortBy != "" {
|
||||
direction := "ASC"
|
||||
if req.Pagination.Sort == "desc" {
|
||||
direction = "DESC"
|
||||
}
|
||||
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
||||
}
|
||||
|
||||
// Apply pagination (manual calculation like articles)
|
||||
page := req.Pagination.Page
|
||||
limit := req.Pagination.Limit
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
offset := (page - 1) * limit
|
||||
err = query.Offset(offset).Limit(limit).Find(&accesses).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Create pagination response
|
||||
paging = paginator.Pagination{
|
||||
Page: page,
|
||||
Limit: limit,
|
||||
Count: count,
|
||||
TotalPage: int((count + int64(limit) - 1) / int64(limit)),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) GetByUserLevelId(userLevelId uint) (accesses []*entity.UserLevelMenuAccesses, err error) {
|
||||
query := _i.DB.DB.Model(&entity.UserLevelMenuAccesses{})
|
||||
query = query.Where("user_level_id = ? AND is_active = ?", userLevelId, true)
|
||||
query = query.Preload("Menu")
|
||||
err = query.Find(&accesses).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) GetByMenuId(menuId uint) (accesses []*entity.UserLevelMenuAccesses, err error) {
|
||||
query := _i.DB.DB.Model(&entity.UserLevelMenuAccesses{})
|
||||
query = query.Where("menu_id = ? AND is_active = ?", menuId, true)
|
||||
query = query.Preload("UserLevel")
|
||||
err = query.Find(&accesses).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) CheckAccess(userLevelId uint, menuId uint) (hasAccess bool, err error) {
|
||||
var access entity.UserLevelMenuAccesses
|
||||
query := _i.DB.DB.Model(&entity.UserLevelMenuAccesses{})
|
||||
query = query.Where("user_level_id = ? AND menu_id = ? AND is_active = ? AND can_access = ?", userLevelId, menuId, true, true)
|
||||
err = query.First(&access).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) FindOne(id uint) (access *entity.UserLevelMenuAccesses, err error) {
|
||||
query := _i.DB.DB.Preload("UserLevel").Preload("Menu")
|
||||
if err := query.First(&access, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return access, nil
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) Create(access *entity.UserLevelMenuAccesses) (err error) {
|
||||
return _i.DB.DB.Create(access).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) CreateBatch(accesses []*entity.UserLevelMenuAccesses) (err error) {
|
||||
return _i.DB.DB.Create(&accesses).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) Update(id uint, access *entity.UserLevelMenuAccesses) (err error) {
|
||||
return _i.DB.DB.Model(&entity.UserLevelMenuAccesses{}).
|
||||
Where(&entity.UserLevelMenuAccesses{ID: id}).
|
||||
Updates(access).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) Delete(id uint) (err error) {
|
||||
return _i.DB.DB.Delete(&entity.UserLevelMenuAccesses{}, id).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) DeleteByUserLevelId(userLevelId uint) (err error) {
|
||||
return _i.DB.DB.Where("user_level_id = ?", userLevelId).Delete(&entity.UserLevelMenuAccesses{}).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesRepository) DeleteByMenuId(menuId uint) (err error) {
|
||||
return _i.DB.DB.Where("menu_id = ?", menuId).Delete(&entity.UserLevelMenuAccesses{}).Error
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package request
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type UserLevelMenuAccessesQueryRequest struct {
|
||||
UserLevelId *uint `query:"user_level_id"`
|
||||
MenuId *uint `query:"menu_id"`
|
||||
ClientId *uuid.UUID `query:"client_id"`
|
||||
CanAccess *bool `query:"can_access"`
|
||||
Pagination *paginator.Pagination `query:"pagination"`
|
||||
}
|
||||
|
||||
type UserLevelMenuAccessesCreateRequest struct {
|
||||
UserLevelId uint `json:"userLevelId" validate:"required"`
|
||||
MenuId uint `json:"menuId" validate:"required"`
|
||||
CanAccess bool `json:"canAccess"`
|
||||
ClientId *uuid.UUID `json:"clientId"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
}
|
||||
|
||||
func (req UserLevelMenuAccessesCreateRequest) ToEntity() *entity.UserLevelMenuAccesses {
|
||||
return &entity.UserLevelMenuAccesses{
|
||||
UserLevelId: req.UserLevelId,
|
||||
MenuId: req.MenuId,
|
||||
CanAccess: req.CanAccess,
|
||||
ClientId: req.ClientId,
|
||||
IsActive: req.IsActive,
|
||||
}
|
||||
}
|
||||
|
||||
type UserLevelMenuAccessesUpdateRequest struct {
|
||||
UserLevelId *uint `json:"userLevelId"`
|
||||
MenuId *uint `json:"menuId"`
|
||||
CanAccess *bool `json:"canAccess"`
|
||||
ClientId *uuid.UUID `json:"clientId"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
}
|
||||
|
||||
func (req UserLevelMenuAccessesUpdateRequest) ToEntity() *entity.UserLevelMenuAccesses {
|
||||
access := &entity.UserLevelMenuAccesses{}
|
||||
if req.UserLevelId != nil {
|
||||
access.UserLevelId = *req.UserLevelId
|
||||
}
|
||||
if req.MenuId != nil {
|
||||
access.MenuId = *req.MenuId
|
||||
}
|
||||
if req.CanAccess != nil {
|
||||
access.CanAccess = *req.CanAccess
|
||||
}
|
||||
access.ClientId = req.ClientId
|
||||
access.IsActive = req.IsActive
|
||||
return access
|
||||
}
|
||||
|
||||
type UserLevelMenuAccessesBatchCreateRequest struct {
|
||||
UserLevelId uint `json:"userLevelId" validate:"required"`
|
||||
MenuIds []uint `json:"menuIds" validate:"required,min=1"`
|
||||
ClientId *uuid.UUID `json:"clientId"`
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package response
|
||||
|
||||
import "time"
|
||||
|
||||
type UserLevelMenuAccessesResponse struct {
|
||||
ID uint `json:"id"`
|
||||
UserLevelId uint `json:"userLevelId"`
|
||||
MenuId uint `json:"menuId"`
|
||||
CanAccess bool `json:"canAccess"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/mapper"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/repository"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/request"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/response"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
)
|
||||
|
||||
// UserLevelMenuAccessesService
|
||||
type userLevelMenuAccessesService struct {
|
||||
Repo repository.UserLevelMenuAccessesRepository
|
||||
Log zerolog.Logger
|
||||
}
|
||||
|
||||
// UserLevelMenuAccessesService define interface of IUserLevelMenuAccessesService
|
||||
type UserLevelMenuAccessesService interface {
|
||||
All(req request.UserLevelMenuAccessesQueryRequest) (accesses []*response.UserLevelMenuAccessesResponse, paging paginator.Pagination, err error)
|
||||
GetByUserLevelId(userLevelId uint) (accesses []*response.UserLevelMenuAccessesResponse, err error)
|
||||
GetByMenuId(menuId uint) (accesses []*response.UserLevelMenuAccessesResponse, err error)
|
||||
CheckAccess(userLevelId uint, menuId uint) (hasAccess bool, err error)
|
||||
Show(id uint) (access *response.UserLevelMenuAccessesResponse, err error)
|
||||
Save(req request.UserLevelMenuAccessesCreateRequest) (err error)
|
||||
SaveBatch(req request.UserLevelMenuAccessesBatchCreateRequest) (err error)
|
||||
Update(id uint, req request.UserLevelMenuAccessesUpdateRequest) (err error)
|
||||
Delete(id uint) error
|
||||
}
|
||||
|
||||
// NewUserLevelMenuAccessesService init UserLevelMenuAccessesService
|
||||
func NewUserLevelMenuAccessesService(repo repository.UserLevelMenuAccessesRepository, log zerolog.Logger) UserLevelMenuAccessesService {
|
||||
return &userLevelMenuAccessesService{
|
||||
Repo: repo,
|
||||
Log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// All implement interface of UserLevelMenuAccessesService
|
||||
func (_i *userLevelMenuAccessesService) All(req request.UserLevelMenuAccessesQueryRequest) (accesses []*response.UserLevelMenuAccessesResponse, paging paginator.Pagination, err error) {
|
||||
results, paging, err := _i.Repo.GetAll(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
accesses = append(accesses, mapper.UserLevelMenuAccessesResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesService) GetByUserLevelId(userLevelId uint) (accesses []*response.UserLevelMenuAccessesResponse, err error) {
|
||||
results, err := _i.Repo.GetByUserLevelId(userLevelId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
accesses = append(accesses, mapper.UserLevelMenuAccessesResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesService) GetByMenuId(menuId uint) (accesses []*response.UserLevelMenuAccessesResponse, err error) {
|
||||
results, err := _i.Repo.GetByMenuId(menuId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
accesses = append(accesses, mapper.UserLevelMenuAccessesResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesService) CheckAccess(userLevelId uint, menuId uint) (hasAccess bool, err error) {
|
||||
return _i.Repo.CheckAccess(userLevelId, menuId)
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesService) Show(id uint) (access *response.UserLevelMenuAccessesResponse, err error) {
|
||||
result, err := _i.Repo.FindOne(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapper.UserLevelMenuAccessesResponseMapper(result), nil
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesService) Save(req request.UserLevelMenuAccessesCreateRequest) (err error) {
|
||||
_i.Log.Info().Interface("data", req).Msg("Creating user level menu access")
|
||||
|
||||
isActive := true
|
||||
if req.IsActive != nil {
|
||||
isActive = *req.IsActive
|
||||
}
|
||||
|
||||
access := req.ToEntity()
|
||||
access.IsActive = &isActive
|
||||
|
||||
return _i.Repo.Create(access)
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesService) SaveBatch(req request.UserLevelMenuAccessesBatchCreateRequest) (err error) {
|
||||
_i.Log.Info().Interface("data", req).Msg("Creating user level menu accesses batch")
|
||||
|
||||
isActive := true
|
||||
var accesses []*entity.UserLevelMenuAccesses
|
||||
|
||||
for _, menuId := range req.MenuIds {
|
||||
access := &entity.UserLevelMenuAccesses{
|
||||
UserLevelId: req.UserLevelId,
|
||||
MenuId: menuId,
|
||||
CanAccess: true,
|
||||
ClientId: req.ClientId,
|
||||
IsActive: &isActive,
|
||||
}
|
||||
accesses = append(accesses, access)
|
||||
}
|
||||
|
||||
return _i.Repo.CreateBatch(accesses)
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesService) Update(id uint, req request.UserLevelMenuAccessesUpdateRequest) (err error) {
|
||||
_i.Log.Info().Interface("data", req).Msg("Updating user level menu access")
|
||||
|
||||
isActive := true
|
||||
if req.IsActive != nil {
|
||||
isActive = *req.IsActive
|
||||
}
|
||||
|
||||
access := req.ToEntity()
|
||||
access.IsActive = &isActive
|
||||
|
||||
return _i.Repo.Update(id, access)
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuAccessesService) Delete(id uint) error {
|
||||
result, err := _i.Repo.FindOne(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isActive := false
|
||||
result.IsActive = &isActive
|
||||
return _i.Repo.Update(id, result)
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package user_level_menu_accesses
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/fx"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/controller"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/repository"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses/service"
|
||||
)
|
||||
|
||||
// struct of UserLevelMenuAccessesRouter
|
||||
type UserLevelMenuAccessesRouter struct {
|
||||
App fiber.Router
|
||||
Controller *controller.Controller
|
||||
}
|
||||
|
||||
// register bulky of UserLevelMenuAccesses module
|
||||
var NewUserLevelMenuAccessesModule = fx.Options(
|
||||
// register repository of UserLevelMenuAccesses module
|
||||
fx.Provide(repository.NewUserLevelMenuAccessesRepository),
|
||||
|
||||
// register service of UserLevelMenuAccesses module
|
||||
fx.Provide(service.NewUserLevelMenuAccessesService),
|
||||
|
||||
// register controller of UserLevelMenuAccesses module
|
||||
fx.Provide(controller.NewController),
|
||||
|
||||
// register router of UserLevelMenuAccesses module
|
||||
fx.Provide(NewUserLevelMenuAccessesRouter),
|
||||
)
|
||||
|
||||
// init UserLevelMenuAccessesRouter
|
||||
func NewUserLevelMenuAccessesRouter(fiber *fiber.App, controller *controller.Controller) *UserLevelMenuAccessesRouter {
|
||||
return &UserLevelMenuAccessesRouter{
|
||||
App: fiber,
|
||||
Controller: controller,
|
||||
}
|
||||
}
|
||||
|
||||
// register routes of UserLevelMenuAccesses module
|
||||
func (_i *UserLevelMenuAccessesRouter) RegisterUserLevelMenuAccessesRoutes() {
|
||||
// define controllers
|
||||
userLevelMenuAccessesController := _i.Controller.UserLevelMenuAccesses
|
||||
|
||||
// define routes
|
||||
_i.App.Route("/user-level-menu-accesses", func(router fiber.Router) {
|
||||
router.Get("/", userLevelMenuAccessesController.All)
|
||||
router.Get("/:id", userLevelMenuAccessesController.Show)
|
||||
router.Get("/user-level/:user_level_id", userLevelMenuAccessesController.GetByUserLevelId)
|
||||
router.Get("/menu/:menu_id", userLevelMenuAccessesController.GetByMenuId)
|
||||
router.Get("/check/:user_level_id/:menu_id", userLevelMenuAccessesController.CheckAccess)
|
||||
router.Post("/", userLevelMenuAccessesController.Save)
|
||||
router.Post("/batch", userLevelMenuAccessesController.SaveBatch)
|
||||
router.Put("/:id", userLevelMenuAccessesController.Update)
|
||||
router.Delete("/:id", userLevelMenuAccessesController.Delete)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/service"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
UserLevelMenuActionAccesses UserLevelMenuActionAccessesController
|
||||
}
|
||||
|
||||
func NewController(userLevelMenuActionAccessesService service.UserLevelMenuActionAccessesService) *Controller {
|
||||
return &Controller{
|
||||
UserLevelMenuActionAccesses: NewUserLevelMenuActionAccessesController(userLevelMenuActionAccessesService),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,379 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/request"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/service"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
|
||||
utilRes "netidhub-saas-be/utils/response"
|
||||
utilVal "netidhub-saas-be/utils/validator"
|
||||
)
|
||||
|
||||
type userLevelMenuActionAccessesController struct {
|
||||
userLevelMenuActionAccessesService service.UserLevelMenuActionAccessesService
|
||||
}
|
||||
|
||||
type UserLevelMenuActionAccessesController interface {
|
||||
All(c *fiber.Ctx) error
|
||||
GetByUserLevelId(c *fiber.Ctx) error
|
||||
GetByUserLevelIdAndMenuId(c *fiber.Ctx) error
|
||||
GetByMenuId(c *fiber.Ctx) error
|
||||
CheckAccess(c *fiber.Ctx) error
|
||||
Show(c *fiber.Ctx) error
|
||||
Save(c *fiber.Ctx) error
|
||||
SaveBatch(c *fiber.Ctx) error
|
||||
Update(c *fiber.Ctx) error
|
||||
Delete(c *fiber.Ctx) error
|
||||
}
|
||||
|
||||
func NewUserLevelMenuActionAccessesController(userLevelMenuActionAccessesService service.UserLevelMenuActionAccessesService) UserLevelMenuActionAccessesController {
|
||||
return &userLevelMenuActionAccessesController{
|
||||
userLevelMenuActionAccessesService: userLevelMenuActionAccessesService,
|
||||
}
|
||||
}
|
||||
|
||||
// All UserLevelMenuActionAccesses
|
||||
// @Summary Get all UserLevelMenuActionAccesses
|
||||
// @Description API for getting all UserLevelMenuActionAccesses
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param user_level_id query int false "User Level ID"
|
||||
// @Param menu_id query int false "Menu ID"
|
||||
// @Param action_code query string false "Action Code"
|
||||
// @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 /user-level-menu-action-accesses [get]
|
||||
func (_i *userLevelMenuActionAccessesController) All(c *fiber.Ctx) error {
|
||||
paginate, err := paginator.Paginate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := request.UserLevelMenuActionAccessesQueryRequest{
|
||||
Pagination: paginate,
|
||||
}
|
||||
|
||||
if userLevelId := c.Query("user_level_id"); userLevelId != "" {
|
||||
id, _ := strconv.ParseUint(userLevelId, 10, 0)
|
||||
userLevelIdUint := uint(id)
|
||||
req.UserLevelId = &userLevelIdUint
|
||||
}
|
||||
|
||||
if menuId := c.Query("menu_id"); menuId != "" {
|
||||
id, _ := strconv.ParseUint(menuId, 10, 0)
|
||||
menuIdUint := uint(id)
|
||||
req.MenuId = &menuIdUint
|
||||
}
|
||||
|
||||
if actionCode := c.Query("action_code"); actionCode != "" {
|
||||
req.ActionCode = &actionCode
|
||||
}
|
||||
|
||||
accessesData, paging, err := _i.userLevelMenuActionAccessesService.All(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuActionAccesses list successfully retrieved"},
|
||||
Data: accessesData,
|
||||
Meta: paging,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByUserLevelId get UserLevelMenuActionAccesses by User Level ID
|
||||
// @Summary Get UserLevelMenuActionAccesses by User Level ID
|
||||
// @Description API for getting UserLevelMenuActionAccesses by User Level ID
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param user_level_id path int true "User Level ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-action-accesses/user-level/{user_level_id} [get]
|
||||
func (_i *userLevelMenuActionAccessesController) GetByUserLevelId(c *fiber.Ctx) error {
|
||||
userLevelId, err := strconv.ParseUint(c.Params("user_level_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessesData, err := _i.userLevelMenuActionAccessesService.GetByUserLevelId(uint(userLevelId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuActionAccesses by user level successfully retrieved"},
|
||||
Data: accessesData,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByUserLevelIdAndMenuId get UserLevelMenuActionAccesses by User Level ID and Menu ID
|
||||
// @Summary Get UserLevelMenuActionAccesses by User Level ID and Menu ID
|
||||
// @Description API for getting UserLevelMenuActionAccesses by User Level ID and Menu ID
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param user_level_id path int true "User Level ID"
|
||||
// @Param menu_id path int true "Menu ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-action-accesses/user-level/{user_level_id}/menu/{menu_id} [get]
|
||||
func (_i *userLevelMenuActionAccessesController) GetByUserLevelIdAndMenuId(c *fiber.Ctx) error {
|
||||
userLevelId, err := strconv.ParseUint(c.Params("user_level_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
menuId, err := strconv.ParseUint(c.Params("menu_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessesData, err := _i.userLevelMenuActionAccessesService.GetByUserLevelIdAndMenuId(uint(userLevelId), uint(menuId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuActionAccesses by user level and menu successfully retrieved"},
|
||||
Data: accessesData,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByMenuId get UserLevelMenuActionAccesses by Menu ID
|
||||
// @Summary Get UserLevelMenuActionAccesses by Menu ID
|
||||
// @Description API for getting UserLevelMenuActionAccesses by Menu ID
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param menu_id path int true "Menu ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-action-accesses/menu/{menu_id} [get]
|
||||
func (_i *userLevelMenuActionAccessesController) GetByMenuId(c *fiber.Ctx) error {
|
||||
menuId, err := strconv.ParseUint(c.Params("menu_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessesData, err := _i.userLevelMenuActionAccessesService.GetByMenuId(uint(menuId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuActionAccesses by menu successfully retrieved"},
|
||||
Data: accessesData,
|
||||
})
|
||||
}
|
||||
|
||||
// CheckAccess check if user level has access to action in menu
|
||||
// @Summary Check User Level Menu Action Access
|
||||
// @Description API for checking if user level has access to action in menu
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param user_level_id path int true "User Level ID"
|
||||
// @Param menu_id path int true "Menu ID"
|
||||
// @Param action_code path string true "Action Code"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-action-accesses/check/{user_level_id}/{menu_id}/{action_code} [get]
|
||||
func (_i *userLevelMenuActionAccessesController) CheckAccess(c *fiber.Ctx) error {
|
||||
userLevelId, err := strconv.ParseUint(c.Params("user_level_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
menuId, err := strconv.ParseUint(c.Params("menu_id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
actionCode := c.Params("action_code")
|
||||
if actionCode == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||
"success": false,
|
||||
"code": 400,
|
||||
"messages": []string{"Action code is required"},
|
||||
})
|
||||
}
|
||||
|
||||
hasAccess, err := _i.userLevelMenuActionAccessesService.CheckAccess(uint(userLevelId), uint(menuId), actionCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Access check completed"},
|
||||
Data: fiber.Map{"has_access": hasAccess},
|
||||
})
|
||||
}
|
||||
|
||||
// Show get one UserLevelMenuActionAccess
|
||||
// @Summary Get one UserLevelMenuActionAccess
|
||||
// @Description API for getting one UserLevelMenuActionAccess
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param id path int true "UserLevelMenuActionAccess ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-action-accesses/{id} [get]
|
||||
func (_i *userLevelMenuActionAccessesController) Show(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessData, err := _i.userLevelMenuActionAccessesService.Show(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuActionAccess successfully retrieved"},
|
||||
Data: accessData,
|
||||
})
|
||||
}
|
||||
|
||||
// Save create UserLevelMenuActionAccess
|
||||
// @Summary Create UserLevelMenuActionAccess
|
||||
// @Description API for create UserLevelMenuActionAccess
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param payload body request.UserLevelMenuActionAccessesCreateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-action-accesses [post]
|
||||
func (_i *userLevelMenuActionAccessesController) Save(c *fiber.Ctx) error {
|
||||
req := new(request.UserLevelMenuActionAccessesCreateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := _i.userLevelMenuActionAccessesService.Save(*req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuActionAccess successfully created"},
|
||||
})
|
||||
}
|
||||
|
||||
// SaveBatch create UserLevelMenuActionAccesses batch
|
||||
// @Summary Create UserLevelMenuActionAccesses batch
|
||||
// @Description API for create UserLevelMenuActionAccesses batch
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param payload body request.UserLevelMenuActionAccessesBatchCreateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-action-accesses/batch [post]
|
||||
func (_i *userLevelMenuActionAccessesController) SaveBatch(c *fiber.Ctx) error {
|
||||
req := new(request.UserLevelMenuActionAccessesBatchCreateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := _i.userLevelMenuActionAccessesService.SaveBatch(*req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuActionAccesses batch successfully created"},
|
||||
})
|
||||
}
|
||||
|
||||
// Update UserLevelMenuActionAccess
|
||||
// @Summary Update UserLevelMenuActionAccess
|
||||
// @Description API for update UserLevelMenuActionAccess
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param id path int true "UserLevelMenuActionAccess ID"
|
||||
// @Param payload body request.UserLevelMenuActionAccessesUpdateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-action-accesses/{id} [put]
|
||||
func (_i *userLevelMenuActionAccessesController) Update(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := new(request.UserLevelMenuActionAccessesUpdateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = _i.userLevelMenuActionAccessesService.Update(uint(id), *req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuActionAccess successfully updated"},
|
||||
})
|
||||
}
|
||||
|
||||
// Delete UserLevelMenuActionAccess
|
||||
// @Summary Delete UserLevelMenuActionAccess
|
||||
// @Description API for delete UserLevelMenuActionAccess
|
||||
// @Tags UserLevelMenuActionAccesses
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
||||
// @Param id path int true "UserLevelMenuActionAccess ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /user-level-menu-action-accesses/{id} [delete]
|
||||
func (_i *userLevelMenuActionAccessesController) Delete(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = _i.userLevelMenuActionAccessesService.Delete(uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"UserLevelMenuActionAccess successfully deleted"},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package mapper
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
res "netidhub-saas-be/app/module/user_level_menu_action_accesses/response"
|
||||
)
|
||||
|
||||
func UserLevelMenuActionAccessesResponseMapper(accessReq *entity.UserLevelMenuActionAccesses) (accessRes *res.UserLevelMenuActionAccessesResponse) {
|
||||
if accessReq != nil {
|
||||
accessRes = &res.UserLevelMenuActionAccessesResponse{
|
||||
ID: accessReq.ID,
|
||||
UserLevelId: accessReq.UserLevelId,
|
||||
MenuId: accessReq.MenuId,
|
||||
ActionCode: accessReq.ActionCode,
|
||||
CanAccess: accessReq.CanAccess,
|
||||
IsActive: accessReq.IsActive,
|
||||
CreatedAt: accessReq.CreatedAt,
|
||||
UpdatedAt: accessReq.UpdatedAt,
|
||||
}
|
||||
}
|
||||
return accessRes
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"netidhub-saas-be/app/database"
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/request"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type userLevelMenuActionAccessesRepository struct {
|
||||
DB *database.Database
|
||||
}
|
||||
|
||||
// UserLevelMenuActionAccessesRepository define interface of IUserLevelMenuActionAccessesRepository
|
||||
type UserLevelMenuActionAccessesRepository interface {
|
||||
GetAll(req request.UserLevelMenuActionAccessesQueryRequest) (accesses []*entity.UserLevelMenuActionAccesses, paging paginator.Pagination, err error)
|
||||
GetByUserLevelId(userLevelId uint) (accesses []*entity.UserLevelMenuActionAccesses, err error)
|
||||
GetByUserLevelIdAndMenuId(userLevelId uint, menuId uint) (accesses []*entity.UserLevelMenuActionAccesses, err error)
|
||||
GetByMenuId(menuId uint) (accesses []*entity.UserLevelMenuActionAccesses, err error)
|
||||
CheckAccess(userLevelId uint, menuId uint, actionCode string) (hasAccess bool, err error)
|
||||
FindOne(id uint) (access *entity.UserLevelMenuActionAccesses, err error)
|
||||
Create(access *entity.UserLevelMenuActionAccesses) (err error)
|
||||
CreateBatch(accesses []*entity.UserLevelMenuActionAccesses) (err error)
|
||||
Update(id uint, access *entity.UserLevelMenuActionAccesses) (err error)
|
||||
Delete(id uint) (err error)
|
||||
DeleteByUserLevelId(userLevelId uint) (err error)
|
||||
DeleteByMenuId(menuId uint) (err error)
|
||||
DeleteByUserLevelIdAndMenuId(userLevelId uint, menuId uint) (err error)
|
||||
}
|
||||
|
||||
func NewUserLevelMenuActionAccessesRepository(db *database.Database) UserLevelMenuActionAccessesRepository {
|
||||
return &userLevelMenuActionAccessesRepository{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
// implement interface of IUserLevelMenuActionAccessesRepository
|
||||
func (_i *userLevelMenuActionAccessesRepository) GetAll(req request.UserLevelMenuActionAccessesQueryRequest) (accesses []*entity.UserLevelMenuActionAccesses, paging paginator.Pagination, err error) {
|
||||
var count int64
|
||||
|
||||
query := _i.DB.DB.Model(&entity.UserLevelMenuActionAccesses{})
|
||||
query = query.Where("is_active = ?", true)
|
||||
|
||||
if req.UserLevelId != nil {
|
||||
query = query.Where("user_level_id = ?", req.UserLevelId)
|
||||
}
|
||||
if req.MenuId != nil {
|
||||
query = query.Where("menu_id = ?", req.MenuId)
|
||||
}
|
||||
if req.ActionCode != nil && *req.ActionCode != "" {
|
||||
query = query.Where("action_code = ?", req.ActionCode)
|
||||
}
|
||||
if req.ClientId != nil {
|
||||
query = query.Where("client_id = ?", req.ClientId)
|
||||
}
|
||||
if req.CanAccess != nil {
|
||||
query = query.Where("can_access = ?", req.CanAccess)
|
||||
}
|
||||
|
||||
// Preload relations
|
||||
query = query.Preload("UserLevel").Preload("Menu")
|
||||
|
||||
query.Count(&count)
|
||||
|
||||
// Apply sorting
|
||||
if req.Pagination.SortBy != "" {
|
||||
direction := "ASC"
|
||||
if req.Pagination.Sort == "desc" {
|
||||
direction = "DESC"
|
||||
}
|
||||
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
||||
}
|
||||
|
||||
// Apply pagination (manual calculation like articles)
|
||||
page := req.Pagination.Page
|
||||
limit := req.Pagination.Limit
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
offset := (page - 1) * limit
|
||||
err = query.Offset(offset).Limit(limit).Find(&accesses).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Create pagination response
|
||||
paging = paginator.Pagination{
|
||||
Page: page,
|
||||
Limit: limit,
|
||||
Count: count,
|
||||
TotalPage: int((count + int64(limit) - 1) / int64(limit)),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) GetByUserLevelId(userLevelId uint) (accesses []*entity.UserLevelMenuActionAccesses, err error) {
|
||||
query := _i.DB.DB.Model(&entity.UserLevelMenuActionAccesses{})
|
||||
query = query.Where("user_level_id = ? AND is_active = ?", userLevelId, true)
|
||||
query = query.Preload("Menu")
|
||||
err = query.Find(&accesses).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) GetByUserLevelIdAndMenuId(userLevelId uint, menuId uint) (accesses []*entity.UserLevelMenuActionAccesses, err error) {
|
||||
query := _i.DB.DB.Model(&entity.UserLevelMenuActionAccesses{})
|
||||
query = query.Where("user_level_id = ? AND menu_id = ? AND is_active = ?", userLevelId, menuId, true)
|
||||
query = query.Preload("Menu")
|
||||
err = query.Find(&accesses).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) GetByMenuId(menuId uint) (accesses []*entity.UserLevelMenuActionAccesses, err error) {
|
||||
query := _i.DB.DB.Model(&entity.UserLevelMenuActionAccesses{})
|
||||
query = query.Where("menu_id = ? AND is_active = ?", menuId, true)
|
||||
query = query.Preload("UserLevel")
|
||||
err = query.Find(&accesses).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) CheckAccess(userLevelId uint, menuId uint, actionCode string) (hasAccess bool, err error) {
|
||||
var access entity.UserLevelMenuActionAccesses
|
||||
query := _i.DB.DB.Model(&entity.UserLevelMenuActionAccesses{})
|
||||
query = query.Where("user_level_id = ? AND menu_id = ? AND action_code = ? AND is_active = ? AND can_access = ?", userLevelId, menuId, actionCode, true, true)
|
||||
err = query.First(&access).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) FindOne(id uint) (access *entity.UserLevelMenuActionAccesses, err error) {
|
||||
query := _i.DB.DB.Preload("UserLevel").Preload("Menu")
|
||||
if err := query.First(&access, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return access, nil
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) Create(access *entity.UserLevelMenuActionAccesses) (err error) {
|
||||
return _i.DB.DB.Create(access).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) CreateBatch(accesses []*entity.UserLevelMenuActionAccesses) (err error) {
|
||||
return _i.DB.DB.Create(&accesses).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) Update(id uint, access *entity.UserLevelMenuActionAccesses) (err error) {
|
||||
return _i.DB.DB.Model(&entity.UserLevelMenuActionAccesses{}).
|
||||
Where(&entity.UserLevelMenuActionAccesses{ID: id}).
|
||||
Updates(access).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) Delete(id uint) (err error) {
|
||||
return _i.DB.DB.Delete(&entity.UserLevelMenuActionAccesses{}, id).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) DeleteByUserLevelId(userLevelId uint) (err error) {
|
||||
return _i.DB.DB.Where("user_level_id = ?", userLevelId).Delete(&entity.UserLevelMenuActionAccesses{}).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) DeleteByMenuId(menuId uint) (err error) {
|
||||
return _i.DB.DB.Where("menu_id = ?", menuId).Delete(&entity.UserLevelMenuActionAccesses{}).Error
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesRepository) DeleteByUserLevelIdAndMenuId(userLevelId uint, menuId uint) (err error) {
|
||||
return _i.DB.DB.Where("user_level_id = ? AND menu_id = ?", userLevelId, menuId).Delete(&entity.UserLevelMenuActionAccesses{}).Error
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package request
|
||||
|
||||
import (
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type UserLevelMenuActionAccessesQueryRequest struct {
|
||||
UserLevelId *uint `query:"user_level_id"`
|
||||
MenuId *uint `query:"menu_id"`
|
||||
ActionCode *string `query:"action_code"`
|
||||
ClientId *uuid.UUID `query:"client_id"`
|
||||
CanAccess *bool `query:"can_access"`
|
||||
Pagination *paginator.Pagination `query:"pagination"`
|
||||
}
|
||||
|
||||
type UserLevelMenuActionAccessesCreateRequest struct {
|
||||
UserLevelId uint `json:"userLevelId" validate:"required"`
|
||||
MenuId uint `json:"menuId" validate:"required"`
|
||||
ActionCode string `json:"actionCode" validate:"required"`
|
||||
CanAccess bool `json:"canAccess"`
|
||||
ClientId *uuid.UUID `json:"clientId"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
}
|
||||
|
||||
func (req UserLevelMenuActionAccessesCreateRequest) ToEntity() *entity.UserLevelMenuActionAccesses {
|
||||
return &entity.UserLevelMenuActionAccesses{
|
||||
UserLevelId: req.UserLevelId,
|
||||
MenuId: req.MenuId,
|
||||
ActionCode: req.ActionCode,
|
||||
CanAccess: req.CanAccess,
|
||||
ClientId: req.ClientId,
|
||||
IsActive: req.IsActive,
|
||||
}
|
||||
}
|
||||
|
||||
type UserLevelMenuActionAccessesUpdateRequest struct {
|
||||
UserLevelId *uint `json:"userLevelId"`
|
||||
MenuId *uint `json:"menuId"`
|
||||
ActionCode *string `json:"actionCode"`
|
||||
CanAccess *bool `json:"canAccess"`
|
||||
ClientId *uuid.UUID `json:"clientId"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
}
|
||||
|
||||
func (req UserLevelMenuActionAccessesUpdateRequest) ToEntity() *entity.UserLevelMenuActionAccesses {
|
||||
access := &entity.UserLevelMenuActionAccesses{}
|
||||
if req.UserLevelId != nil {
|
||||
access.UserLevelId = *req.UserLevelId
|
||||
}
|
||||
if req.MenuId != nil {
|
||||
access.MenuId = *req.MenuId
|
||||
}
|
||||
if req.ActionCode != nil {
|
||||
access.ActionCode = *req.ActionCode
|
||||
}
|
||||
if req.CanAccess != nil {
|
||||
access.CanAccess = *req.CanAccess
|
||||
}
|
||||
access.ClientId = req.ClientId
|
||||
access.IsActive = req.IsActive
|
||||
return access
|
||||
}
|
||||
|
||||
type UserLevelMenuActionAccessesBatchCreateRequest struct {
|
||||
UserLevelId uint `json:"userLevelId" validate:"required"`
|
||||
MenuId uint `json:"menuId" validate:"required"`
|
||||
ActionCodes []string `json:"actionCodes" validate:"required,min=1"`
|
||||
ClientId *uuid.UUID `json:"clientId"`
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package response
|
||||
|
||||
import "time"
|
||||
|
||||
type UserLevelMenuActionAccessesResponse struct {
|
||||
ID uint `json:"id"`
|
||||
UserLevelId uint `json:"userLevelId"`
|
||||
MenuId uint `json:"menuId"`
|
||||
ActionCode string `json:"actionCode"`
|
||||
CanAccess bool `json:"canAccess"`
|
||||
IsActive *bool `json:"isActive"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
"netidhub-saas-be/app/database/entity"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/mapper"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/repository"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/request"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/response"
|
||||
"netidhub-saas-be/utils/paginator"
|
||||
)
|
||||
|
||||
// UserLevelMenuActionAccessesService
|
||||
type userLevelMenuActionAccessesService struct {
|
||||
Repo repository.UserLevelMenuActionAccessesRepository
|
||||
Log zerolog.Logger
|
||||
}
|
||||
|
||||
// UserLevelMenuActionAccessesService define interface of IUserLevelMenuActionAccessesService
|
||||
type UserLevelMenuActionAccessesService interface {
|
||||
All(req request.UserLevelMenuActionAccessesQueryRequest) (accesses []*response.UserLevelMenuActionAccessesResponse, paging paginator.Pagination, err error)
|
||||
GetByUserLevelId(userLevelId uint) (accesses []*response.UserLevelMenuActionAccessesResponse, err error)
|
||||
GetByUserLevelIdAndMenuId(userLevelId uint, menuId uint) (accesses []*response.UserLevelMenuActionAccessesResponse, err error)
|
||||
GetByMenuId(menuId uint) (accesses []*response.UserLevelMenuActionAccessesResponse, err error)
|
||||
CheckAccess(userLevelId uint, menuId uint, actionCode string) (hasAccess bool, err error)
|
||||
Show(id uint) (access *response.UserLevelMenuActionAccessesResponse, err error)
|
||||
Save(req request.UserLevelMenuActionAccessesCreateRequest) (err error)
|
||||
SaveBatch(req request.UserLevelMenuActionAccessesBatchCreateRequest) (err error)
|
||||
Update(id uint, req request.UserLevelMenuActionAccessesUpdateRequest) (err error)
|
||||
Delete(id uint) error
|
||||
}
|
||||
|
||||
// NewUserLevelMenuActionAccessesService init UserLevelMenuActionAccessesService
|
||||
func NewUserLevelMenuActionAccessesService(repo repository.UserLevelMenuActionAccessesRepository, log zerolog.Logger) UserLevelMenuActionAccessesService {
|
||||
return &userLevelMenuActionAccessesService{
|
||||
Repo: repo,
|
||||
Log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// All implement interface of UserLevelMenuActionAccessesService
|
||||
func (_i *userLevelMenuActionAccessesService) All(req request.UserLevelMenuActionAccessesQueryRequest) (accesses []*response.UserLevelMenuActionAccessesResponse, paging paginator.Pagination, err error) {
|
||||
results, paging, err := _i.Repo.GetAll(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
accesses = append(accesses, mapper.UserLevelMenuActionAccessesResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesService) GetByUserLevelId(userLevelId uint) (accesses []*response.UserLevelMenuActionAccessesResponse, err error) {
|
||||
results, err := _i.Repo.GetByUserLevelId(userLevelId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
accesses = append(accesses, mapper.UserLevelMenuActionAccessesResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesService) GetByUserLevelIdAndMenuId(userLevelId uint, menuId uint) (accesses []*response.UserLevelMenuActionAccessesResponse, err error) {
|
||||
results, err := _i.Repo.GetByUserLevelIdAndMenuId(userLevelId, menuId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
accesses = append(accesses, mapper.UserLevelMenuActionAccessesResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesService) GetByMenuId(menuId uint) (accesses []*response.UserLevelMenuActionAccessesResponse, err error) {
|
||||
results, err := _i.Repo.GetByMenuId(menuId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
accesses = append(accesses, mapper.UserLevelMenuActionAccessesResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesService) CheckAccess(userLevelId uint, menuId uint, actionCode string) (hasAccess bool, err error) {
|
||||
return _i.Repo.CheckAccess(userLevelId, menuId, actionCode)
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesService) Show(id uint) (access *response.UserLevelMenuActionAccessesResponse, err error) {
|
||||
result, err := _i.Repo.FindOne(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapper.UserLevelMenuActionAccessesResponseMapper(result), nil
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesService) Save(req request.UserLevelMenuActionAccessesCreateRequest) (err error) {
|
||||
_i.Log.Info().Interface("data", req).Msg("Creating user level menu action access")
|
||||
|
||||
isActive := true
|
||||
if req.IsActive != nil {
|
||||
isActive = *req.IsActive
|
||||
}
|
||||
|
||||
access := req.ToEntity()
|
||||
access.IsActive = &isActive
|
||||
|
||||
return _i.Repo.Create(access)
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesService) SaveBatch(req request.UserLevelMenuActionAccessesBatchCreateRequest) (err error) {
|
||||
_i.Log.Info().Interface("data", req).Msg("Creating user level menu action accesses batch")
|
||||
|
||||
isActive := true
|
||||
var accesses []*entity.UserLevelMenuActionAccesses
|
||||
|
||||
for _, actionCode := range req.ActionCodes {
|
||||
access := &entity.UserLevelMenuActionAccesses{
|
||||
UserLevelId: req.UserLevelId,
|
||||
MenuId: req.MenuId,
|
||||
ActionCode: actionCode,
|
||||
CanAccess: true,
|
||||
ClientId: req.ClientId,
|
||||
IsActive: &isActive,
|
||||
}
|
||||
accesses = append(accesses, access)
|
||||
}
|
||||
|
||||
return _i.Repo.CreateBatch(accesses)
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesService) Update(id uint, req request.UserLevelMenuActionAccessesUpdateRequest) (err error) {
|
||||
_i.Log.Info().Interface("data", req).Msg("Updating user level menu action access")
|
||||
|
||||
isActive := true
|
||||
if req.IsActive != nil {
|
||||
isActive = *req.IsActive
|
||||
}
|
||||
|
||||
access := req.ToEntity()
|
||||
access.IsActive = &isActive
|
||||
|
||||
return _i.Repo.Update(id, access)
|
||||
}
|
||||
|
||||
func (_i *userLevelMenuActionAccessesService) Delete(id uint) error {
|
||||
result, err := _i.Repo.FindOne(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isActive := false
|
||||
result.IsActive = &isActive
|
||||
return _i.Repo.Update(id, result)
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package user_level_menu_action_accesses
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/fx"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/controller"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/repository"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses/service"
|
||||
)
|
||||
|
||||
// struct of UserLevelMenuActionAccessesRouter
|
||||
type UserLevelMenuActionAccessesRouter struct {
|
||||
App fiber.Router
|
||||
Controller *controller.Controller
|
||||
}
|
||||
|
||||
// register bulky of UserLevelMenuActionAccesses module
|
||||
var NewUserLevelMenuActionAccessesModule = fx.Options(
|
||||
// register repository of UserLevelMenuActionAccesses module
|
||||
fx.Provide(repository.NewUserLevelMenuActionAccessesRepository),
|
||||
|
||||
// register service of UserLevelMenuActionAccesses module
|
||||
fx.Provide(service.NewUserLevelMenuActionAccessesService),
|
||||
|
||||
// register controller of UserLevelMenuActionAccesses module
|
||||
fx.Provide(controller.NewController),
|
||||
|
||||
// register router of UserLevelMenuActionAccesses module
|
||||
fx.Provide(NewUserLevelMenuActionAccessesRouter),
|
||||
)
|
||||
|
||||
// init UserLevelMenuActionAccessesRouter
|
||||
func NewUserLevelMenuActionAccessesRouter(fiber *fiber.App, controller *controller.Controller) *UserLevelMenuActionAccessesRouter {
|
||||
return &UserLevelMenuActionAccessesRouter{
|
||||
App: fiber,
|
||||
Controller: controller,
|
||||
}
|
||||
}
|
||||
|
||||
// register routes of UserLevelMenuActionAccesses module
|
||||
func (_i *UserLevelMenuActionAccessesRouter) RegisterUserLevelMenuActionAccessesRoutes() {
|
||||
// define controllers
|
||||
userLevelMenuActionAccessesController := _i.Controller.UserLevelMenuActionAccesses
|
||||
|
||||
// define routes
|
||||
_i.App.Route("/user-level-menu-action-accesses", func(router fiber.Router) {
|
||||
router.Get("/", userLevelMenuActionAccessesController.All)
|
||||
router.Get("/:id", userLevelMenuActionAccessesController.Show)
|
||||
router.Get("/user-level/:user_level_id", userLevelMenuActionAccessesController.GetByUserLevelId)
|
||||
router.Get("/user-level/:user_level_id/menu/:menu_id", userLevelMenuActionAccessesController.GetByUserLevelIdAndMenuId)
|
||||
router.Get("/menu/:menu_id", userLevelMenuActionAccessesController.GetByMenuId)
|
||||
router.Get("/check/:user_level_id/:menu_id/:action_code", userLevelMenuActionAccessesController.CheckAccess)
|
||||
router.Post("/", userLevelMenuActionAccessesController.Save)
|
||||
router.Post("/batch", userLevelMenuActionAccessesController.SaveBatch)
|
||||
router.Put("/:id", userLevelMenuActionAccessesController.Update)
|
||||
router.Delete("/:id", userLevelMenuActionAccessesController.Delete)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +58,7 @@ func (_i *userLevelModuleAccessesRepository) GetAll(req request.UserLevelModuleA
|
|||
|
||||
query.Count(&count)
|
||||
|
||||
// Apply sorting
|
||||
if req.Pagination.SortBy != "" {
|
||||
direction := "ASC"
|
||||
if req.Pagination.Sort == "desc" {
|
||||
|
|
@ -66,15 +67,29 @@ func (_i *userLevelModuleAccessesRepository) GetAll(req request.UserLevelModuleA
|
|||
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
||||
}
|
||||
|
||||
req.Pagination.Count = count
|
||||
req.Pagination = paginator.Paging(req.Pagination)
|
||||
// Apply pagination (manual calculation like articles)
|
||||
page := req.Pagination.Page
|
||||
limit := req.Pagination.Limit
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&accesses).Error
|
||||
offset := (page - 1) * limit
|
||||
err = query.Offset(offset).Limit(limit).Find(&accesses).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
paging = *req.Pagination
|
||||
// Create pagination response
|
||||
paging = paginator.Pagination{
|
||||
Page: page,
|
||||
Limit: limit,
|
||||
Count: count,
|
||||
TotalPage: int((count + int64(limit) - 1) / int64(limit)),
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ import (
|
|||
)
|
||||
|
||||
type UserLevelModuleAccessesQueryRequest struct {
|
||||
UserLevelId *uint `query:"user_level_id"`
|
||||
ModuleId *uint `query:"module_id"`
|
||||
CanAccess *bool `query:"can_access"`
|
||||
ClientId *uuid.UUID `query:"client_id"`
|
||||
Pagination *paginator.Query `query:"pagination"`
|
||||
UserLevelId *uint `query:"user_level_id"`
|
||||
ModuleId *uint `query:"module_id"`
|
||||
CanAccess *bool `query:"can_access"`
|
||||
ClientId *uuid.UUID `query:"client_id"`
|
||||
Pagination *paginator.Pagination `query:"pagination"`
|
||||
}
|
||||
|
||||
type UserLevelModuleAccessesCreateRequest struct {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ import (
|
|||
"netidhub-saas-be/app/module/magazines"
|
||||
"netidhub-saas-be/app/module/master_menus"
|
||||
"netidhub-saas-be/app/module/master_modules"
|
||||
"netidhub-saas-be/app/module/menu_actions"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses"
|
||||
"netidhub-saas-be/app/module/provinces"
|
||||
"netidhub-saas-be/app/module/schedules"
|
||||
"netidhub-saas-be/app/module/subscription"
|
||||
|
|
@ -65,9 +68,12 @@ type Router struct {
|
|||
FeedbacksRouter *feedbacks.FeedbacksRouter
|
||||
MagazineFilesRouter *magazine_files.MagazineFilesRouter
|
||||
MagazinesRouter *magazines.MagazinesRouter
|
||||
MasterMenusRouter *master_menus.MasterMenusRouter
|
||||
MasterModulesRouter *master_modules.MasterModulesRouter
|
||||
ProvincesRouter *provinces.ProvincesRouter
|
||||
MasterMenusRouter *master_menus.MasterMenusRouter
|
||||
MasterModulesRouter *master_modules.MasterModulesRouter
|
||||
MenuActionsRouter *menu_actions.MenuActionsRouter
|
||||
UserLevelMenuAccessesRouter *user_level_menu_accesses.UserLevelMenuAccessesRouter
|
||||
UserLevelMenuActionAccessesRouter *user_level_menu_action_accesses.UserLevelMenuActionAccessesRouter
|
||||
ProvincesRouter *provinces.ProvincesRouter
|
||||
SchedulesRouter *schedules.SchedulesRouter
|
||||
SubscriptionRouter *subscription.SubscriptionRouter
|
||||
UserLevelsRouter *user_levels.UserLevelsRouter
|
||||
|
|
@ -104,6 +110,9 @@ func NewRouter(
|
|||
magazinesRouter *magazines.MagazinesRouter,
|
||||
masterMenuRouter *master_menus.MasterMenusRouter,
|
||||
masterModuleRouter *master_modules.MasterModulesRouter,
|
||||
menuActionsRouter *menu_actions.MenuActionsRouter,
|
||||
userLevelMenuAccessesRouter *user_level_menu_accesses.UserLevelMenuAccessesRouter,
|
||||
userLevelMenuActionAccessesRouter *user_level_menu_action_accesses.UserLevelMenuActionAccessesRouter,
|
||||
provincesRouter *provinces.ProvincesRouter,
|
||||
schedulesRouter *schedules.SchedulesRouter,
|
||||
subscriptionRouter *subscription.SubscriptionRouter,
|
||||
|
|
@ -137,9 +146,12 @@ func NewRouter(
|
|||
FeedbacksRouter: feedbacksRouter,
|
||||
MagazineFilesRouter: magazineFilesRouter,
|
||||
MagazinesRouter: magazinesRouter,
|
||||
MasterMenusRouter: masterMenuRouter,
|
||||
MasterModulesRouter: masterModuleRouter,
|
||||
ProvincesRouter: provincesRouter,
|
||||
MasterMenusRouter: masterMenuRouter,
|
||||
MasterModulesRouter: masterModuleRouter,
|
||||
MenuActionsRouter: menuActionsRouter,
|
||||
UserLevelMenuAccessesRouter: userLevelMenuAccessesRouter,
|
||||
UserLevelMenuActionAccessesRouter: userLevelMenuActionAccessesRouter,
|
||||
ProvincesRouter: provincesRouter,
|
||||
SchedulesRouter: schedulesRouter,
|
||||
SubscriptionRouter: subscriptionRouter,
|
||||
UserLevelsRouter: userLevelsRouter,
|
||||
|
|
@ -184,6 +196,9 @@ func (r *Router) Register() {
|
|||
r.MagazineFilesRouter.RegisterMagazineFilesRoutes()
|
||||
r.MasterMenusRouter.RegisterMasterMenusRoutes()
|
||||
r.MasterModulesRouter.RegisterMasterModulesRoutes()
|
||||
r.MenuActionsRouter.RegisterMenuActionsRoutes()
|
||||
r.UserLevelMenuAccessesRouter.RegisterUserLevelMenuAccessesRoutes()
|
||||
r.UserLevelMenuActionAccessesRouter.RegisterUserLevelMenuActionAccessesRoutes()
|
||||
r.ProvincesRouter.RegisterProvincesRoutes()
|
||||
r.SchedulesRouter.RegisterSchedulesRoutes()
|
||||
r.SubscriptionRouter.RegisterSubscriptionRoutes()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,311 @@
|
|||
# 📋 Plan: Menu & Action Access Control System
|
||||
|
||||
## 🎯 Tujuan
|
||||
|
||||
Membangun sistem akses kontrol yang memungkinkan:
|
||||
1. **1 Menu memiliki banyak Actions** - Satu menu dapat memiliki berbagai action (view table, create, edit, delete, approve, export, dll)
|
||||
2. **User Level dapat di-assign Menu** - Setiap user level dapat di-assign menu apa saja yang bisa diakses
|
||||
3. **User Level dapat di-assign Actions per Menu** - Setiap user level dapat di-assign action apa saja yang bisa dilakukan di setiap menu (contoh: Creator hanya bisa create dan edit, Approver bisa delete)
|
||||
|
||||
## 🔍 Analisis Kebutuhan
|
||||
|
||||
### Use Case 1: Menu "Content Management"
|
||||
- **Actions yang tersedia:**
|
||||
- `view` - Melihat daftar content
|
||||
- `create` - Membuat content baru
|
||||
- `edit` - Mengedit content yang ada
|
||||
- `delete` - Menghapus content
|
||||
- `approve` - Approve content
|
||||
- `export` - Export data content
|
||||
|
||||
### Use Case 2: User Level "Creator"
|
||||
- **Menu yang bisa diakses:** Content Management
|
||||
- **Actions yang bisa dilakukan:**
|
||||
- ✅ `view` - Bisa melihat daftar
|
||||
- ✅ `create` - Bisa membuat baru
|
||||
- ✅ `edit` - Bisa mengedit
|
||||
- ❌ `delete` - Tidak bisa menghapus
|
||||
- ❌ `approve` - Tidak bisa approve
|
||||
- ❌ `export` - Tidak bisa export
|
||||
|
||||
### Use Case 3: User Level "Approver"
|
||||
- **Menu yang bisa diakses:** Content Management
|
||||
- **Actions yang bisa dilakukan:**
|
||||
- ✅ `view` - Bisa melihat daftar
|
||||
- ❌ `create` - Tidak bisa membuat baru
|
||||
- ❌ `edit` - Tidak bisa mengedit
|
||||
- ✅ `delete` - Bisa menghapus
|
||||
- ✅ `approve` - Bisa approve
|
||||
- ✅ `export` - Bisa export
|
||||
|
||||
## 🏗️ Arsitektur Sistem
|
||||
|
||||
### Opsi 1: Menu-Action Based (Recommended) ⭐
|
||||
|
||||
**Konsep:**
|
||||
- Menu memiliki Actions langsung (bukan melalui Module)
|
||||
- User Level memiliki akses ke Menu
|
||||
- User Level memiliki akses ke Actions di dalam Menu
|
||||
|
||||
**Struktur Database:**
|
||||
|
||||
#### 1. `master_menus` (Existing - Enhanced)
|
||||
```sql
|
||||
-- Sudah ada, tidak perlu perubahan
|
||||
-- Menu seperti: "Content Management", "User Management", "Settings"
|
||||
```
|
||||
|
||||
#### 2. `menu_actions` (New)
|
||||
```sql
|
||||
CREATE TABLE menu_actions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
menu_id INT NOT NULL,
|
||||
action_code VARCHAR(50) NOT NULL, -- 'view', 'create', 'edit', 'delete', 'approve', 'export'
|
||||
action_name VARCHAR(255) NOT NULL, -- 'View Content', 'Create Content', etc.
|
||||
description TEXT NULL,
|
||||
path_url VARCHAR(255) NULL, -- Optional: untuk routing frontend
|
||||
http_method VARCHAR(10) NULL, -- Optional: 'GET', 'POST', 'PUT', 'DELETE'
|
||||
position INT NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (menu_id) REFERENCES master_menus(id) ON DELETE CASCADE,
|
||||
UNIQUE(menu_id, action_code)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_menu_actions_menu_id ON menu_actions(menu_id);
|
||||
CREATE INDEX idx_menu_actions_action_code ON menu_actions(action_code);
|
||||
```
|
||||
|
||||
#### 3. `user_level_menu_accesses` (New)
|
||||
```sql
|
||||
CREATE TABLE user_level_menu_accesses (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_level_id INT NOT NULL,
|
||||
menu_id INT NOT NULL,
|
||||
can_access BOOLEAN DEFAULT TRUE,
|
||||
client_id UUID NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (user_level_id) REFERENCES user_levels(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (menu_id) REFERENCES master_menus(id) ON DELETE CASCADE,
|
||||
UNIQUE(user_level_id, menu_id, client_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_level_menu_accesses_user_level_id ON user_level_menu_accesses(user_level_id);
|
||||
CREATE INDEX idx_user_level_menu_accesses_menu_id ON user_level_menu_accesses(menu_id);
|
||||
```
|
||||
|
||||
#### 4. `user_level_menu_action_accesses` (New)
|
||||
```sql
|
||||
CREATE TABLE user_level_menu_action_accesses (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_level_id INT NOT NULL,
|
||||
menu_id INT NOT NULL,
|
||||
action_code VARCHAR(50) NOT NULL,
|
||||
can_access BOOLEAN DEFAULT TRUE,
|
||||
client_id UUID NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (user_level_id) REFERENCES user_levels(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (menu_id) REFERENCES master_menus(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (menu_id, action_code) REFERENCES menu_actions(menu_id, action_code) ON DELETE CASCADE,
|
||||
UNIQUE(user_level_id, menu_id, action_code, client_id)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_user_level_menu_action_accesses_user_level_id ON user_level_menu_action_accesses(user_level_id);
|
||||
CREATE INDEX idx_user_level_menu_action_accesses_menu_id ON user_level_menu_action_accesses(menu_id);
|
||||
CREATE INDEX idx_user_level_menu_action_accesses_action_code ON user_level_menu_action_accesses(action_code);
|
||||
```
|
||||
|
||||
**Relasi:**
|
||||
```
|
||||
master_menus (1) ─────< (N) menu_actions
|
||||
│ │
|
||||
│ │
|
||||
│ (1) │ (N)
|
||||
│ │
|
||||
∨ ∨
|
||||
user_level_menu_accesses user_level_menu_action_accesses
|
||||
│ │
|
||||
│ (N) │ (N)
|
||||
│ │
|
||||
∨ ∨
|
||||
user_levels (1) ──────────────┘
|
||||
```
|
||||
|
||||
**Keuntungan:**
|
||||
- ✅ Lebih sederhana dan intuitif
|
||||
- ✅ Langsung ke point: Menu → Actions
|
||||
- ✅ Mudah di-manage: assign menu, lalu assign actions
|
||||
- ✅ Tidak perlu konsep "Module" yang membingungkan
|
||||
- ✅ Frontend lebih mudah: cek menu access, lalu cek action access
|
||||
|
||||
**Kekurangan:**
|
||||
- ❌ Perlu migration dari sistem Module yang ada
|
||||
- ❌ Perlu refactor middleware dan service yang sudah ada
|
||||
|
||||
---
|
||||
|
||||
### Opsi 2: Keep Module, Enhance Structure
|
||||
|
||||
**Konsep:**
|
||||
- Tetap menggunakan Module, tapi Module sekarang lebih spesifik ke Menu
|
||||
- Module = Action di dalam Menu
|
||||
- User Level memiliki akses ke Menu
|
||||
- User Level memiliki akses ke Module (Action) di dalam Menu
|
||||
|
||||
**Struktur Database:**
|
||||
|
||||
#### 1. `master_menus` (Existing)
|
||||
```sql
|
||||
-- Tidak berubah
|
||||
```
|
||||
|
||||
#### 2. `master_modules` (Existing - Enhanced)
|
||||
```sql
|
||||
-- Tetap ada, tapi sekarang lebih spesifik:
|
||||
-- Module sekarang = Action di dalam Menu
|
||||
-- action_type menjadi lebih penting
|
||||
```
|
||||
|
||||
#### 3. `menu_modules` (Existing - Enhanced)
|
||||
```sql
|
||||
-- Tetap ada, relasi Menu dengan Module (Action)
|
||||
-- Tapi sekarang lebih strict: 1 module hanya untuk 1 menu
|
||||
```
|
||||
|
||||
#### 4. `user_level_menu_accesses` (New)
|
||||
```sql
|
||||
-- Sama seperti Opsi 1
|
||||
```
|
||||
|
||||
#### 5. `user_level_module_accesses` (Existing)
|
||||
```sql
|
||||
-- Tetap ada, tapi sekarang lebih spesifik:
|
||||
-- Module = Action di dalam Menu
|
||||
```
|
||||
|
||||
**Keuntungan:**
|
||||
- ✅ Tidak perlu migration besar-besaran
|
||||
- ✅ Bisa reuse struktur yang sudah ada
|
||||
- ✅ Lebih fleksibel (module bisa digunakan oleh banyak menu)
|
||||
|
||||
**Kekurangan:**
|
||||
- ❌ Konsep "Module" masih membingungkan
|
||||
- ❌ Lebih kompleks: Menu → Module → Action
|
||||
- ❌ Perlu mapping yang lebih kompleks
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Rekomendasi: Opsi 1 (Menu-Action Based)
|
||||
|
||||
**Alasan:**
|
||||
1. **Lebih intuitif** - Langsung ke point: Menu punya Actions
|
||||
2. **Lebih mudah di-manage** - Admin langsung assign menu dan actions
|
||||
3. **Lebih mudah di-frontend** - Cek menu access, lalu cek action access
|
||||
4. **Lebih scalable** - Mudah ditambah menu baru dengan actions baru
|
||||
5. **Lebih maintainable** - Struktur lebih jelas dan mudah dipahami
|
||||
|
||||
## 📝 Implementation Plan
|
||||
|
||||
### Phase 1: Database Schema
|
||||
1. ✅ Buat tabel `menu_actions`
|
||||
2. ✅ Buat tabel `user_level_menu_accesses`
|
||||
3. ✅ Buat tabel `user_level_menu_action_accesses`
|
||||
4. ✅ Buat migration script
|
||||
5. ✅ Migrate data dari `master_modules` dan `menu_modules` ke `menu_actions` (jika perlu)
|
||||
|
||||
### Phase 2: Backend Entities & Repositories
|
||||
1. ✅ Buat entity `MenuActions`
|
||||
2. ✅ Buat entity `UserLevelMenuAccesses`
|
||||
3. ✅ Buat entity `UserLevelMenuActionAccesses`
|
||||
4. ✅ Buat repository untuk masing-masing entity
|
||||
5. ✅ Buat service untuk masing-masing entity
|
||||
|
||||
### Phase 3: Backend API Endpoints
|
||||
1. ✅ CRUD API untuk `menu_actions`
|
||||
2. ✅ CRUD API untuk `user_level_menu_accesses`
|
||||
3. ✅ CRUD API untuk `user_level_menu_action_accesses`
|
||||
4. ✅ API untuk get menu actions by menu_id
|
||||
5. ✅ API untuk get user level menu accesses
|
||||
6. ✅ API untuk get user level menu action accesses
|
||||
|
||||
### Phase 4: Backend Middleware
|
||||
1. ✅ Buat middleware `CheckMenuAccess` - cek apakah user level bisa akses menu
|
||||
2. ✅ Buat middleware `CheckMenuActionAccess` - cek apakah user level bisa akses action di menu
|
||||
3. ✅ Update existing middleware untuk menggunakan struktur baru
|
||||
|
||||
### Phase 5: Frontend Services
|
||||
1. ✅ Buat service untuk `menu_actions`
|
||||
2. ✅ Buat service untuk `user_level_menu_accesses`
|
||||
3. ✅ Buat service untuk `user_level_menu_action_accesses`
|
||||
4. ✅ Update existing services
|
||||
|
||||
### Phase 6: Frontend UI - Menu Management
|
||||
1. ✅ Update halaman Menu Management untuk menampilkan Actions
|
||||
2. ✅ Tambah form untuk manage Actions di setiap Menu
|
||||
3. ✅ Tambah UI untuk assign Actions ke Menu
|
||||
|
||||
### Phase 7: Frontend UI - User Level Management
|
||||
1. ✅ Update halaman User Level Management
|
||||
2. ✅ Tambah tab "Menu Access" untuk assign menu ke user level
|
||||
3. ✅ Tambah tab "Action Access" untuk assign actions per menu ke user level
|
||||
4. ✅ Update form User Level untuk include menu dan action access
|
||||
|
||||
### Phase 8: Frontend UI - Permission Check
|
||||
1. ✅ Buat hook `useMenuAccess` untuk cek menu access
|
||||
2. ✅ Buat hook `useMenuActionAccess` untuk cek action access
|
||||
3. ✅ Update components untuk menggunakan hooks
|
||||
4. ✅ Hide/show UI elements berdasarkan permission
|
||||
|
||||
### Phase 9: Testing & Documentation
|
||||
1. ✅ Test semua API endpoints
|
||||
2. ✅ Test middleware
|
||||
3. ✅ Test frontend UI
|
||||
4. ✅ Update documentation
|
||||
|
||||
## 🔄 Migration Strategy
|
||||
|
||||
### Option A: Clean Slate (Recommended)
|
||||
- Buat struktur baru dari awal
|
||||
- Data lama tetap ada tapi tidak digunakan
|
||||
- Migrate data secara bertahap jika perlu
|
||||
|
||||
### Option B: Gradual Migration
|
||||
- Keep struktur lama dan baru berjalan bersamaan
|
||||
- Migrate data dari lama ke baru
|
||||
- Deprecate struktur lama setelah semua ter-migrate
|
||||
|
||||
## 📊 Comparison: Current vs Proposed
|
||||
|
||||
### Current System
|
||||
```
|
||||
Menu → Module (via menu_modules) → User Level Access (via user_level_module_accesses)
|
||||
```
|
||||
- Module adalah entitas terpisah
|
||||
- Module bisa digunakan oleh banyak menu
|
||||
- Akses diberikan ke Module, bukan ke Menu + Action
|
||||
|
||||
### Proposed System
|
||||
```
|
||||
Menu → Actions (via menu_actions) → User Level Menu Access → User Level Action Access
|
||||
```
|
||||
- Actions langsung di dalam Menu
|
||||
- Actions spesifik untuk Menu tertentu
|
||||
- Akses diberikan ke Menu dan Actions secara terpisah
|
||||
|
||||
## ✅ Next Steps
|
||||
|
||||
1. **Review & Approval** - Review plan ini dengan tim
|
||||
2. **Decision** - Pilih antara Opsi 1 atau Opsi 2
|
||||
3. **Database Design** - Finalize database schema
|
||||
4. **Implementation** - Mulai implementasi sesuai phase yang sudah direncanakan
|
||||
|
||||
## 📚 Reference
|
||||
|
||||
- Current system: `docs/MENU_MODULE_ACCESS_SYSTEM.md`
|
||||
- Implementation summary: `docs/IMPLEMENTATION_SUMMARY_MENU_MODULE_ACCESS.md`
|
||||
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
-- Migration: Add Menu Action Access System
|
||||
-- Description: Create menu_actions, user_level_menu_accesses, and user_level_menu_action_accesses tables
|
||||
-- Date: 2026-01-16
|
||||
|
||||
-- ============================================================================
|
||||
-- Step 1: Create menu_actions table
|
||||
-- ============================================================================
|
||||
CREATE TABLE IF NOT EXISTS menu_actions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
menu_id INT NOT NULL,
|
||||
action_code VARCHAR(50) NOT NULL,
|
||||
action_name VARCHAR(255) NOT NULL,
|
||||
description TEXT NULL,
|
||||
path_url VARCHAR(255) NULL,
|
||||
http_method VARCHAR(10) NULL,
|
||||
position INT NULL,
|
||||
client_id UUID NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (menu_id) REFERENCES master_menus(id) ON DELETE CASCADE,
|
||||
UNIQUE(menu_id, action_code, COALESCE(client_id, '00000000-0000-0000-0000-000000000000'::UUID))
|
||||
);
|
||||
|
||||
-- Add indexes for performance
|
||||
CREATE INDEX idx_menu_actions_menu_id ON menu_actions(menu_id);
|
||||
CREATE INDEX idx_menu_actions_action_code ON menu_actions(action_code);
|
||||
CREATE INDEX idx_menu_actions_client_id ON menu_actions(client_id) WHERE client_id IS NOT NULL;
|
||||
CREATE INDEX idx_menu_actions_is_active ON menu_actions(is_active);
|
||||
|
||||
-- Add comments
|
||||
COMMENT ON TABLE menu_actions IS 'Actions yang tersedia di setiap menu (view, create, edit, delete, approve, export, etc)';
|
||||
COMMENT ON COLUMN menu_actions.menu_id IS 'Foreign key ke master_menus';
|
||||
COMMENT ON COLUMN menu_actions.action_code IS 'Kode action: view, create, edit, delete, approve, export, etc';
|
||||
COMMENT ON COLUMN menu_actions.action_name IS 'Nama action yang ditampilkan ke user';
|
||||
COMMENT ON COLUMN menu_actions.path_url IS 'Optional: URL path untuk routing frontend';
|
||||
COMMENT ON COLUMN menu_actions.http_method IS 'Optional: HTTP method (GET, POST, PUT, DELETE)';
|
||||
|
||||
-- ============================================================================
|
||||
-- Step 2: Create user_level_menu_accesses table
|
||||
-- ============================================================================
|
||||
CREATE TABLE IF NOT EXISTS user_level_menu_accesses (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_level_id INT NOT NULL,
|
||||
menu_id INT NOT NULL,
|
||||
can_access BOOLEAN DEFAULT TRUE,
|
||||
client_id UUID NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (user_level_id) REFERENCES user_levels(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (menu_id) REFERENCES master_menus(id) ON DELETE CASCADE,
|
||||
UNIQUE(user_level_id, menu_id, COALESCE(client_id, '00000000-0000-0000-0000-000000000000'::UUID))
|
||||
);
|
||||
|
||||
-- Add indexes for performance
|
||||
CREATE INDEX idx_user_level_menu_accesses_user_level_id ON user_level_menu_accesses(user_level_id);
|
||||
CREATE INDEX idx_user_level_menu_accesses_menu_id ON user_level_menu_accesses(menu_id);
|
||||
CREATE INDEX idx_user_level_menu_accesses_client_id ON user_level_menu_accesses(client_id) WHERE client_id IS NOT NULL;
|
||||
CREATE INDEX idx_user_level_menu_accesses_is_active ON user_level_menu_accesses(is_active);
|
||||
|
||||
-- Add comments
|
||||
COMMENT ON TABLE user_level_menu_accesses IS 'Mengatur akses user_level ke menu tertentu';
|
||||
COMMENT ON COLUMN user_level_menu_accesses.user_level_id IS 'Foreign key ke user_levels';
|
||||
COMMENT ON COLUMN user_level_menu_accesses.menu_id IS 'Foreign key ke master_menus';
|
||||
COMMENT ON COLUMN user_level_menu_accesses.can_access IS 'Apakah user level boleh mengakses menu ini';
|
||||
|
||||
-- ============================================================================
|
||||
-- Step 3: Create user_level_menu_action_accesses table
|
||||
-- ============================================================================
|
||||
CREATE TABLE IF NOT EXISTS user_level_menu_action_accesses (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_level_id INT NOT NULL,
|
||||
menu_id INT NOT NULL,
|
||||
action_code VARCHAR(50) NOT NULL,
|
||||
can_access BOOLEAN DEFAULT TRUE,
|
||||
client_id UUID NULL,
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
FOREIGN KEY (user_level_id) REFERENCES user_levels(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (menu_id) REFERENCES master_menus(id) ON DELETE CASCADE,
|
||||
UNIQUE(user_level_id, menu_id, action_code, COALESCE(client_id, '00000000-0000-0000-0000-000000000000'::UUID))
|
||||
);
|
||||
|
||||
-- Add indexes for performance
|
||||
CREATE INDEX idx_user_level_menu_action_accesses_user_level_id ON user_level_menu_action_accesses(user_level_id);
|
||||
CREATE INDEX idx_user_level_menu_action_accesses_menu_id ON user_level_menu_action_accesses(menu_id);
|
||||
CREATE INDEX idx_user_level_menu_action_accesses_action_code ON user_level_menu_action_accesses(action_code);
|
||||
CREATE INDEX idx_user_level_menu_action_accesses_client_id ON user_level_menu_action_accesses(client_id) WHERE client_id IS NOT NULL;
|
||||
CREATE INDEX idx_user_level_menu_action_accesses_is_active ON user_level_menu_action_accesses(is_active);
|
||||
|
||||
-- Add comments
|
||||
COMMENT ON TABLE user_level_menu_action_accesses IS 'Mengatur akses user_level ke action tertentu di dalam menu';
|
||||
COMMENT ON COLUMN user_level_menu_action_accesses.user_level_id IS 'Foreign key ke user_levels';
|
||||
COMMENT ON COLUMN user_level_menu_action_accesses.menu_id IS 'Foreign key ke master_menus';
|
||||
COMMENT ON COLUMN user_level_menu_action_accesses.action_code IS 'Kode action (harus sesuai dengan menu_actions.action_code)';
|
||||
COMMENT ON COLUMN user_level_menu_action_accesses.can_access IS 'Apakah user level boleh melakukan action ini';
|
||||
|
||||
-- ============================================================================
|
||||
-- Step 4: Create trigger for updated_at
|
||||
-- ============================================================================
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
-- Apply trigger to menu_actions
|
||||
DROP TRIGGER IF EXISTS update_menu_actions_updated_at ON menu_actions;
|
||||
CREATE TRIGGER update_menu_actions_updated_at
|
||||
BEFORE UPDATE ON menu_actions
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- Apply trigger to user_level_menu_accesses
|
||||
DROP TRIGGER IF EXISTS update_user_level_menu_accesses_updated_at ON user_level_menu_accesses;
|
||||
CREATE TRIGGER update_user_level_menu_accesses_updated_at
|
||||
BEFORE UPDATE ON user_level_menu_accesses
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- Apply trigger to user_level_menu_action_accesses
|
||||
DROP TRIGGER IF EXISTS update_user_level_menu_action_accesses_updated_at ON user_level_menu_action_accesses;
|
||||
CREATE TRIGGER update_user_level_menu_action_accesses_updated_at
|
||||
BEFORE UPDATE ON user_level_menu_action_accesses
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- ============================================================================
|
||||
-- Verification
|
||||
-- ============================================================================
|
||||
DO $$
|
||||
DECLARE
|
||||
v_menu_actions_exists BOOLEAN;
|
||||
v_user_level_menu_accesses_exists BOOLEAN;
|
||||
v_user_level_menu_action_accesses_exists BOOLEAN;
|
||||
BEGIN
|
||||
-- Check menu_actions table
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'menu_actions'
|
||||
) INTO v_menu_actions_exists;
|
||||
|
||||
-- Check user_level_menu_accesses table
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'user_level_menu_accesses'
|
||||
) INTO v_user_level_menu_accesses_exists;
|
||||
|
||||
-- Check user_level_menu_action_accesses table
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'user_level_menu_action_accesses'
|
||||
) INTO v_user_level_menu_action_accesses_exists;
|
||||
|
||||
-- Report results
|
||||
RAISE NOTICE '========================================';
|
||||
RAISE NOTICE 'Migration Verification Results:';
|
||||
RAISE NOTICE '========================================';
|
||||
|
||||
IF v_menu_actions_exists THEN
|
||||
RAISE NOTICE '✓ Table menu_actions created successfully';
|
||||
ELSE
|
||||
RAISE WARNING '✗ Table menu_actions NOT created';
|
||||
END IF;
|
||||
|
||||
IF v_user_level_menu_accesses_exists THEN
|
||||
RAISE NOTICE '✓ Table user_level_menu_accesses created successfully';
|
||||
ELSE
|
||||
RAISE WARNING '✗ Table user_level_menu_accesses NOT created';
|
||||
END IF;
|
||||
|
||||
IF v_user_level_menu_action_accesses_exists THEN
|
||||
RAISE NOTICE '✓ Table user_level_menu_action_accesses created successfully';
|
||||
ELSE
|
||||
RAISE WARNING '✗ Table user_level_menu_action_accesses NOT created';
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '========================================';
|
||||
|
||||
IF v_menu_actions_exists AND v_user_level_menu_accesses_exists AND v_user_level_menu_action_accesses_exists THEN
|
||||
RAISE NOTICE 'Migration completed successfully! ✓';
|
||||
ELSE
|
||||
RAISE WARNING 'Migration completed with errors! Please check above.';
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE '========================================';
|
||||
END $$;
|
||||
|
||||
1794
docs/swagger/docs.go
1794
docs/swagger/docs.go
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
6
main.go
6
main.go
|
|
@ -27,6 +27,9 @@ import (
|
|||
"netidhub-saas-be/app/module/magazines"
|
||||
"netidhub-saas-be/app/module/master_menus"
|
||||
"netidhub-saas-be/app/module/master_modules"
|
||||
"netidhub-saas-be/app/module/menu_actions"
|
||||
"netidhub-saas-be/app/module/user_level_menu_accesses"
|
||||
"netidhub-saas-be/app/module/user_level_menu_action_accesses"
|
||||
"netidhub-saas-be/app/module/provinces"
|
||||
"netidhub-saas-be/app/module/schedules"
|
||||
"netidhub-saas-be/app/module/subscription"
|
||||
|
|
@ -93,6 +96,9 @@ func main() {
|
|||
magazine_files.NewMagazineFilesModule,
|
||||
master_menus.NewMasterMenusModule,
|
||||
master_modules.NewMasterModulesModule,
|
||||
menu_actions.NewMenuActionsModule,
|
||||
user_level_menu_accesses.NewUserLevelMenuAccessesModule,
|
||||
user_level_menu_action_accesses.NewUserLevelMenuActionAccessesModule,
|
||||
provinces.NewProvincesModule,
|
||||
schedules.NewSchedulesModule,
|
||||
subscription.NewSubscriptionModule,
|
||||
|
|
|
|||
Loading…
Reference in New Issue