import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards, } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger'; import { UserRole } from '../../database/entities/user.entity'; import { AdminGuard } from '../../common/guards/admin.guard'; import { Roles } from '../../common/decorators/roles.decorator'; import { ZodValidationPipe } from '../../common/pipes/zod-validation.pipe'; import { CreateUserDtoSchema, ListUsersQueryDtoSchema, UpdateUserRoleDtoSchema, UserIdParamDtoSchema, } from './dto/admin.dto'; import { AdminService } from './admin.service'; /** * All admin handlers use Zod validation via `ZodValidationPipe` and an * INLINE body/param/query type. Using inline types (rather than class * metatypes) avoids the Nest class-transformer pass which would otherwise * overwrite the raw body before our pipe sees it. */ @ApiTags('admin') @ApiBearerAuth() @Controller('api/v1/admin') @UseGuards(AdminGuard) @Roles('admin') export class AdminController { constructor(private readonly admin: AdminService) {} @Get('users') @ApiOperation({ summary: 'List all users (admin only)' }) list( @Query(new ZodValidationPipe(ListUsersQueryDtoSchema)) query: { limit?: number; cursor?: string; role?: UserRole }, ) { return this.admin.listUsers(query); } @Patch('users/:id') @ApiOperation({ summary: 'Update a user role (admin only)' }) update( @Param(new ZodValidationPipe(UserIdParamDtoSchema)) params: { id: string }, @Body(new ZodValidationPipe(UpdateUserRoleDtoSchema)) body: { role: UserRole }, ) { return this.admin.updateUserRole(params.id, body.role); } @Delete('users/:id') @ApiOperation({ summary: 'Delete a user (admin only)' }) async remove( @Param(new ZodValidationPipe(UserIdParamDtoSchema)) params: { id: string }, ): Promise { await this.admin.deleteUser(params.id); } @Post('users') @ApiOperation({ summary: 'Create a user (admin only)' }) create( @Body(new ZodValidationPipe(CreateUserDtoSchema)) body: { username: string; password: string; role: UserRole }, ) { return this.admin.createUser(body.username, body.password, body.role); } }