Skip to content

Commit fbeaf48

Browse files
committed
feat: add GDPR account management methods (Article 17 & 20)
Add delete_account_data() and export_account_data() for Right to Erasure and Right to Data Portability. Bump version to 1.1.0.
1 parent b65892a commit fbeaf48

5 files changed

Lines changed: 95 additions & 2 deletions

File tree

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,30 @@ async def check_message(message: str):
327327

328328
---
329329

330+
## Best Practices
331+
332+
### Message Batching
333+
334+
The **bullying** and **unsafe content** methods analyze a single `text` field per request. If your platform receives messages one at a time (e.g., a chat app), concatenate a **sliding window of recent messages** into one string before calling the API. Single words or short fragments lack context for accurate detection and can be exploited to bypass safety filters.
335+
336+
```python
337+
# Bad — each message analyzed in isolation, easily evaded
338+
for msg in messages:
339+
client.detect_bullying(text=msg)
340+
341+
# Good — recent messages analyzed together
342+
window = " ".join(recent_messages[-10:])
343+
client.detect_bullying(text=window)
344+
```
345+
346+
The **grooming** method already accepts a `messages` list and analyzes the full conversation in context.
347+
348+
### PII Redaction
349+
350+
Enable `PII_REDACTION_ENABLED=true` on your SafeNest API to automatically strip emails, phone numbers, URLs, social handles, IPs, and other PII from detection summaries and webhook payloads. The original text is still analyzed in full — only stored outputs are scrubbed.
351+
352+
---
353+
330354
## Support
331355

332356
- **API Docs**: [api.safenest.dev/docs](https://api.safenest.dev/docs)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "safenest"
7-
version = "1.0.1"
7+
version = "1.1.0"
88
description = "Official Python SDK for SafeNest - AI-powered child safety API"
99
readme = "README.md"
1010
license = "MIT"

safenest/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
ActionPlanResult,
4141
ReportResult,
4242
Usage,
43+
# Account types (GDPR)
44+
AccountDeletionResult,
45+
AccountExportResult,
4346
)
4447
from safenest.errors import (
4548
SafeNestError,
@@ -52,7 +55,7 @@
5255
NetworkError,
5356
)
5457

55-
__version__ = "1.0.0"
58+
__version__ = "1.1.0"
5659
__all__ = [
5760
# Client
5861
"SafeNest",
@@ -84,6 +87,9 @@
8487
"ActionPlanResult",
8588
"ReportResult",
8689
"Usage",
90+
# Account types (GDPR)
91+
"AccountDeletionResult",
92+
"AccountExportResult",
8793
# Errors
8894
"SafeNestError",
8995
"AuthenticationError",

safenest/client.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
ValidationError,
1717
)
1818
from safenest.models import (
19+
AccountDeletionResult,
20+
AccountExportResult,
1921
ActionPlanResult,
2022
AnalysisContext,
2123
AnalyzeEmotionsInput,
@@ -469,6 +471,28 @@ async def generate_report(
469471
data = await self._request("POST", "/api/v1/reports/incident", body)
470472
return ReportResult.from_dict(data)
471473

474+
# =========================================================================
475+
# Account Management (GDPR)
476+
# =========================================================================
477+
478+
async def delete_account_data(self) -> AccountDeletionResult:
479+
"""Delete all account data (GDPR Article 17 — Right to Erasure).
480+
481+
Returns:
482+
AccountDeletionResult with deletion confirmation.
483+
"""
484+
data = await self._request("DELETE", "/api/v1/account/data")
485+
return AccountDeletionResult.from_dict(data)
486+
487+
async def export_account_data(self) -> AccountExportResult:
488+
"""Export all account data as JSON (GDPR Article 20 — Right to Data Portability).
489+
490+
Returns:
491+
AccountExportResult with full data export.
492+
"""
493+
data = await self._request("GET", "/api/v1/account/export")
494+
return AccountExportResult.from_dict(data)
495+
472496
# =========================================================================
473497
# Private Methods
474498
# =========================================================================

safenest/models.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,3 +411,42 @@ def from_dict(cls, data: dict[str, Any]) -> "ReportResult":
411411
external_id=data.get("external_id"),
412412
metadata=data.get("metadata"),
413413
)
414+
415+
416+
# =============================================================================
417+
# Account Management (GDPR)
418+
# =============================================================================
419+
420+
421+
@dataclass
422+
class AccountDeletionResult:
423+
"""Result from account data deletion (GDPR Article 17)."""
424+
425+
message: str
426+
deleted_count: int
427+
428+
@classmethod
429+
def from_dict(cls, data: dict[str, Any]) -> "AccountDeletionResult":
430+
"""Create from API response dictionary."""
431+
return cls(
432+
message=data["message"],
433+
deleted_count=data["deleted_count"],
434+
)
435+
436+
437+
@dataclass
438+
class AccountExportResult:
439+
"""Result from account data export (GDPR Article 20)."""
440+
441+
user_id: str
442+
exported_at: str
443+
data: dict[str, Any]
444+
445+
@classmethod
446+
def from_dict(cls, data: dict[str, Any]) -> "AccountExportResult":
447+
"""Create from API response dictionary."""
448+
return cls(
449+
user_id=data["userId"],
450+
exported_at=data["exportedAt"],
451+
data=data["data"],
452+
)

0 commit comments

Comments
 (0)