178 lines
4.6 KiB
TypeScript
178 lines
4.6 KiB
TypeScript
/**
|
|
* GDPR Controller
|
|
*
|
|
* Endpoints for GDPR compliance (data export, deletion, consent)
|
|
*/
|
|
|
|
import {
|
|
Controller,
|
|
Get,
|
|
Post,
|
|
Delete,
|
|
Body,
|
|
UseGuards,
|
|
HttpCode,
|
|
HttpStatus,
|
|
Res,
|
|
} from '@nestjs/common';
|
|
import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse } from '@nestjs/swagger';
|
|
import { Response } from 'express';
|
|
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
|
|
import { CurrentUser } from '../decorators/current-user.decorator';
|
|
import { UserPayload } from '../decorators/current-user.decorator';
|
|
import { GDPRService, ConsentData } from '../services/gdpr.service';
|
|
|
|
@ApiTags('GDPR')
|
|
@Controller('gdpr')
|
|
@UseGuards(JwtAuthGuard)
|
|
@ApiBearerAuth()
|
|
export class GDPRController {
|
|
constructor(private readonly gdprService: GDPRService) {}
|
|
|
|
/**
|
|
* Export user data (GDPR Right to Data Portability)
|
|
*/
|
|
@Get('export')
|
|
@ApiOperation({
|
|
summary: 'Export all user data',
|
|
description: 'Export all personal data in JSON format (GDPR Article 20)',
|
|
})
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'Data export successful',
|
|
})
|
|
async exportData(@CurrentUser() user: UserPayload, @Res() res: Response): Promise<void> {
|
|
const exportData = await this.gdprService.exportUserData(user.id);
|
|
|
|
// Set headers for file download
|
|
res.setHeader('Content-Type', 'application/json');
|
|
res.setHeader(
|
|
'Content-Disposition',
|
|
`attachment; filename="xpeditis-data-export-${user.id}-${Date.now()}.json"`
|
|
);
|
|
|
|
res.json(exportData);
|
|
}
|
|
|
|
/**
|
|
* Export user data as CSV
|
|
*/
|
|
@Get('export/csv')
|
|
@ApiOperation({
|
|
summary: 'Export user data as CSV',
|
|
description: 'Export personal data in CSV format for easy viewing',
|
|
})
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'CSV export successful',
|
|
})
|
|
async exportDataCSV(@CurrentUser() user: UserPayload, @Res() res: Response): Promise<void> {
|
|
const exportData = await this.gdprService.exportUserData(user.id);
|
|
|
|
// Convert to CSV (simplified version)
|
|
let csv = 'Category,Field,Value\n';
|
|
|
|
// User data
|
|
Object.entries(exportData.userData).forEach(([key, value]) => {
|
|
csv += `User Data,${key},"${value}"\n`;
|
|
});
|
|
|
|
// Set headers
|
|
res.setHeader('Content-Type', 'text/csv');
|
|
res.setHeader(
|
|
'Content-Disposition',
|
|
`attachment; filename="xpeditis-data-export-${user.id}-${Date.now()}.csv"`
|
|
);
|
|
|
|
res.send(csv);
|
|
}
|
|
|
|
/**
|
|
* Delete user data (GDPR Right to Erasure)
|
|
*/
|
|
@Delete('delete-account')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({
|
|
summary: 'Delete user account and data',
|
|
description: 'Permanently delete or anonymize user data (GDPR Article 17)',
|
|
})
|
|
@ApiResponse({
|
|
status: 204,
|
|
description: 'Account deletion initiated',
|
|
})
|
|
async deleteAccount(
|
|
@CurrentUser() user: UserPayload,
|
|
@Body() body: { reason?: string; confirmEmail: string }
|
|
): Promise<void> {
|
|
// Verify email confirmation (security measure)
|
|
if (body.confirmEmail !== user.email) {
|
|
throw new Error('Email confirmation does not match');
|
|
}
|
|
|
|
await this.gdprService.deleteUserData(user.id, body.reason);
|
|
}
|
|
|
|
/**
|
|
* Record consent
|
|
*/
|
|
@Post('consent')
|
|
@HttpCode(HttpStatus.OK)
|
|
@ApiOperation({
|
|
summary: 'Record user consent',
|
|
description: 'Record consent for marketing, analytics, etc. (GDPR Article 7)',
|
|
})
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'Consent recorded',
|
|
})
|
|
async recordConsent(
|
|
@CurrentUser() user: UserPayload,
|
|
@Body() body: Omit<ConsentData, 'userId'>
|
|
): Promise<{ success: boolean }> {
|
|
await this.gdprService.recordConsent({
|
|
...body,
|
|
userId: user.id,
|
|
});
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Withdraw consent
|
|
*/
|
|
@Post('consent/withdraw')
|
|
@HttpCode(HttpStatus.OK)
|
|
@ApiOperation({
|
|
summary: 'Withdraw consent',
|
|
description: 'Withdraw consent for marketing or analytics (GDPR Article 7.3)',
|
|
})
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'Consent withdrawn',
|
|
})
|
|
async withdrawConsent(
|
|
@CurrentUser() user: UserPayload,
|
|
@Body() body: { consentType: 'marketing' | 'analytics' }
|
|
): Promise<{ success: boolean }> {
|
|
await this.gdprService.withdrawConsent(user.id, body.consentType);
|
|
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* Get consent status
|
|
*/
|
|
@Get('consent')
|
|
@ApiOperation({
|
|
summary: 'Get current consent status',
|
|
description: 'Retrieve current consent preferences',
|
|
})
|
|
@ApiResponse({
|
|
status: 200,
|
|
description: 'Consent status retrieved',
|
|
})
|
|
async getConsentStatus(@CurrentUser() user: UserPayload): Promise<any> {
|
|
return this.gdprService.getConsentStatus(user.id);
|
|
}
|
|
}
|