250 lines
6.2 KiB
TypeScript
250 lines
6.2 KiB
TypeScript
import { Request, Response } from 'express';
|
|
import { z } from 'zod';
|
|
|
|
import { getErrorMessage } from '../../utils/error-utils';
|
|
|
|
import { rbacService } from './rbac.service';
|
|
|
|
const AssignRoleDto = z.object({
|
|
userId: z.string(),
|
|
roleId: z.string(),
|
|
expiresAt: z.string().optional(),
|
|
});
|
|
|
|
const GrantPermissionDto = z.object({
|
|
userId: z.string(),
|
|
permissionId: z.string(),
|
|
expiresAt: z.string().optional(),
|
|
});
|
|
|
|
/**
|
|
* EN: RBAC Controller
|
|
* VI: Controller RBAC
|
|
*/
|
|
export class RBACController {
|
|
/**
|
|
* EN: Get user permissions
|
|
* VI: Lấy quyền của người dùng
|
|
*/
|
|
async getUserPermissions(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.id || (req as any).user?.sub || req.params.userId;
|
|
|
|
if (!userId) {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: { code: 'USER_ID_REQUIRED', message: 'User ID required' },
|
|
});
|
|
return;
|
|
}
|
|
|
|
const permissions = await rbacService.getUserPermissions(userId);
|
|
const roles = await rbacService.getUserRoles(userId);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: {
|
|
permissions,
|
|
roles,
|
|
},
|
|
});
|
|
} catch (error: unknown) {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: {
|
|
code: 'GET_PERMISSIONS_FAILED',
|
|
message: getErrorMessage(error) || 'Failed to get permissions',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* EN: Assign role to user
|
|
* VI: Gán role cho người dùng
|
|
*/
|
|
async assignRole(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const data = AssignRoleDto.parse(req.body);
|
|
const grantedBy = (req as any).user?.id || (req as any).user?.sub;
|
|
|
|
await rbacService.assignRole(data.userId, data.roleId, {
|
|
grantedBy,
|
|
expiresAt: data.expiresAt ? new Date(data.expiresAt) : undefined,
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
data: { message: 'Role assigned successfully' },
|
|
});
|
|
} catch (error: unknown) {
|
|
if (error instanceof z.ZodError) {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
code: 'VALIDATION_ERROR',
|
|
message: 'Invalid input',
|
|
details: error.issues,
|
|
},
|
|
});
|
|
return;
|
|
}
|
|
|
|
res.status(500).json({
|
|
success: false,
|
|
error: {
|
|
code: 'ASSIGN_ROLE_FAILED',
|
|
message: getErrorMessage(error) || 'Failed to assign role',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* EN: Revoke role from user
|
|
* VI: Thu hồi role từ người dùng
|
|
*/
|
|
async revokeRole(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const { userId, roleId } = req.body;
|
|
|
|
if (!userId || !roleId) {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: { code: 'INVALID_INPUT', message: 'userId and roleId required' },
|
|
});
|
|
return;
|
|
}
|
|
|
|
await rbacService.revokeRole(userId, roleId);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: { message: 'Role revoked successfully' },
|
|
});
|
|
} catch (error: unknown) {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: {
|
|
code: 'REVOKE_ROLE_FAILED',
|
|
message: getErrorMessage(error) || 'Failed to revoke role',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* EN: Grant permission to user
|
|
* VI: Cấp quyền cho người dùng
|
|
*/
|
|
async grantPermission(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const data = GrantPermissionDto.parse(req.body);
|
|
const grantedBy = (req as any).user?.id || (req as any).user?.sub;
|
|
|
|
await rbacService.grantPermission(data.userId, data.permissionId, {
|
|
grantedBy,
|
|
expiresAt: data.expiresAt ? new Date(data.expiresAt) : undefined,
|
|
});
|
|
|
|
res.json({
|
|
success: true,
|
|
data: { message: 'Permission granted successfully' },
|
|
});
|
|
} catch (error: unknown) {
|
|
if (error instanceof z.ZodError) {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
code: 'VALIDATION_ERROR',
|
|
message: 'Invalid input',
|
|
details: error.issues,
|
|
},
|
|
});
|
|
return;
|
|
}
|
|
|
|
res.status(500).json({
|
|
success: false,
|
|
error: {
|
|
code: 'GRANT_PERMISSION_FAILED',
|
|
message: getErrorMessage(error) || 'Failed to grant permission',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* EN: Check permission
|
|
* VI: Kiểm tra quyền
|
|
*/
|
|
async checkPermission(req: Request, res: Response): Promise<void> {
|
|
try {
|
|
const userId = (req as any).user?.id || (req as any).user?.sub;
|
|
const { resource, action, scope } = req.query;
|
|
|
|
if (!userId || !resource || !action) {
|
|
res.status(400).json({
|
|
success: false,
|
|
error: {
|
|
code: 'INVALID_INPUT',
|
|
message: 'userId, resource, and action are required',
|
|
},
|
|
});
|
|
return;
|
|
}
|
|
|
|
const hasPermission = await rbacService.hasPermission(
|
|
userId,
|
|
resource as string,
|
|
action as string,
|
|
scope as string | undefined
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: { hasPermission },
|
|
});
|
|
} catch (error: unknown) {
|
|
res.status(500).json({
|
|
success: false,
|
|
error: {
|
|
code: 'CHECK_PERMISSION_FAILED',
|
|
message: getErrorMessage(error) || 'Failed to check permission',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
/**
|
|
* EN: Get all roles
|
|
* VI: Lấy tất cả roles
|
|
*/
|
|
async getRoles(req: Request, res: Response): Promise<void> {
|
|
res.status(501).json({
|
|
success: false,
|
|
error: {
|
|
code: 'NOT_IMPLEMENTED',
|
|
message: 'Get roles is not yet implemented / Lấy roles chưa được triển khai'
|
|
},
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
|
|
/**
|
|
* EN: Create new role
|
|
* VI: Tạo role mới
|
|
*/
|
|
async createRole(req: Request, res: Response): Promise<void> {
|
|
res.status(501).json({
|
|
success: false,
|
|
error: {
|
|
code: 'NOT_IMPLEMENTED',
|
|
message: 'Create role is not yet implemented / Tạo role chưa được triển khai'
|
|
},
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
}
|
|
}
|
|
|
|
export const rbacController = new RBACController();
|