287 lines
7.8 KiB
Go
287 lines
7.8 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
|
|
"eslogad-be/internal/contract"
|
|
"eslogad-be/internal/entities"
|
|
"eslogad-be/internal/repository"
|
|
"eslogad-be/internal/transformer"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type RBACServiceImpl struct {
|
|
repo *repository.RBACRepository
|
|
}
|
|
|
|
func NewRBACService(repo *repository.RBACRepository) *RBACServiceImpl {
|
|
return &RBACServiceImpl{repo: repo}
|
|
}
|
|
|
|
// Permissions
|
|
func (s *RBACServiceImpl) CreatePermission(ctx context.Context, req *contract.CreatePermissionRequest) (*contract.PermissionResponse, error) {
|
|
p := &entities.Permission{Code: req.Code}
|
|
if req.Description != nil {
|
|
p.Description = *req.Description
|
|
}
|
|
if err := s.repo.CreatePermission(ctx, p); err != nil {
|
|
return nil, err
|
|
}
|
|
return &contract.PermissionResponse{
|
|
ID: p.ID,
|
|
Code: p.Code,
|
|
Action: p.Action,
|
|
Description: &p.Description,
|
|
}, nil
|
|
}
|
|
func (s *RBACServiceImpl) UpdatePermission(ctx context.Context, id uuid.UUID, req *contract.UpdatePermissionRequest) (*contract.PermissionResponse, error) {
|
|
p := &entities.Permission{ID: id}
|
|
if req.Code != nil {
|
|
p.Code = *req.Code
|
|
}
|
|
if req.Description != nil {
|
|
p.Description = *req.Description
|
|
}
|
|
if err := s.repo.UpdatePermission(ctx, p); err != nil {
|
|
return nil, err
|
|
}
|
|
// fetch full row
|
|
perms, err := s.repo.ListPermissions(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, x := range perms {
|
|
if x.ID == id {
|
|
return &contract.PermissionResponse{
|
|
ID: x.ID,
|
|
Code: x.Code,
|
|
Action: x.Action,
|
|
Description: &x.Description,
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
func (s *RBACServiceImpl) DeletePermission(ctx context.Context, id uuid.UUID) error {
|
|
return s.repo.DeletePermission(ctx, id)
|
|
}
|
|
func (s *RBACServiceImpl) ListPermissions(ctx context.Context) (*contract.ListPermissionsResponse, error) {
|
|
perms, err := s.repo.ListPermissions(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &contract.ListPermissionsResponse{Permissions: transformer.PermissionsToContract(perms)}, nil
|
|
}
|
|
|
|
// Roles
|
|
func (s *RBACServiceImpl) CreateRole(ctx context.Context, req *contract.CreateRoleRequest) (*contract.RoleWithPermissionsResponse, error) {
|
|
role := &entities.Role{Name: req.Name, Code: req.Code}
|
|
if req.Description != nil {
|
|
role.Description = *req.Description
|
|
}
|
|
if err := s.repo.CreateRole(ctx, role); err != nil {
|
|
return nil, err
|
|
}
|
|
if len(req.PermissionCodes) > 0 {
|
|
_ = s.repo.SetRolePermissionsByCodes(ctx, role.ID, req.PermissionCodes)
|
|
}
|
|
perms, _ := s.repo.GetPermissionsByRoleID(ctx, role.ID)
|
|
resp := transformer.RoleWithPermissionsToContract(*role, perms)
|
|
return &resp, nil
|
|
}
|
|
func (s *RBACServiceImpl) UpdateRole(ctx context.Context, id uuid.UUID, req *contract.UpdateRoleRequest) (*contract.RoleWithPermissionsResponse, error) {
|
|
role := &entities.Role{ID: id}
|
|
if req.Name != nil {
|
|
role.Name = *req.Name
|
|
}
|
|
if req.Code != nil {
|
|
role.Code = *req.Code
|
|
}
|
|
if req.Description != nil {
|
|
role.Description = *req.Description
|
|
}
|
|
if err := s.repo.UpdateRole(ctx, role); err != nil {
|
|
return nil, err
|
|
}
|
|
if req.PermissionCodes != nil {
|
|
_ = s.repo.SetRolePermissionsByCodes(ctx, id, *req.PermissionCodes)
|
|
}
|
|
perms, _ := s.repo.GetPermissionsByRoleID(ctx, id)
|
|
// fetch updated role
|
|
roles, err := s.repo.ListRoles(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, r := range roles {
|
|
if r.ID == id {
|
|
resp := transformer.RoleWithPermissionsToContract(r, perms)
|
|
return &resp, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
func (s *RBACServiceImpl) DeleteRole(ctx context.Context, id uuid.UUID) error {
|
|
return s.repo.DeleteRole(ctx, id)
|
|
}
|
|
func (s *RBACServiceImpl) ListRoles(ctx context.Context) (*contract.ListRolesResponse, error) {
|
|
roles, err := s.repo.ListRoles(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := make([]contract.RoleWithPermissionsResponse, 0, len(roles))
|
|
for _, r := range roles {
|
|
perms, _ := s.repo.GetPermissionsByRoleID(ctx, r.ID)
|
|
out = append(out, transformer.RoleWithPermissionsToContract(r, perms))
|
|
}
|
|
return &contract.ListRolesResponse{Roles: out}, nil
|
|
}
|
|
|
|
// New methods for the required API endpoints
|
|
func (s *RBACServiceImpl) GetPermissionsGrouped(ctx context.Context) (*contract.PermissionsGroupedResponse, error) {
|
|
modules, err := s.repo.ListModules(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]contract.ModuleWithPermissionsResponse, 0, len(modules))
|
|
for _, module := range modules {
|
|
perms, err := s.repo.ListPermissions(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
modulePerms := make([]contract.PermissionResponse, 0)
|
|
for _, perm := range perms {
|
|
if perm.ModuleID != nil && *perm.ModuleID == module.ID {
|
|
modulePerms = append(modulePerms, contract.PermissionResponse{
|
|
ID: perm.ID,
|
|
Code: perm.Code,
|
|
Action: perm.Action,
|
|
Description: &perm.Description,
|
|
})
|
|
}
|
|
}
|
|
|
|
result = append(result, contract.ModuleWithPermissionsResponse{
|
|
Module: contract.ModuleResponse{
|
|
ID: module.ID,
|
|
Name: module.Name,
|
|
Code: module.Code,
|
|
},
|
|
Permissions: modulePerms,
|
|
})
|
|
}
|
|
|
|
return &contract.PermissionsGroupedResponse{Data: result}, nil
|
|
}
|
|
|
|
func (s *RBACServiceImpl) CreateOrUpdateRole(ctx context.Context, req *contract.CreateOrUpdateRoleRequest) (*contract.RoleDetailResponse, error) {
|
|
// Check if role exists
|
|
existingRole, _ := s.repo.GetRoleByCode(ctx, req.Code)
|
|
|
|
var role *entities.Role
|
|
if existingRole != nil {
|
|
// Update existing role
|
|
role = existingRole
|
|
role.Name = req.Name
|
|
role.Description = req.Description
|
|
if err := s.repo.UpdateRole(ctx, role); err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
// Create new role
|
|
role = &entities.Role{
|
|
Name: req.Name,
|
|
Code: req.Code,
|
|
Description: req.Description,
|
|
}
|
|
if err := s.repo.CreateRole(ctx, role); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Set permissions based on module and actions
|
|
permissionIDs := make([]uuid.UUID, 0)
|
|
for _, modPerm := range req.Permissions {
|
|
_, err := s.repo.GetModuleByCode(ctx, modPerm.Module)
|
|
if err != nil {
|
|
continue // Skip if module not found
|
|
}
|
|
|
|
for _, action := range modPerm.Actions {
|
|
permCode := modPerm.Module + "_" + action
|
|
perm, err := s.repo.GetPermissionByCode(ctx, permCode)
|
|
if err == nil && perm != nil {
|
|
permissionIDs = append(permissionIDs, perm.ID)
|
|
}
|
|
}
|
|
}
|
|
|
|
if err := s.repo.SetRolePermissionsByIDs(ctx, role.ID, permissionIDs); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Build response
|
|
return s.GetRoleDetail(ctx, role.ID)
|
|
}
|
|
|
|
func (s *RBACServiceImpl) GetRoleDetail(ctx context.Context, roleID uuid.UUID) (*contract.RoleDetailResponse, error) {
|
|
role, err := s.repo.GetRoleByID(ctx, roleID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
permissions, err := s.repo.GetPermissionsByRoleID(ctx, roleID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Group permissions by module
|
|
moduleMap := make(map[uuid.UUID]*contract.RolePermissionModuleResponse)
|
|
|
|
for _, perm := range permissions {
|
|
if perm.ModuleID == nil {
|
|
continue
|
|
}
|
|
|
|
if _, exists := moduleMap[*perm.ModuleID]; !exists {
|
|
if perm.Module != nil {
|
|
moduleMap[*perm.ModuleID] = &contract.RolePermissionModuleResponse{
|
|
Module: contract.ModuleResponse{
|
|
ID: perm.Module.ID,
|
|
Name: perm.Module.Name,
|
|
Code: perm.Module.Code,
|
|
},
|
|
Actions: []contract.PermissionActionResponse{},
|
|
}
|
|
}
|
|
}
|
|
|
|
if modResp, exists := moduleMap[*perm.ModuleID]; exists {
|
|
modResp.Actions = append(modResp.Actions, contract.PermissionActionResponse{
|
|
ID: perm.ID,
|
|
Action: perm.Action,
|
|
Code: perm.Code,
|
|
Description: perm.Description,
|
|
})
|
|
}
|
|
}
|
|
|
|
// Convert map to slice
|
|
permissionModules := make([]contract.RolePermissionModuleResponse, 0, len(moduleMap))
|
|
for _, modResp := range moduleMap {
|
|
permissionModules = append(permissionModules, *modResp)
|
|
}
|
|
|
|
return &contract.RoleDetailResponse{
|
|
ID: role.ID,
|
|
Name: role.Name,
|
|
Code: role.Code,
|
|
Description: role.Description,
|
|
CreatedAt: role.CreatedAt,
|
|
UpdatedAt: role.UpdatedAt,
|
|
Permissions: permissionModules,
|
|
}, nil
|
|
}
|