generated from fahricansecer/boilerplate-be
Initial commit
This commit is contained in:
270
src/modules/admin/admin.controller.ts
Normal file
270
src/modules/admin/admin.controller.ts
Normal file
@@ -0,0 +1,270 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Param,
|
||||
Body,
|
||||
Query,
|
||||
UseInterceptors,
|
||||
Inject,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
CacheInterceptor,
|
||||
CacheKey,
|
||||
CacheTTL,
|
||||
CACHE_MANAGER,
|
||||
} from '@nestjs/cache-manager';
|
||||
import * as cacheManager from 'cache-manager';
|
||||
import { ApiTags, ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
|
||||
import { Roles } from '../../common/decorators';
|
||||
import { PrismaService } from '../../database/prisma.service';
|
||||
import { PaginationDto } from '../../common/dto/pagination.dto';
|
||||
import {
|
||||
ApiResponse,
|
||||
createSuccessResponse,
|
||||
createPaginatedResponse,
|
||||
PaginatedData,
|
||||
} from '../../common/types/api-response.type';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { UserResponseDto } from '../users/dto/user.dto';
|
||||
import {
|
||||
PermissionResponseDto,
|
||||
RolePermissionResponseDto,
|
||||
RoleResponseDto,
|
||||
UserRoleResponseDto,
|
||||
} from './dto/admin.dto';
|
||||
|
||||
@ApiTags('Admin')
|
||||
@ApiBearerAuth()
|
||||
@Controller('admin')
|
||||
@Roles('admin')
|
||||
export class AdminController {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
@Inject(CACHE_MANAGER) private cacheManager: cacheManager.Cache,
|
||||
) {}
|
||||
|
||||
// ================== Users Management ==================
|
||||
|
||||
@Get('users')
|
||||
@ApiOperation({ summary: 'Get all users (admin)' })
|
||||
async getAllUsers(
|
||||
@Query() pagination: PaginationDto,
|
||||
): Promise<ApiResponse<PaginatedData<UserResponseDto>>> {
|
||||
const { skip, take, orderBy } = pagination;
|
||||
|
||||
const [users, total] = await Promise.all([
|
||||
this.prisma.user.findMany({
|
||||
skip,
|
||||
take,
|
||||
orderBy,
|
||||
include: {
|
||||
roles: {
|
||||
include: {
|
||||
role: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
this.prisma.user.count(),
|
||||
]);
|
||||
|
||||
const dtos = plainToInstance(
|
||||
UserResponseDto,
|
||||
users,
|
||||
) as unknown as UserResponseDto[];
|
||||
|
||||
return createPaginatedResponse(
|
||||
dtos,
|
||||
total,
|
||||
pagination.page || 1,
|
||||
pagination.limit || 10,
|
||||
);
|
||||
}
|
||||
|
||||
@Put('users/:id/toggle-active')
|
||||
@ApiOperation({ summary: 'Toggle user active status' })
|
||||
async toggleUserActive(
|
||||
@Param('id') id: string,
|
||||
): Promise<ApiResponse<UserResponseDto>> {
|
||||
const user = await this.prisma.user.findUnique({ where: { id } });
|
||||
|
||||
const updated = await this.prisma.user.update({
|
||||
where: { id },
|
||||
data: { isActive: !user?.isActive },
|
||||
});
|
||||
|
||||
return createSuccessResponse(
|
||||
plainToInstance(UserResponseDto, updated),
|
||||
'User status updated',
|
||||
);
|
||||
}
|
||||
|
||||
@Post('users/:userId/roles/:roleId')
|
||||
@ApiOperation({ summary: 'Assign role to user' })
|
||||
async assignRole(
|
||||
@Param('userId') userId: string,
|
||||
@Param('roleId') roleId: string,
|
||||
): Promise<ApiResponse<UserRoleResponseDto>> {
|
||||
const userRole = await this.prisma.userRole.create({
|
||||
data: { userId, roleId },
|
||||
});
|
||||
return createSuccessResponse(
|
||||
plainToInstance(UserRoleResponseDto, userRole),
|
||||
'Role assigned to user',
|
||||
);
|
||||
}
|
||||
|
||||
@Delete('users/:userId/roles/:roleId')
|
||||
@ApiOperation({ summary: 'Remove role from user' })
|
||||
async removeRole(
|
||||
@Param('userId') userId: string,
|
||||
@Param('roleId') roleId: string,
|
||||
): Promise<ApiResponse<null>> {
|
||||
await this.prisma.userRole.deleteMany({
|
||||
where: { userId, roleId },
|
||||
});
|
||||
return createSuccessResponse(null, 'Role removed from user');
|
||||
}
|
||||
|
||||
// ================== Roles Management ==================
|
||||
|
||||
@Get('roles')
|
||||
@UseInterceptors(CacheInterceptor)
|
||||
@CacheKey('roles_list')
|
||||
@CacheTTL(60 * 1000)
|
||||
@ApiOperation({ summary: 'Get all roles' })
|
||||
async getAllRoles(): Promise<ApiResponse<RoleResponseDto[]>> {
|
||||
const roles = await this.prisma.role.findMany({
|
||||
include: {
|
||||
permissions: {
|
||||
include: {
|
||||
permission: true,
|
||||
},
|
||||
},
|
||||
_count: {
|
||||
select: { users: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Transform Prisma structure to DTO structure
|
||||
const transformedRoles = roles.map((role) => ({
|
||||
...role,
|
||||
permissions: role.permissions.map((rp) => rp.permission),
|
||||
}));
|
||||
|
||||
return createSuccessResponse(
|
||||
plainToInstance(
|
||||
RoleResponseDto,
|
||||
transformedRoles,
|
||||
) as unknown as RoleResponseDto[],
|
||||
);
|
||||
}
|
||||
|
||||
@Post('roles')
|
||||
@ApiOperation({ summary: 'Create a new role' })
|
||||
async createRole(
|
||||
@Body() data: { name: string; description?: string },
|
||||
): Promise<ApiResponse<RoleResponseDto>> {
|
||||
const role = await this.prisma.role.create({ data });
|
||||
await this.cacheManager.del('roles_list');
|
||||
return createSuccessResponse(
|
||||
plainToInstance(RoleResponseDto, role),
|
||||
'Role created',
|
||||
201,
|
||||
);
|
||||
}
|
||||
|
||||
@Put('roles/:id')
|
||||
@ApiOperation({ summary: 'Update a role' })
|
||||
async updateRole(
|
||||
@Param('id') id: string,
|
||||
@Body() data: { name?: string; description?: string },
|
||||
): Promise<ApiResponse<RoleResponseDto>> {
|
||||
const role = await this.prisma.role.update({ where: { id }, data });
|
||||
await this.cacheManager.del('roles_list');
|
||||
return createSuccessResponse(
|
||||
plainToInstance(RoleResponseDto, role),
|
||||
'Role updated',
|
||||
);
|
||||
}
|
||||
|
||||
@Delete('roles/:id')
|
||||
@ApiOperation({ summary: 'Delete a role' })
|
||||
async deleteRole(@Param('id') id: string): Promise<ApiResponse<null>> {
|
||||
await this.prisma.role.delete({ where: { id } });
|
||||
await this.cacheManager.del('roles_list');
|
||||
return createSuccessResponse(null, 'Role deleted');
|
||||
}
|
||||
|
||||
// ================== Permissions Management ==================
|
||||
|
||||
@Get('permissions')
|
||||
@UseInterceptors(CacheInterceptor)
|
||||
@CacheKey('permissions_list')
|
||||
@CacheTTL(60 * 1000)
|
||||
@ApiOperation({ summary: 'Get all permissions' })
|
||||
async getAllPermissions(): Promise<ApiResponse<PermissionResponseDto[]>> {
|
||||
const permissions = await this.prisma.permission.findMany();
|
||||
return createSuccessResponse(
|
||||
plainToInstance(
|
||||
PermissionResponseDto,
|
||||
permissions,
|
||||
) as unknown as PermissionResponseDto[],
|
||||
);
|
||||
}
|
||||
|
||||
@Post('permissions')
|
||||
@ApiOperation({ summary: 'Create a new permission' })
|
||||
async createPermission(
|
||||
@Body()
|
||||
data: {
|
||||
name: string;
|
||||
description?: string;
|
||||
resource: string;
|
||||
action: string;
|
||||
},
|
||||
): Promise<ApiResponse<PermissionResponseDto>> {
|
||||
const permission = await this.prisma.permission.create({ data });
|
||||
await this.cacheManager.del('permissions_list');
|
||||
return createSuccessResponse(
|
||||
plainToInstance(PermissionResponseDto, permission),
|
||||
'Permission created',
|
||||
201,
|
||||
);
|
||||
}
|
||||
|
||||
@Post('roles/:roleId/permissions/:permissionId')
|
||||
@ApiOperation({ summary: 'Assign permission to role' })
|
||||
async assignPermission(
|
||||
@Param('roleId') roleId: string,
|
||||
@Param('permissionId') permissionId: string,
|
||||
): Promise<ApiResponse<RolePermissionResponseDto>> {
|
||||
const rolePermission = await this.prisma.rolePermission.create({
|
||||
data: { roleId, permissionId },
|
||||
});
|
||||
// Invalidate roles_list because permissions are nested in roles
|
||||
await this.cacheManager.del('roles_list');
|
||||
return createSuccessResponse(
|
||||
plainToInstance(RolePermissionResponseDto, rolePermission),
|
||||
'Permission assigned to role',
|
||||
);
|
||||
}
|
||||
|
||||
@Delete('roles/:roleId/permissions/:permissionId')
|
||||
@ApiOperation({ summary: 'Remove permission from role' })
|
||||
async removePermission(
|
||||
@Param('roleId') roleId: string,
|
||||
@Param('permissionId') permissionId: string,
|
||||
): Promise<ApiResponse<null>> {
|
||||
await this.prisma.rolePermission.deleteMany({
|
||||
where: { roleId, permissionId },
|
||||
});
|
||||
// Invalidate roles_list because permissions are nested in roles
|
||||
await this.cacheManager.del('roles_list');
|
||||
return createSuccessResponse(null, 'Permission removed from role');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user