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