fe429dbe01
- Links anlegen und aendern: Passwort, Ablaufdatum und Bezeichnung nur im JSON-Koerper, Vorpruefung aus den frisch gelesenen Faehigkeiten (Passwort/Ablauf verlangt, Hochladen, mehrere Links), echte Datumspruefung, nur geaenderte Felder beim Aendern - Routen shares/mine, shares/received (angenommen plus offen, 404/405 bei offen = leer) und POST shares/:id/accept am Ende der Klasse - Fehlerzweige fuer Passwort und Ablauf mit Tests; nie Passwort in Antwort oder Fehler - Live-Test e2e-shares.sh: Abschnitte links (Pflicht-Passwort und Pflicht-Ablauf per occ) und received (eingehend, offen, annehmen, verlassen) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
217 lines
7.4 KiB
TypeScript
217 lines
7.4 KiB
TypeScript
import 'reflect-metadata';
|
|
import { GUARDS_METADATA } from '@nestjs/common/constants';
|
|
import { Role } from '@prisma/client';
|
|
import { describe, expect, it } from 'vitest';
|
|
import { ROLES_KEY } from '../auth/decorators/roles.decorator';
|
|
import { DkvController } from '../dkv/dkv.controller';
|
|
import { DomainsController } from '../domains/domains.controller';
|
|
import { ModuleGrantsController } from '../groups/module-grants.controller';
|
|
import { HandelswareDatevController } from '../handelsware-datev/handelsware-datev.controller';
|
|
import { KantineDatevController } from '../kantine-datev/kantine-datev.controller';
|
|
import { NextcloudFilesController } from '../nextcloud-files/nextcloud-files.controller';
|
|
import { NextcloudStatusController } from '../nextcloud-status/nextcloud-status.controller';
|
|
import { ProxmoxController } from '../proxmox/proxmox.controller';
|
|
import { TendersController } from '../tenders/tenders.controller';
|
|
import { MODULE_MANAGE_KEY, MODULE_SLUG_KEY, ModuleGuard } from './module.guard';
|
|
import { ModuleRegistryController } from './module-registry.controller';
|
|
|
|
/**
|
|
* Metadaten-Beweis für die Freigabestufe Verwalten (261002-icv, L-04/L-09):
|
|
* welche Handler auf `@ModuleManage` umgestellt wurden und welche bewusst
|
|
* Administratoren vorbehalten bleiben (T-icv-01/06/07/08). Reine Metadaten —
|
|
* kein Nest-Start, keine Datenbank.
|
|
*/
|
|
|
|
const ADMIN_ONLY = [Role.ADMIN, Role.SUPER_ADMIN];
|
|
|
|
function methodsOf(controller: { prototype: object }): string[] {
|
|
return Object.getOwnPropertyNames(controller.prototype).filter(
|
|
(name) => name !== 'constructor' && typeof (controller.prototype as any)[name] === 'function',
|
|
);
|
|
}
|
|
|
|
function handler(controller: { prototype: object }, name: string) {
|
|
return (controller.prototype as any)[name];
|
|
}
|
|
|
|
function expectManage(controller: { prototype: object }, name: string, slug: string) {
|
|
const fn = handler(controller, name);
|
|
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn), `${name} MODULE_MANAGE_KEY`).toBe(true);
|
|
expect(Reflect.getMetadata(MODULE_SLUG_KEY, fn), `${name} MODULE_SLUG_KEY`).toBe(slug);
|
|
expect(Reflect.getMetadata(GUARDS_METADATA, fn), `${name} guards`).toContain(ModuleGuard);
|
|
expect(Reflect.getMetadata(ROLES_KEY, fn), `${name} ROLES_KEY`).toBeUndefined();
|
|
}
|
|
|
|
function expectAdminOnly(controller: { prototype: object }, name: string) {
|
|
const fn = handler(controller, name);
|
|
expect(Reflect.getMetadata(ROLES_KEY, fn), `${name} ROLES_KEY`).toEqual(ADMIN_ONLY);
|
|
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn), `${name} MODULE_MANAGE_KEY`).toBeUndefined();
|
|
}
|
|
|
|
describe('Umgestellte Handler (Verwalten)', () => {
|
|
it('DkvController: ganze Klasse Verwalten, kein Handler trägt @Roles', () => {
|
|
expect(Reflect.getMetadata(MODULE_SLUG_KEY, DkvController)).toBe('dkv-fleet');
|
|
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, DkvController)).toBe(true);
|
|
expect(Reflect.getMetadata(GUARDS_METADATA, DkvController)).toContain(ModuleGuard);
|
|
const names = methodsOf(DkvController).filter((n) =>
|
|
Reflect.hasMetadata('path', handler(DkvController, n)),
|
|
);
|
|
expect(names.length).toBe(11);
|
|
for (const name of names) {
|
|
expect(Reflect.getMetadata(ROLES_KEY, handler(DkvController, name)), name).toBeUndefined();
|
|
}
|
|
});
|
|
|
|
it.each([
|
|
'create',
|
|
'update',
|
|
'remove',
|
|
'poll',
|
|
'test',
|
|
'testDraft',
|
|
])('ProxmoxController.%s verlangt Verwalten für proxmox', (name) => {
|
|
expectManage(ProxmoxController, name, 'proxmox');
|
|
});
|
|
|
|
it('ProxmoxController.list bleibt auf Benutzen-Ebene', () => {
|
|
const fn = handler(ProxmoxController, 'list');
|
|
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn)).toBeUndefined();
|
|
expect(Reflect.getMetadata(ROLES_KEY, fn)).toBeUndefined();
|
|
});
|
|
|
|
it.each([
|
|
'create',
|
|
'update',
|
|
'remove',
|
|
'checkAll',
|
|
'checkOne',
|
|
'uploadLogo',
|
|
'removeLogo',
|
|
])('NextcloudStatusController.%s verlangt Verwalten für nextcloud-status', (name) => {
|
|
expectManage(NextcloudStatusController, name, 'nextcloud-status');
|
|
});
|
|
|
|
it.each([
|
|
'list',
|
|
'logo',
|
|
'subscribe',
|
|
'unsubscribe',
|
|
'recentAlerts',
|
|
])('NextcloudStatusController.%s bleibt auf Benutzen-Ebene', (name) => {
|
|
const fn = handler(NextcloudStatusController, name);
|
|
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn)).toBeUndefined();
|
|
expect(Reflect.getMetadata(ROLES_KEY, fn)).toBeUndefined();
|
|
});
|
|
|
|
it.each([
|
|
'getSettings',
|
|
'saveSettings',
|
|
'testConnection',
|
|
'createCustomer',
|
|
'updateCustomer',
|
|
'deleteCustomer',
|
|
'createContact',
|
|
'assignContacts',
|
|
'checkAvailability',
|
|
'getNameServers',
|
|
'createOrder',
|
|
'submitOrder',
|
|
'cancelOrder',
|
|
])('DomainsController.%s verlangt Verwalten für domains (quick-261008-dts)', (name) => {
|
|
expectManage(DomainsController, name, 'domains');
|
|
});
|
|
|
|
it.each([
|
|
'getStatus',
|
|
'listCustomers',
|
|
'listContacts',
|
|
'listDomains',
|
|
'listOrders',
|
|
'refreshOrders',
|
|
])('DomainsController.%s bleibt auf Benutzen-Ebene', (name) => {
|
|
const fn = handler(DomainsController, name);
|
|
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn)).toBeUndefined();
|
|
expect(Reflect.getMetadata(ROLES_KEY, fn)).toBeUndefined();
|
|
});
|
|
|
|
it.each([
|
|
'getSettings',
|
|
'testSettings',
|
|
])('NextcloudFilesController.%s verlangt Verwalten für nextcloud-files (quick-261008-mzu)', (name) => {
|
|
expectManage(NextcloudFilesController, name, 'nextcloud-files');
|
|
});
|
|
|
|
// Spätere Aufgaben von quick-261008-mzu ergänzen diese Liste um ihre Benutzen-Handler.
|
|
it.each([
|
|
'getStatus',
|
|
'getServer',
|
|
'getServerLogo',
|
|
'connectPassword',
|
|
'startFlow',
|
|
'pollFlow',
|
|
'cancelFlow',
|
|
'disconnect',
|
|
'list',
|
|
'remove',
|
|
'createFolder',
|
|
'move',
|
|
'preview',
|
|
'download',
|
|
'downloadZip',
|
|
'startUpload',
|
|
'putSingle',
|
|
'putChunk',
|
|
'completeUpload',
|
|
'uploadState',
|
|
'abortUpload',
|
|
'getSharePolicy',
|
|
'listSharesForPath',
|
|
'searchSharees',
|
|
'createShare',
|
|
'listMyShares',
|
|
'listReceivedShares',
|
|
'updateShare',
|
|
'deleteShare',
|
|
'acceptShare',
|
|
])('NextcloudFilesController.%s bleibt auf Benutzen-Ebene', (name) => {
|
|
const fn = handler(NextcloudFilesController, name);
|
|
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, fn)).toBeUndefined();
|
|
expect(Reflect.getMetadata(ROLES_KEY, fn)).toBeUndefined();
|
|
});
|
|
|
|
it('KantineDatevController.saveSettings und HandelswareDatevController.saveSettings verlangen Verwalten', () => {
|
|
expectManage(KantineDatevController, 'saveSettings', 'kantine-datev');
|
|
expectManage(HandelswareDatevController, 'saveSettings', 'handelsware-datev');
|
|
});
|
|
});
|
|
|
|
describe('Bewusst nur für Administratoren (T-icv-01, T-icv-07)', () => {
|
|
it.each([
|
|
'getSourceConfig',
|
|
'saveSourceConfig',
|
|
'pollNow',
|
|
])('TendersController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)', (name) => {
|
|
expectAdminOnly(TendersController, name);
|
|
});
|
|
|
|
it.each([
|
|
'matrix',
|
|
'userAccess',
|
|
'create',
|
|
'remove',
|
|
])('ModuleGrantsController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)', (name) => {
|
|
expectAdminOnly(ModuleGrantsController, name);
|
|
});
|
|
|
|
it.each([
|
|
'activate',
|
|
'deactivate',
|
|
])('ModuleRegistryController.%s bleibt @Roles(ADMIN, SUPER_ADMIN)', (name) => {
|
|
expectAdminOnly(ModuleRegistryController, name);
|
|
});
|
|
|
|
it('NextcloudFilesController.saveSettings: die Nextcloud-Adresse legt nur ein Administrator fest (quick-261008-mzu, CR-02)', () => {
|
|
expectAdminOnly(NextcloudFilesController, 'saveSettings');
|
|
});
|
|
});
|