389 lines
9.9 KiB
Python
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
|