mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 16:00:56 +00:00
Nest runs class and method guards together, so a class gate naming only the view key silently required view AND action. Staff granted just an action were denied before their key was checked. Each class gate now names every key its routes use, and FleetView accepts an array so the fleet controllers keep their coarse fallback. Drops the one-off grant mapping SQL with it: already applied to dev, and this fix removes the companion-view rule that was its recurring part.
97 lines
2.9 KiB
TypeScript
97 lines
2.9 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Delete,
|
|
Get,
|
|
HttpCode,
|
|
HttpStatus,
|
|
Param,
|
|
ParseUUIDPipe,
|
|
Patch,
|
|
Post,
|
|
Query,
|
|
} from '@nestjs/common';
|
|
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
|
|
|
import {
|
|
BookingStaff,
|
|
FleetManage,
|
|
FleetView,
|
|
} from '../../common/booking-guards';
|
|
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
|
|
import { CreateRouteDto } from './dto/create-route.dto';
|
|
import { FilterRoutesDto } from './dto/filter-routes.dto';
|
|
import { UpdateRouteDto } from './dto/update-route.dto';
|
|
import { RoutesService } from './routes.service';
|
|
|
|
@ApiTags('routes')
|
|
@ApiBearerAuth()
|
|
@Controller('routes')
|
|
// Class gate lists every key its routes use: Nest runs class AND method
|
|
// guards, so a key missing here would deny before the route's own key runs.
|
|
@FleetView([
|
|
FREIGHT_PERMS.routes.view,
|
|
FREIGHT_PERMS.routes.create,
|
|
FREIGHT_PERMS.routes.update,
|
|
FREIGHT_PERMS.routes.hardDelete,
|
|
FREIGHT_PERMS.routes.delete,
|
|
])
|
|
export class RoutesController {
|
|
constructor(private readonly routesService: RoutesService) {}
|
|
|
|
@Get()
|
|
@ApiOperation({ summary: 'List routes' })
|
|
findAll(@Query() filter: FilterRoutesDto) {
|
|
return this.routesService.findAll(filter);
|
|
}
|
|
|
|
// Must be declared before @Get(':id') so the path isn't captured as an id.
|
|
@Get('paged')
|
|
@ApiOperation({ summary: 'List routes, paginated ({items, meta})' })
|
|
findAllPaged(@Query() filter: FilterRoutesDto) {
|
|
return this.routesService.findAllPaged(filter);
|
|
}
|
|
|
|
@Get(':id')
|
|
@ApiOperation({ summary: 'Get route by ID' })
|
|
findOne(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.routesService.findById(id);
|
|
}
|
|
|
|
@Post()
|
|
@FleetManage(FREIGHT_PERMS.routes.create)
|
|
@ApiOperation({ summary: 'Create route' })
|
|
create(@Body() dto: CreateRouteDto) {
|
|
return this.routesService.create(dto);
|
|
}
|
|
|
|
@Patch(':id')
|
|
@FleetManage(FREIGHT_PERMS.routes.update)
|
|
@ApiOperation({ summary: 'Update route' })
|
|
update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateRouteDto) {
|
|
return this.routesService.update(id, dto);
|
|
}
|
|
|
|
// Declared before @Delete(':id') so "permanent" is never captured as an id.
|
|
// BookingStaff, not FleetManage: the latter also accepts the coarse
|
|
// fleet:manage key, which would hand an irreversible purge to everyone who
|
|
// can edit the fleet. This action requires its own grant, nothing else.
|
|
@Delete(':id/permanent')
|
|
@BookingStaff(FREIGHT_PERMS.routes.hardDelete)
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({
|
|
summary:
|
|
'Permanently delete a route (irreversible; refused while any train schedule references it)',
|
|
})
|
|
purge(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.routesService.purge(id);
|
|
}
|
|
|
|
@Delete(':id')
|
|
@FleetManage(FREIGHT_PERMS.routes.delete)
|
|
@ApiOperation({ summary: 'Deactivate route' })
|
|
remove(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.routesService.deactivate(id);
|
|
}
|
|
}
|