Improve GDPR implementation
This commit is contained in:
123
services/auth/app/api/data_export.py
Normal file
123
services/auth/app/api/data_export.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""
|
||||
User data export API endpoints for GDPR compliance
|
||||
Implements Article 15 (Right to Access) and Article 20 (Right to Data Portability)
|
||||
"""
|
||||
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi.responses import JSONResponse
|
||||
import structlog
|
||||
|
||||
from shared.auth.decorators import get_current_user_dep
|
||||
from shared.routing import RouteBuilder
|
||||
from app.core.database import get_db
|
||||
from app.services.data_export_service import DataExportService
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
router = APIRouter()
|
||||
route_builder = RouteBuilder('auth')
|
||||
|
||||
|
||||
@router.get("/api/v1/users/me/export")
|
||||
async def export_my_data(
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
db = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Export all personal data for the current user
|
||||
|
||||
GDPR Article 15 - Right of access by the data subject
|
||||
GDPR Article 20 - Right to data portability
|
||||
|
||||
Returns complete user data in machine-readable JSON format including:
|
||||
- Personal information
|
||||
- Account data
|
||||
- Consent history
|
||||
- Security logs
|
||||
- Audit trail
|
||||
|
||||
Response is provided in JSON format for easy data portability.
|
||||
"""
|
||||
try:
|
||||
user_id = UUID(current_user["sub"])
|
||||
|
||||
export_service = DataExportService(db)
|
||||
data = await export_service.export_user_data(user_id)
|
||||
|
||||
logger.info(
|
||||
"data_export_requested",
|
||||
user_id=str(user_id),
|
||||
email=current_user.get("email")
|
||||
)
|
||||
|
||||
return JSONResponse(
|
||||
content=data,
|
||||
status_code=status.HTTP_200_OK,
|
||||
headers={
|
||||
"Content-Disposition": f'attachment; filename="user_data_export_{user_id}.json"',
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"data_export_failed",
|
||||
user_id=current_user.get("sub"),
|
||||
error=str(e)
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to export user data"
|
||||
)
|
||||
|
||||
|
||||
@router.get("/api/v1/users/me/export/summary")
|
||||
async def get_export_summary(
|
||||
current_user: dict = Depends(get_current_user_dep),
|
||||
db = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Get a summary of what data would be exported
|
||||
|
||||
Useful for showing users what data we have about them
|
||||
before they request full export.
|
||||
"""
|
||||
try:
|
||||
user_id = UUID(current_user["sub"])
|
||||
|
||||
export_service = DataExportService(db)
|
||||
data = await export_service.export_user_data(user_id)
|
||||
|
||||
summary = {
|
||||
"user_id": str(user_id),
|
||||
"data_categories": {
|
||||
"personal_data": bool(data.get("personal_data")),
|
||||
"account_data": bool(data.get("account_data")),
|
||||
"consent_data": bool(data.get("consent_data")),
|
||||
"security_data": bool(data.get("security_data")),
|
||||
"onboarding_data": bool(data.get("onboarding_data")),
|
||||
"audit_logs": bool(data.get("audit_logs"))
|
||||
},
|
||||
"data_counts": {
|
||||
"active_sessions": data.get("account_data", {}).get("active_sessions_count", 0),
|
||||
"consent_changes": data.get("consent_data", {}).get("total_consent_changes", 0),
|
||||
"login_attempts": len(data.get("security_data", {}).get("recent_login_attempts", [])),
|
||||
"audit_logs": data.get("audit_logs", {}).get("total_logs_exported", 0)
|
||||
},
|
||||
"export_format": "JSON",
|
||||
"gdpr_articles": ["Article 15 (Right to Access)", "Article 20 (Data Portability)"]
|
||||
}
|
||||
|
||||
return summary
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"export_summary_failed",
|
||||
user_id=current_user.get("sub"),
|
||||
error=str(e)
|
||||
)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to generate export summary"
|
||||
)
|
||||
Reference in New Issue
Block a user