- OrgCreate / OrgUpdate / OrgResponse um output_language (de | en). - routers/organizations.py persistiert die Sprache nach create/update via shared.services.org_settings.set_org_setting. - _enrich_org liest output_language aus organization_settings (Default de). - Frontend: Dropdown im Modal Neue Organisation und im Org-Edit-Formular, Auto-Befuellung aus org.output_language. Cache-Buster auf app.js gebumpt. Phase 7 von 8 (eng_demo / Org-Sprache).
100 Zeilen
2.6 KiB
Python
100 Zeilen
2.6 KiB
Python
"""Pydantic Models für das Verwaltungsportal."""
|
|
from pydantic import BaseModel, Field
|
|
from typing import Optional
|
|
|
|
|
|
class MagicLinkRequest(BaseModel):
|
|
email: str = Field(min_length=3, max_length=200)
|
|
|
|
|
|
class MagicLinkResponse(BaseModel):
|
|
message: str
|
|
|
|
|
|
class VerifyTokenRequest(BaseModel):
|
|
token: str = Field(min_length=10, max_length=200)
|
|
|
|
|
|
class TokenResponse(BaseModel):
|
|
access_token: str
|
|
token_type: str = "bearer"
|
|
username: str
|
|
email: str = ""
|
|
|
|
|
|
class OrgCreate(BaseModel):
|
|
name: str = Field(min_length=1, max_length=200)
|
|
slug: str = Field(min_length=1, max_length=100, pattern="^[a-z0-9-]+$")
|
|
output_language: str = Field(default="de", pattern="^(de|en)$")
|
|
|
|
|
|
class OrgUpdate(BaseModel):
|
|
name: Optional[str] = Field(default=None, max_length=200)
|
|
is_active: Optional[bool] = None
|
|
output_language: Optional[str] = Field(default=None, pattern="^(de|en)$")
|
|
|
|
|
|
class OrgResponse(BaseModel):
|
|
id: int
|
|
name: str
|
|
slug: str
|
|
is_active: bool
|
|
user_count: int = 0
|
|
license_status: str = ""
|
|
license_type: str = ""
|
|
created_at: str
|
|
globe_access: bool = False
|
|
network_access: bool = False
|
|
output_language: str = "de"
|
|
|
|
|
|
class LicenseCreate(BaseModel):
|
|
organization_id: int
|
|
license_type: str = Field(pattern="^(trial|annual|permanent)$")
|
|
max_users: int = Field(default=5, ge=1, le=1000)
|
|
duration_days: Optional[int] = Field(default=None, ge=1, le=3650)
|
|
token_budget_usd: Optional[float] = None
|
|
credits_total: Optional[int] = None
|
|
cost_per_credit: Optional[float] = None
|
|
budget_warning_percent: Optional[int] = Field(default=80, ge=1, le=100)
|
|
unlimited_budget: bool = False
|
|
|
|
|
|
class LicenseResponse(BaseModel):
|
|
id: int
|
|
organization_id: int
|
|
license_type: str
|
|
max_users: int
|
|
valid_from: str
|
|
valid_until: Optional[str]
|
|
status: str
|
|
notes: Optional[str]
|
|
token_budget_usd: Optional[float] = None
|
|
credits_total: Optional[int] = None
|
|
credits_used: Optional[float] = None
|
|
cost_per_credit: Optional[float] = None
|
|
budget_warning_percent: Optional[int] = None
|
|
unlimited_budget: bool = False
|
|
created_at: str
|
|
globe_access: bool = False
|
|
network_access: bool = False
|
|
|
|
|
|
class UserCreate(BaseModel):
|
|
email: str = Field(min_length=3, max_length=200)
|
|
username: Optional[str] = Field(default=None, max_length=100)
|
|
role: str = Field(default="member", pattern="^(org_admin|member)$")
|
|
|
|
|
|
class UserResponse(BaseModel):
|
|
id: int
|
|
email: str
|
|
username: str
|
|
organization_id: int
|
|
role: str
|
|
is_active: bool
|
|
last_login_at: Optional[str]
|
|
created_at: str
|
|
globe_access: bool = False
|
|
network_access: bool = False
|