feat(dsgvo): Art. 15 Auskunftsrecht – strukturierter Datenexport pro User
Security Audit / Python Dependency Audit (push) Has been cancelled
Security Audit / Node.js Dependency Audit (push) Has been cancelled

GET /users/{id}/export-data liefert alle personenbezogenen Daten
(Profil, Zeiterfassung, Abwesenheiten, Kommentare, Urlaubs-/Überstunden-
konto, Auszahlungen, AuditLog-Einträge über den User) als JSON-Download.
Eigenes Konto immer erlaubt, fremde Konten nur HR/Admin/Manager der
eigenen Firma. Ergänzt die bestehende Art.-17-Anonymisierung.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CviFgc739S89xS97pvjszj
This commit is contained in:
2026-08-07 08:19:15 +02:00
co-authored by Claude Sonnet 5
parent a6b54c8f74
commit 84af5a874a
2 changed files with 153 additions and 1 deletions
+26 -1
View File
@@ -2,7 +2,7 @@ from typing import Annotated
from uuid import UUID
from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile
from fastapi.responses import PlainTextResponse
from fastapi.responses import PlainTextResponse, Response
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db
@@ -22,6 +22,7 @@ from app.schemas.user import (
UserUpdate,
)
from app.services import user_import_service
from app.services.gdpr_service import gdpr_service
from app.services.user_service import user_service
router = APIRouter(prefix="/users", tags=["Users"])
@@ -244,6 +245,30 @@ async def anonymize_user(
return UserOut.model_validate(user)
@router.get("/{user_id}/export-data")
async def export_user_data(
user_id: UUID,
current_user: CurrentUser,
db: AsyncSession = Depends(get_db),
):
"""DSGVO Art. 15 (Auskunftsrecht): strukturierter Export aller
personenbezogenen Daten des Users als JSON. Eigenes Konto immer erlaubt,
fremde Konten nur für HR/Admin/Manager der eigenen Firma."""
if user_id != current_user.id and current_user.role not in _hr_roles:
raise HTTPException(status_code=403, detail="Keine Berechtigung für dieses Konto")
try:
data = await gdpr_service.export_user_data(user_id, current_user.company_id, db)
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
content = gdpr_service.to_json(data)
return Response(
content=content, media_type="application/json",
headers={"Content-Disposition": f"attachment; filename=datenauskunft_{user_id}.json"},
)
@router.post("/{user_id}/kiosk-pin", response_model=MessageResponse)
async def set_kiosk_pin(
user_id: UUID,