You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
67 lines
2.2 KiB
Python
67 lines
2.2 KiB
Python
# backend/app/services/export_service.py — per-user 데이터 ZIP 번들(소유권) + 민감 필드 redact
|
|
import io
|
|
import json
|
|
import zipfile
|
|
from datetime import date, datetime
|
|
|
|
from sqlmodel import Session, select
|
|
|
|
from ..models import (
|
|
ConnectorAccount,
|
|
Email,
|
|
InboxItem,
|
|
Notification,
|
|
Person,
|
|
Task,
|
|
Trip,
|
|
)
|
|
|
|
_REDACT_FIELDS = {"token_enc", "password_hash", "token_hash", "code_verifier", "scopes"}
|
|
|
|
|
|
def _ser(v):
|
|
if isinstance(v, (datetime, date)):
|
|
return v.isoformat()
|
|
return v
|
|
|
|
|
|
def _dump(rows, user_id: str) -> list[dict]:
|
|
out = []
|
|
for r in rows:
|
|
d = r.model_dump()
|
|
if d.get("user_id") not in (None, user_id) and "user_id" in d:
|
|
continue
|
|
for k in list(d.keys()):
|
|
if k in _REDACT_FIELDS and d[k]:
|
|
d[k] = "[redacted]"
|
|
else:
|
|
d[k] = _ser(d[k])
|
|
out.append(d)
|
|
return out
|
|
|
|
|
|
def _scoped(session: Session, model, user_id: str):
|
|
stmt = select(model)
|
|
if hasattr(model, "user_id"):
|
|
stmt = stmt.where(model.user_id == user_id)
|
|
return session.exec(stmt).all()
|
|
|
|
|
|
def build_export(session: Session, user: Person) -> bytes:
|
|
"""사용자 전 데이터 ZIP(profile/tasks/inbox/emails/notifications/trips/connectors)."""
|
|
buf = io.BytesIO()
|
|
with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as z:
|
|
profile = {"id": user.id, "name": user.name, "initial": user.initial, "email": user.email}
|
|
z.writestr("profile.json", json.dumps(profile, ensure_ascii=False, indent=2))
|
|
bundles = {
|
|
"tasks.json": _dump(_scoped(session, Task, user.id), user.id),
|
|
"inbox.json": _dump(_scoped(session, InboxItem, user.id), user.id),
|
|
"emails.json": _dump(_scoped(session, Email, user.id), user.id),
|
|
"notifications.json": _dump(_scoped(session, Notification, user.id), user.id),
|
|
"trips.json": _dump(_scoped(session, Trip, user.id), user.id),
|
|
"connectors.json": _dump(_scoped(session, ConnectorAccount, user.id), user.id),
|
|
}
|
|
for name, data in bundles.items():
|
|
z.writestr(name, json.dumps(data, ensure_ascii=False, indent=2))
|
|
return buf.getvalue()
|