Files
edr-platform/apps/edr-freight-api/src/modules/warehouses/warehouse-inspection.controller.ts
Nathnael da08a9b085 fix(auth): list every route key on the class-level guard
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.
2026-08-07 08:43:20 +00:00

80 lines
3.1 KiB
TypeScript

import {
Body,
Controller,
Get,
Param,
ParseUUIDPipe,
Patch,
Post,
UploadedFiles,
UseInterceptors,
} from '@nestjs/common';
import { AnyFilesInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger';
import { BookingStaff } from '../../common/booking-guards';
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
import { CreateInspectionReportDto } from './dto/create-inspection-report.dto';
import { UpdateInspectionReportDto } from './dto/update-inspection-report.dto';
import { WarehouseInspectionService } from './warehouse-inspection.service';
@ApiTags('warehouse-inspection')
@ApiBearerAuth()
// Baseline read: inspection reports are opened from inventory screens too —
// either view permission grants reads; writes stack their own per route.
@Controller()
// 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.
@BookingStaff([
FREIGHT_PERMS.warehouseInspectionReports.view,
FREIGHT_PERMS.warehouseInventory.view,
FREIGHT_PERMS.warehouseInspectionReports.create,
FREIGHT_PERMS.warehouseInspectionReports.update,
])
export class WarehouseInspectionController {
constructor(private readonly inspectionService: WarehouseInspectionService) {}
@Post('warehouse-inventory/:inventoryId/inspection-reports')
@BookingStaff(FREIGHT_PERMS.warehouseInspectionReports.create)
@ApiOperation({ summary: 'Create an inspection / damage report for an inventory item' })
create(
@Param('inventoryId', ParseUUIDPipe) inventoryId: string,
@Body() dto: CreateInspectionReportDto,
) {
return this.inspectionService.create(inventoryId, dto);
}
@Get('warehouse-inventory/:inventoryId/inspection-reports')
@ApiOperation({ summary: 'List inspection reports for an inventory item' })
listByInventory(@Param('inventoryId', ParseUUIDPipe) inventoryId: string) {
return this.inspectionService.findByInventory(inventoryId);
}
@Get('warehouse-inspection-reports/:id')
@ApiOperation({ summary: 'Get an inspection report (with attachments)' })
async findOne(@Param('id', ParseUUIDPipe) id: string) {
const report = await this.inspectionService.findById(id);
const attachments = await this.inspectionService.listAttachments(id);
return { ...report, attachments };
}
@Patch('warehouse-inspection-reports/:id')
@BookingStaff(FREIGHT_PERMS.warehouseInspectionReports.update)
@ApiOperation({ summary: 'Update an inspection report' })
update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateInspectionReportDto) {
return this.inspectionService.update(id, dto);
}
@Post('warehouse-inspection-reports/:id/attachments')
@BookingStaff(FREIGHT_PERMS.warehouseInspectionReports.update)
@UseInterceptors(AnyFilesInterceptor())
@ApiConsumes('multipart/form-data')
@ApiOperation({ summary: 'Upload inspection images / documents' })
addAttachments(
@Param('id', ParseUUIDPipe) id: string,
@UploadedFiles() files: Express.Multer.File[],
) {
return this.inspectionService.addAttachments(id, files);
}
}