import { Body, Controller, Get, HttpCode, HttpStatus, Param, ParseUUIDPipe, Post, UseGuards, } from '@nestjs/common'; import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { z } from 'zod'; import type { NodeListResponse, NodeSummary } from '@hexahost/contracts'; import { CurrentUser } from '../auth/decorators/current-user.decorator'; import { SessionGuard } from '../auth/guards/session.guard'; import { ZodValidationPipe } from '../common/pipes/zod-validation.pipe'; import { AdminNodesService } from './admin-nodes.service'; import type { CreateNodeResponse } from './admin-nodes.service'; const createNodeRequestSchema = z.object({ name: z.string().min(1).max(64), hostname: z.string().min(1).max(255), maxServers: z.number().int().min(1).max(1000).optional(), maxRamMb: z.number().int().min(2048).max(1048576).optional(), platformRamMb: z.number().int().min(512).max(65536).optional(), }); const maintenanceRequestSchema = z.object({ enabled: z.boolean(), }); @ApiTags('admin') @Controller('admin/nodes') @UseGuards(SessionGuard) export class AdminNodesController { constructor(private readonly adminNodesService: AdminNodesService) {} @Get() @ApiOperation({ summary: 'List game nodes (super admin only)' }) list(@CurrentUser() user: { roles: string[] }): Promise { this.adminNodesService.assertSuperAdmin(user.roles); return this.adminNodesService.listNodes(); } @Post() @HttpCode(HttpStatus.CREATED) @ApiOperation({ summary: 'Register a new game node (super admin only)' }) @ApiResponse({ status: 201, description: 'Node created with enrollment token' }) create( @CurrentUser() user: { roles: string[] }, @Body(new ZodValidationPipe(createNodeRequestSchema)) body: unknown, ): Promise { this.adminNodesService.assertSuperAdmin(user.roles); return this.adminNodesService.createNode( body as Parameters[0], ); } @Post(':id/drain') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Drain a game node (super admin only)' }) drain( @CurrentUser() user: { roles: string[] }, @Param('id', ParseUUIDPipe) id: string, ): Promise { this.adminNodesService.assertSuperAdmin(user.roles); return this.adminNodesService.requestDrain(id); } @Post(':id/maintenance') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Toggle maintenance mode for a node (super admin only)' }) maintenance( @CurrentUser() user: { roles: string[] }, @Param('id', ParseUUIDPipe) id: string, @Body(new ZodValidationPipe(maintenanceRequestSchema)) body: unknown, ): Promise { this.adminNodesService.assertSuperAdmin(user.roles); const input = body as z.infer; return this.adminNodesService.setMaintenance(id, input.enabled); } }