feat(auth): implement Phase 4 user profile and API key endpoints
Build and Push / build (release) Successful in 1m10s
Build and Push / build (release) Successful in 1m10s
Add user profile, preferences, and API key management endpoints: - GET /auth/users/me - full user profile with roles and preferences - GET/PATCH /auth/users/me/preferences - user preferences management - GET/POST/DELETE /auth/users/me/api-keys - API key lifecycle API keys use tak_ prefix, SHA-256 hashing, and are shown only once on creation. Preferences support partial updates with JSON merge behavior. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
7752cd9d23
commit
397a47c8fc
@@ -145,3 +145,67 @@ class GroupRoleAssignmentResponse(BaseSchema):
|
||||
group_id: uuid.UUID = Field(..., description="Group ID")
|
||||
group_name: str = Field(..., description="Group name")
|
||||
roles: list[str] = Field(..., description="Currently assigned role names")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# User Profile (Phase 4)
|
||||
# =============================================================================
|
||||
|
||||
class UserProfileResponse(BaseSchema):
|
||||
"""Response from GET /users/me - full user profile"""
|
||||
|
||||
user: UserSchema = Field(..., description="User profile")
|
||||
roles: list[RoleSchema] = Field(..., description="User's permission roles")
|
||||
preferences: UserPreferencesSchema = Field(..., description="User preferences")
|
||||
|
||||
|
||||
class PreferencesUpdateRequest(BaseSchema):
|
||||
"""Request for PATCH /users/me/preferences"""
|
||||
|
||||
theme: Optional[str] = Field(None, description="Theme preference: system, light, dark")
|
||||
default_room: Optional[str] = Field(None, description="Default room for housekeeping")
|
||||
preferences_json: Optional[dict] = Field(None, description="Extended preferences (merged)")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# API Keys (Phase 4)
|
||||
# =============================================================================
|
||||
|
||||
class ApiKeyCreateRequest(BaseSchema):
|
||||
"""Request for POST /users/me/api-keys"""
|
||||
|
||||
name: str = Field(..., min_length=1, max_length=100, description="Human-readable key name")
|
||||
scopes: Optional[list[str]] = Field(None, description="Optional scope restriction (role names)")
|
||||
expires_in_days: Optional[int] = Field(None, ge=1, le=365, description="Days until expiration (optional)")
|
||||
|
||||
|
||||
class ApiKeyCreateResponse(BaseSchema):
|
||||
"""Response from POST /users/me/api-keys - includes the key (shown only once)"""
|
||||
|
||||
id: uuid.UUID = Field(..., description="API key ID")
|
||||
name: str = Field(..., description="Key name")
|
||||
key: str = Field(..., description="The API key (shown only once!)")
|
||||
key_prefix: str = Field(..., description="Key prefix for identification")
|
||||
scopes: Optional[list[str]] = Field(None, description="Scope restriction")
|
||||
expires_at: Optional[datetime] = Field(None, description="Expiration timestamp")
|
||||
created_at: datetime = Field(..., description="Creation timestamp")
|
||||
|
||||
|
||||
class ApiKeySchema(BaseSchema):
|
||||
"""API key information (without the actual key)"""
|
||||
|
||||
id: uuid.UUID = Field(..., description="API key ID")
|
||||
name: str = Field(..., description="Key name")
|
||||
key_prefix: str = Field(..., description="Key prefix for identification (e.g., 'tak_abc1')")
|
||||
scopes: Optional[list[str]] = Field(None, description="Scope restriction")
|
||||
expires_at: Optional[datetime] = Field(None, description="Expiration timestamp")
|
||||
last_used_at: Optional[datetime] = Field(None, description="Last usage timestamp")
|
||||
created_at: datetime = Field(..., description="Creation timestamp")
|
||||
is_expired: bool = Field(..., description="Whether the key has expired")
|
||||
|
||||
|
||||
class ApiKeysListResponse(BaseSchema):
|
||||
"""Response from GET /users/me/api-keys"""
|
||||
|
||||
items: list[ApiKeySchema] = Field(..., description="List of API keys")
|
||||
total: int = Field(..., description="Total count of keys")
|
||||
|
||||
Reference in New Issue
Block a user