feat: RBAC Phase 2d - Auswertung & Ausgabe auf @RequirePermission umgestellt

Dashboard, Search, Calendar, Statistics, Qr, Export, Documents:
@Roles(...) durch @RequirePermission(...) ersetzt bzw. neu eingefuehrt
(alle diese Controller hatten zuvor gar keine Rollenpruefung -
jeder eingeloggte Nutzer konnte lesen). Documents behaelt STAFF-Zugriff
auf Upload und Loeschen.

Verifiziert: tsc, lint, volle e2e-Suite 158/159 gruen (1 getrackter Skip).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Sonnet 5 committed 2026-08-26 07:09:20 +02:00
1 parent c510304813
commit 8832081973
7 files changed
+28 -4

No files matched your search

@@ -1,5 +1,6 @@
import { BadRequestException, Controller, Get, Query } from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { RequirePermission } from '../auth/decorators/require-permission.decorator';
import { CalendarService } from './calendar.service';
@ApiTags('calendar')
@@ -8,6 +9,7 @@ import { CalendarService } from './calendar.service';
export class CalendarController {
constructor(private readonly calendarService: CalendarService) {}
@RequirePermission('calendar:read')
@Get()
getEvents(
@Query('from') from: string,
@@ -1,5 +1,6 @@
import { Controller, Get } from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { RequirePermission } from '../auth/decorators/require-permission.decorator';
import { DashboardService } from './dashboard.service';
@ApiTags('dashboard')
@@ -8,11 +9,13 @@ import { DashboardService } from './dashboard.service';
export class DashboardController {
constructor(private readonly dashboardService: DashboardService) {}
@RequirePermission('dashboard:read')
@Get('summary')
summary() {
return this.dashboardService.summary();
}
@RequirePermission('dashboard:read')
@Get('alerts')
alerts() {
return this.dashboardService.alerts();
@@ -15,8 +15,8 @@ import {
import { FileInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiConsumes, ApiTags } from '@nestjs/swagger';
import type { Response } from 'express';
import { DocumentEntityType, LegacyRole as Role } from '../../generated/prisma';
import { Roles } from '../auth/decorators/roles.decorator';
import { DocumentEntityType } from '../../generated/prisma';
import { RequirePermission } from '../auth/decorators/require-permission.decorator';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import type { AuthenticatedUser } from '../auth/types/authenticated-user';
import { isAllowedDocumentMimeType } from './document-mime-types';
@@ -35,6 +35,7 @@ function sanitizeFilenameHeader(fileName: string): string {
export class DocumentsController {
constructor(private readonly documentsService: DocumentsService) {}
@RequirePermission('documents:read')
@Get()
findAll(
@Query('entityType') entityType: string,
@@ -56,7 +57,7 @@ export class DocumentsController {
);
}
@Roles(Role.ADMIN, Role.BEEKEEPER, Role.STAFF)
@RequirePermission('documents:upload')
@Post()
@ApiConsumes('multipart/form-data')
@UseInterceptors(
@@ -90,6 +91,7 @@ export class DocumentsController {
);
}
@RequirePermission('documents:read')
@Get(':id/download')
async download(@Param('id') id: string, @Res() res: Response): Promise<void> {
const { buffer, fileName, mimeType } =
@@ -102,7 +104,7 @@ export class DocumentsController {
res.send(buffer);
}
@Roles(Role.ADMIN, Role.BEEKEEPER, Role.STAFF)
@RequirePermission('documents:delete')
@Delete(':id')
@HttpCode(204)
delete(@Param('id') id: string, @CurrentUser() actor: AuthenticatedUser) {
@@ -1,6 +1,7 @@
import { Controller, Get, Param, Query, Res } from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import type { Response } from 'express';
import { RequirePermission } from '../auth/decorators/require-permission.decorator';
import { ExportService } from './export.service';
@ApiTags('export')
@@ -9,6 +10,7 @@ import { ExportService } from './export.service';
export class ExportController {
constructor(private readonly exportService: ExportService) {}
@RequirePermission('export:read')
@Get('colonies.csv')
async colonies(@Res() res: Response): Promise<void> {
const csv = await this.exportService.exportColoniesCsv();
@@ -17,6 +19,7 @@ export class ExportController {
res.send(csv);
}
@RequirePermission('export:read')
@Get('honey-batches.csv')
async honeyBatches(@Res() res: Response): Promise<void> {
const csv = await this.exportService.exportHoneyBatchesCsv();
@@ -28,6 +31,7 @@ export class ExportController {
res.send(csv);
}
@RequirePermission('export:read')
@Get(':entity.json')
async entityJson(
@Param('entity') entity: string,
@@ -42,6 +46,7 @@ export class ExportController {
res.send(JSON.stringify(data, null, 2));
}
@RequirePermission('export:read')
@Get(':report.pdf')
async reportPdf(
@Param('report') report: string,
+3
View File
@@ -1,6 +1,7 @@
import { Controller, Get, Param, Res } from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import type { Response } from 'express';
import { RequirePermission } from '../auth/decorators/require-permission.decorator';
import { QrService } from './qr.service';
@ApiTags('qr')
@@ -9,6 +10,7 @@ import { QrService } from './qr.service';
export class QrController {
constructor(private readonly qrService: QrService) {}
@RequirePermission('qr:read')
@Get(':entityType/:id.svg')
async svg(
@Param('entityType') entityType: string,
@@ -20,6 +22,7 @@ export class QrController {
res.send(svg);
}
@RequirePermission('qr:read')
@Get(':entityType/:id/link')
async link(
@Param('entityType') entityType: string,
@@ -1,5 +1,6 @@
import { Controller, Get, Query } from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { RequirePermission } from '../auth/decorators/require-permission.decorator';
import { SearchService } from './search.service';
@ApiTags('search')
@@ -8,6 +9,7 @@ import { SearchService } from './search.service';
export class SearchController {
constructor(private readonly searchService: SearchService) {}
@RequirePermission('search:read')
@Get()
search(@Query('q') q?: string) {
return this.searchService.search(q ?? '');
@@ -1,5 +1,6 @@
import { Controller, Get } from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { RequirePermission } from '../auth/decorators/require-permission.decorator';
import { StatisticsService } from './statistics.service';
@ApiTags('statistics')
@@ -8,31 +9,37 @@ import { StatisticsService } from './statistics.service';
export class StatisticsController {
constructor(private readonly statisticsService: StatisticsService) {}
@RequirePermission('statistics:read')
@Get('colonies')
colonies() {
return this.statisticsService.colonies();
}
@RequirePermission('statistics:read')
@Get('queens')
queens() {
return this.statisticsService.queens();
}
@RequirePermission('statistics:read')
@Get('apiaries')
apiaries() {
return this.statisticsService.apiaries();
}
@RequirePermission('statistics:read')
@Get('varroa')
varroa() {
return this.statisticsService.varroa();
}
@RequirePermission('statistics:read')
@Get('honey')
honey() {
return this.statisticsService.honey();
}
@RequirePermission('statistics:read')
@Get('feeding')
feeding() {
return this.statisticsService.feeding();