feat(CC-057): add ConsentsController (grant/revoke/list consent records per purpose)

This commit is contained in:
admin-valentin 2026-08-01 21:00:08 +00:00
parent c8a517cd2d
commit 497aaa919b

View file

@ -0,0 +1,81 @@
import { Body, Controller, Get, IsString, Post } from '@nestjs/common';
import { and, desc, eq, isNull } from 'drizzle-orm';
import { CurrentSession } from '../auth/session.decorator';
import type { AuthenticatedSession } from '../auth/tenant.guard';
import { db } from '../db/client';
import { consentRecords } from '../db/schema';
class GrantConsentDto {
@IsString() purpose!: string;
}
class RevokeConsentDto {
@IsString() purpose!: string;
}
@Controller('consents')
export class ConsentsController {
@Get()
async list(@CurrentSession() session: AuthenticatedSession) {
return db.query.consentRecords.findMany({
where: and(
eq(consentRecords.tenantId, session.tenantId),
eq(consentRecords.userId, session.userId),
),
orderBy: [desc(consentRecords.grantedAt)],
});
}
@Post('grant')
async grant(
@CurrentSession() session: AuthenticatedSession,
@Body() dto: GrantConsentDto,
) {
// Revoke any previous record for this purpose first
const existing = await db.query.consentRecords.findFirst({
where: and(
eq(consentRecords.tenantId, session.tenantId),
eq(consentRecords.userId, session.userId),
eq(consentRecords.purpose, dto.purpose),
isNull(consentRecords.revokedAt),
),
});
if (existing) {
return existing;
}
const [created] = await db
.insert(consentRecords)
.values({
tenantId: session.tenantId,
userId: session.userId,
purpose: dto.purpose,
grantedAt: new Date(),
})
.returning();
return created;
}
@Post('revoke')
async revoke(
@CurrentSession() session: AuthenticatedSession,
@Body() dto: RevokeConsentDto,
) {
const active = await db.query.consentRecords.findFirst({
where: and(
eq(consentRecords.tenantId, session.tenantId),
eq(consentRecords.userId, session.userId),
eq(consentRecords.purpose, dto.purpose),
isNull(consentRecords.revokedAt),
),
});
if (!active) {
return { revoked: false, reason: 'no active consent for this purpose' };
}
const [updated] = await db
.update(consentRecords)
.set({ revokedAt: new Date() })
.where(eq(consentRecords.id, active.id))
.returning();
return { revoked: true, record: updated };
}
}