feat(api,web): eigene Module — Tabelle, API, Seitenleiste, Rahmen-Seite
- Tabelle CustomModule mit Zeilenschutz (tenant_isolation_policy), Migration 20260929120000 - API /custom-modules: Lesen für jeden Angemeldeten, Schreiben nur Administrator, nur https ohne Zugangsdaten - Seitenleiste zeigt eigene Module unter ihrer Kategorie, Rahmen-Seite mit Sandbox und „In neuem Tab öffnen“ - MODULE_CATEGORIES als gemeinsame Liste, Zugriffsklassifikation nachgemessen fortgeschrieben Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
ForbiddenException,
|
||||
Get,
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
Req,
|
||||
} from '@nestjs/common';
|
||||
import { Role } from '@prisma/client';
|
||||
import { Roles } from '../auth/decorators/roles.decorator';
|
||||
import type { AuthenticatedRequest } from '../auth/types/auth-user';
|
||||
import { CustomModulesService } from './custom-modules.service';
|
||||
import { CreateCustomModuleDto, UpdateCustomModuleDto } from './dto/custom-module.dto';
|
||||
|
||||
/**
|
||||
* Eigene Module (quick-260929-9wc). Lesen (`GET`, `GET :id`) steht jedem
|
||||
* angemeldeten Benutzer offen — die Eintraege sind fuer alle sichtbar (D-01);
|
||||
* Schreiben nur `@Roles(ADMIN, SUPER_ADMIN)` (T-9WC-01). Kein `@UseModule`:
|
||||
* eigene Module haengen an keiner Modul-Aktivierung. `tenantId` kommt
|
||||
* ausschliesslich aus `req.tenantId` (gesetzt vom `TenantGuard`).
|
||||
*
|
||||
* ROUTEN-REIHENFOLGE: NestJS bildet Routen in Deklarationsreihenfolge ab.
|
||||
* Jede kuenftige statische GET-Route MUSS ueber `getOne` (`@Get(':id')`)
|
||||
* stehen, sonst faengt `:id` sie ab (404-Shadowing); der Controller-Test
|
||||
* haelt die Reihenfolge von `list` vor `getOne` fest.
|
||||
*/
|
||||
@Controller('custom-modules')
|
||||
export class CustomModulesController {
|
||||
constructor(private readonly service: CustomModulesService) {}
|
||||
|
||||
private requireTenantId(req: AuthenticatedRequest): string {
|
||||
const tenantId = req.tenantId;
|
||||
if (!tenantId) {
|
||||
throw new ForbiddenException('Kein Mandantenkontext');
|
||||
}
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
@Get()
|
||||
async list(@Req() req: AuthenticatedRequest) {
|
||||
return this.service.list(this.requireTenantId(req));
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
async getOne(@Req() req: AuthenticatedRequest, @Param('id') id: string) {
|
||||
return this.service.getOne(this.requireTenantId(req), id);
|
||||
}
|
||||
|
||||
@Post()
|
||||
@Roles(Role.ADMIN, Role.SUPER_ADMIN)
|
||||
async create(@Req() req: AuthenticatedRequest, @Body() dto: CreateCustomModuleDto) {
|
||||
return this.service.create(this.requireTenantId(req), dto);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@Roles(Role.ADMIN, Role.SUPER_ADMIN)
|
||||
async update(
|
||||
@Req() req: AuthenticatedRequest,
|
||||
@Param('id') id: string,
|
||||
@Body() dto: UpdateCustomModuleDto,
|
||||
) {
|
||||
return this.service.update(this.requireTenantId(req), id, dto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@Roles(Role.ADMIN, Role.SUPER_ADMIN)
|
||||
async remove(@Req() req: AuthenticatedRequest, @Param('id') id: string) {
|
||||
return this.service.remove(this.requireTenantId(req), id);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user