Spaces:
Running
Running
| """Author RAG Chatbot SaaS — SuperAdmin Pydantic Schemas.""" | |
| from datetime import datetime | |
| from typing import Literal | |
| from pydantic import BaseModel, EmailStr, Field, field_validator | |
| class CreateAuthorRequest(BaseModel): | |
| """Request body for SuperAdmin to create a new author account.""" | |
| email: EmailStr | |
| password: str = Field(..., min_length=8, max_length=128) | |
| full_name: str = Field(..., min_length=1, max_length=255) | |
| plan: Literal["monthly", "quarterly", "semi_annual", "annual"] | None = None | |
| auto_renew: bool = False | |
| def password_complexity(cls, v: str) -> str: | |
| if not any(c.isupper() for c in v): | |
| raise ValueError("Password must contain at least one uppercase letter") | |
| if not any(c.islower() for c in v): | |
| raise ValueError("Password must contain at least one lowercase letter") | |
| if not any(c.isdigit() for c in v): | |
| raise ValueError("Password must contain at least one digit") | |
| if not any(c in "!@#$%^&*()_+-=[]{}|;':\",./<>?" for c in v): | |
| raise ValueError("Password must contain at least one special character") | |
| return v | |
| class GrantAccessRequest(BaseModel): | |
| """Request body for granting subscription access to an author.""" | |
| plan: Literal["monthly", "quarterly", "semi_annual", "annual"] | |
| auto_renew: bool = False | |
| notes: str | None = Field(default=None, max_length=500) | |
| custom_token_budget: int | None = Field(default=None, ge=1) | |
| class RevokeAccessRequest(BaseModel): | |
| """Request body for revoking access. Reason is mandatory.""" | |
| reason: str = Field(..., min_length=5, max_length=500) | |
| class AddBonusTokensRequest(BaseModel): | |
| """Request body for adding bonus tokens.""" | |
| bonus_tokens: int = Field(..., ge=1000) | |
| class ExtendSubscriptionRequest(BaseModel): | |
| """Request body for extending a subscription.""" | |
| extend_days: int = Field(..., ge=1, le=365) | |
| class AccessSummary(BaseModel): | |
| """Summary of a client's active access.""" | |
| grant_id: str | |
| plan: str | |
| expires_at: datetime | |
| is_revoked: bool | |
| token_budget: int | |
| bonus_tokens: int | |
| model_config = {"from_attributes": True} | |
| class ClientSummary(BaseModel): | |
| """Summary of an author client for the list view.""" | |
| id: str | |
| email: str | |
| full_name: str | None | |
| website_url: str | None | |
| chatbot_is_active: bool | |
| created_at: datetime | |
| model_config = {"from_attributes": True} | |
| class ClientListResponse(BaseModel): | |
| clients: list[ClientSummary] | |
| count: int | |
| class ClientDetailResponse(BaseModel): | |
| user: ClientSummary | |
| access: AccessSummary | None | |
| class AccessGrantResponse(BaseModel): | |
| """Response after granting access — includes the subscription token.""" | |
| token: str # The subscription token — send to author securely | |
| access: AccessSummary | |
| class AuditEntry(BaseModel): | |
| id: str | |
| timestamp: datetime | |
| actor_email: str | |
| action: str | |
| target_type: str | None | |
| target_id: str | None | |
| details: str | None | |
| model_config = {"from_attributes": True} | |
| class AuditLogListResponse(BaseModel): | |
| entries: list[AuditEntry] | |
| count: int | |
| class PlatformApiCredentialUpsert(BaseModel): | |
| """SuperAdmin: upsert optional retailer API credential (R-180).""" | |
| platform_id: str = Field(min_length=1, max_length=50) | |
| provider: str = Field(min_length=1, max_length=50) | |
| api_key: str = Field(min_length=8, max_length=500) | |
| api_secret: str | None = Field(default=None, max_length=500) | |
| is_enabled: bool = True | |
| class ProviderApiCredentialUpsert(BaseModel): | |
| """SuperAdmin: upsert shared provider API key (covers all linked platforms).""" | |
| provider_id: str = Field(min_length=1, max_length=50) | |
| api_key: str = Field(min_length=8, max_length=500) | |
| api_secret: str | None = Field(default=None, max_length=500) | |
| is_enabled: bool = True | |