Files
periodic-table/backend/src/models.py
2025-12-02 11:47:45 -03:00

389 lines
9.9 KiB
Python

from typing import Optional, List
from datetime import datetime
from pydantic import BaseModel, SecretStr
class TokenRequest(BaseModel):
username: str
password: SecretStr
class TokenResponse(BaseModel):
access_token: str
token_type: str = "bearer"
class UserInfo(BaseModel):
sub: Optional[str] = None # Keycloak subject ID
preferred_username: str
email: Optional[str] = None
full_name: Optional[str] = None
db_user_id: Optional[int] = None # Database user ID (populated after login)
role: Optional[str] = None # User role name
role_id: Optional[int] = None # User role ID (1=editor, 2=auditor, 3=admin)
# Role schemas
ROLE_DISPLAY_NAMES = {
"editor": "Editor",
"auditor": "Auditor",
"admin": "Project Admin"
}
class RoleResponse(BaseModel):
"""Response schema for a role."""
id: int
role_name: str
display_name: str
class Config:
from_attributes = True
@classmethod
def from_role(cls, role) -> "RoleResponse":
"""Create a RoleResponse from a Role model."""
return cls(
id=role.id,
role_name=role.role_name,
display_name=ROLE_DISPLAY_NAMES.get(role.role_name, role.role_name.title())
)
class ProjectMemberResponse(BaseModel):
"""Response schema for a project member with role info."""
id: int
sub: str
role_id: int
role_name: str
role_display_name: str
created_at: Optional[datetime] = None
class Config:
from_attributes = True
class UserRoleUpdateRequest(BaseModel):
"""Request schema for updating a user's role."""
role_id: int
# Project schemas
class ProjectBase(BaseModel):
"""Base schema for projects."""
project_name: str
project_desc: Optional[str] = None
class ProjectResponse(BaseModel):
"""Response schema for a single project."""
id: int
project_name: str
project_desc: Optional[str] = None
created_at: Optional[datetime] = None
class Config:
from_attributes = True
class ProjectCreateRequest(BaseModel):
"""Request schema for creating a project."""
project_name: str
project_desc: Optional[str] = None
class ProjectUpdateRequest(BaseModel):
"""Request schema for updating a project."""
project_name: Optional[str] = None
project_desc: Optional[str] = None
class ProjectListResponse(BaseModel):
"""Response schema for list of projects."""
projects: List[ProjectResponse]
class ProjectMemberRequest(BaseModel):
"""Request schema for adding/removing project members."""
user_id: int
# Group schemas
class GroupResponse(BaseModel):
"""Response schema for a single group."""
id: int
group_name: str
hex_color: str
class Config:
from_attributes = True
class GroupListResponse(BaseModel):
"""Response schema for list of groups."""
groups: List[GroupResponse]
# Tag schemas
class TagResponse(BaseModel):
"""Response schema for a single tag."""
id: int
tag_code: str
tag_description: str
class Config:
from_attributes = True
class TagListResponse(BaseModel):
"""Response schema for list of tags."""
tags: List[TagResponse]
# Priority schemas
class PriorityResponse(BaseModel):
"""Response schema for a priority."""
id: int
priority_name: str
priority_num: int
class Config:
from_attributes = True
# Requirement Status schemas
class RequirementStatusResponse(BaseModel):
"""Response schema for a requirement lifecycle status."""
id: int
status_code: str
status_name: str
description: Optional[str] = None
class Config:
from_attributes = True
# Validation schemas
class ValidationStatusResponse(BaseModel):
"""Response schema for a validation status."""
id: int
status_name: str
class Config:
from_attributes = True
class ValidationResponse(BaseModel):
"""Response schema for a validation."""
id: int
status_name: str
req_version_snapshot: int
comment: Optional[str] = None
created_at: Optional[datetime] = None
class Config:
from_attributes = True
class ValidationHistoryResponse(BaseModel):
"""Response schema for validation history with validator info."""
id: int
status_name: str
status_id: int
req_version_snapshot: int
comment: Optional[str] = None
created_at: Optional[datetime] = None
validator_username: str
validator_id: int
class Config:
from_attributes = True
class ValidationCreateRequest(BaseModel):
"""Request schema for creating a validation."""
status_id: int
comment: Optional[str] = None
# Requirement schemas
class RequirementResponse(BaseModel):
"""Response schema for a single requirement."""
id: int
project_id: int
req_name: str
req_desc: Optional[str] = None
version: int
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
tag: TagResponse
priority: Optional[PriorityResponse] = None
groups: List[GroupResponse] = []
# Requirement lifecycle status (Draft, Regular)
status: Optional[RequirementStatusResponse] = None
# Validation status (Approved, Denied, etc.)
validation_status: Optional[str] = None # Computed from latest validation
validated_by: Optional[str] = None # Username of the validator
validated_at: Optional[datetime] = None # When the latest validation was made
validation_version: Optional[int] = None # Version at which requirement was validated
author_username: Optional[str] = None # Display name of who created the requirement
last_editor_username: Optional[str] = None # Display name of who last edited the requirement
class Config:
from_attributes = True
class RequirementListResponse(BaseModel):
"""Response schema for list of requirements."""
requirements: List[RequirementResponse]
class RequirementCreateRequest(BaseModel):
"""Request schema for creating a requirement."""
project_id: int
tag_id: int
req_name: str
req_desc: Optional[str] = None
priority_id: Optional[int] = None
group_ids: Optional[List[int]] = None
status_id: Optional[int] = None # Defaults to Draft (1) if not provided
class RequirementUpdateRequest(BaseModel):
"""Request schema for updating a requirement."""
req_name: Optional[str] = None
req_desc: Optional[str] = None
tag_id: Optional[int] = None
priority_id: Optional[int] = None
group_ids: Optional[List[int]] = None
status_id: Optional[int] = None
class RequirementHistoryResponse(BaseModel):
"""Response schema for requirement history (previous versions)."""
history_id: int
version: Optional[int] = None
req_name: Optional[str] = None
req_desc: Optional[str] = None
tag_code: Optional[str] = None
priority_name: Optional[str] = None
edited_by_username: Optional[str] = None
valid_from: Optional[datetime] = None
valid_to: Optional[datetime] = None
class Config:
from_attributes = True
# Relationship Type schemas
class RelationshipTypeResponse(BaseModel):
"""Response schema for a relationship type."""
id: int
project_id: int
type_name: str
type_description: Optional[str] = None
inverse_type_name: Optional[str] = None
class Config:
from_attributes = True
class RelationshipTypeCreateRequest(BaseModel):
"""Request schema for creating a relationship type."""
type_name: str
type_description: Optional[str] = None
inverse_type_name: Optional[str] = None
class RelationshipTypeUpdateRequest(BaseModel):
"""Request schema for updating a relationship type."""
type_name: Optional[str] = None
type_description: Optional[str] = None
inverse_type_name: Optional[str] = None
# Requirement Link schemas
class LinkedRequirementInfo(BaseModel):
"""Brief info about a linked requirement."""
id: int
req_name: str
tag_code: str
class Config:
from_attributes = True
class RequirementLinkResponse(BaseModel):
"""Response schema for a requirement link with direction."""
id: int
direction: str # 'outgoing' or 'incoming'
type_name: str
type_id: int
inverse_type_name: Optional[str] = None
linked_requirement: LinkedRequirementInfo
created_by_username: Optional[str] = None
created_by_id: Optional[int] = None
created_at: Optional[datetime] = None
class Config:
from_attributes = True
class RequirementLinkCreateRequest(BaseModel):
"""Request schema for creating a requirement link."""
relationship_type_id: int
target_requirement_id: int
# Requirement Search schemas
class RequirementSearchResult(BaseModel):
"""Response schema for requirement search results (for autocomplete)."""
id: int
req_name: str
tag_code: str
class Config:
from_attributes = True
# Comment schemas
class CommentReplyResponse(BaseModel):
"""Response schema for a comment reply."""
id: int
reply_text: str
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
author_id: Optional[int] = None
author_username: Optional[str] = None
author_full_name: Optional[str] = None
author_role: Optional[str] = None
class Config:
from_attributes = True
class CommentResponse(BaseModel):
"""Response schema for a comment with its replies."""
id: int
comment_text: str
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
author_id: Optional[int] = None
author_username: Optional[str] = None
author_full_name: Optional[str] = None
author_role: Optional[str] = None
replies: List[CommentReplyResponse] = []
class Config:
from_attributes = True
class CommentCreateRequest(BaseModel):
"""Request schema for creating a comment."""
comment_text: str
class ReplyCreateRequest(BaseModel):
"""Request schema for creating a reply."""
reply_text: str