Files
GitMa/backend/app/schemas/server.py
panw 44921c5646 feat: complete Git Repo Manager MVP implementation
Backend (Phase 1-6):
- Pydantic schemas for request/response validation
- Service layer (SSH Key, Server, Repo, Sync)
- API routes with authentication
- FastAPI main application with lifespan management
- ORM models (SshKey, Server, Repo, SyncLog)

Frontend (Phase 7):
- Vue 3 + Element Plus + Pinia + Vue Router
- API client with Axios and interceptors
- State management stores
- All page components (Dashboard, Servers, Repos, SyncLogs, SshKeys, Settings)

Deployment (Phase 8):
- README with quick start guide
- Startup script (start.sh)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 16:30:13 +08:00

173 lines
6.3 KiB
Python

"""
Server Pydantic schemas.
"""
from typing import Optional
from pydantic import BaseModel, Field, field_validator
class ServerCreate(BaseModel):
"""
Schema for creating a new server.
"""
name: str = Field(..., min_length=1, max_length=100, description="Server name")
url: str = Field(..., min_length=1, max_length=500, description="Gitea server URL")
api_token: str = Field(..., min_length=1, description="Gitea API token")
ssh_key_id: int = Field(..., gt=0, description="SSH key ID to use")
local_path: str = Field(..., min_length=1, max_length=500, description="Local storage path")
sync_enabled: bool = Field(default=False, description="Whether sync is enabled")
schedule_cron: Optional[str] = Field(
default=None,
max_length=50,
description="Cron expression for scheduled sync"
)
@field_validator("name")
@classmethod
def name_must_not_be_empty(cls, v: str) -> str:
"""Validate that name is not empty or whitespace only."""
if not v or not v.strip():
raise ValueError("name must not be empty")
return v.strip()
@field_validator("url")
@classmethod
def url_must_not_be_empty(cls, v: str) -> str:
"""Validate that url is not empty or whitespace only."""
if not v or not v.strip():
raise ValueError("url must not be empty")
return v.strip()
@field_validator("api_token")
@classmethod
def api_token_must_not_be_empty(cls, v: str) -> str:
"""Validate that api_token is not empty or whitespace only."""
if not v or not v.strip():
raise ValueError("api_token must not be empty")
return v.strip()
@field_validator("local_path")
@classmethod
def local_path_must_not_be_empty(cls, v: str) -> str:
"""Validate that local_path is not empty or whitespace only."""
if not v or not v.strip():
raise ValueError("local_path must not be empty")
return v.strip()
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "my-gitea",
"url": "https://gitea.example.com",
"api_token": "your_api_token_here",
"ssh_key_id": 1,
"local_path": "/data/gitea-mirror",
"sync_enabled": False,
"schedule_cron": None
}
]
}
}
class ServerUpdate(BaseModel):
"""
Schema for updating a server.
All fields are optional.
"""
name: Optional[str] = Field(None, min_length=1, max_length=100, description="Server name")
url: Optional[str] = Field(None, min_length=1, max_length=500, description="Gitea server URL")
api_token: Optional[str] = Field(None, min_length=1, description="Gitea API token")
ssh_key_id: Optional[int] = Field(None, gt=0, description="SSH key ID to use")
local_path: Optional[str] = Field(None, min_length=1, max_length=500, description="Local storage path")
sync_enabled: Optional[bool] = Field(None, description="Whether sync is enabled")
schedule_cron: Optional[str] = Field(
None,
max_length=50,
description="Cron expression for scheduled sync"
)
status: Optional[str] = Field(
None,
pattern="^(untested|testing|success|error)$",
description="Server status"
)
@field_validator("name")
@classmethod
def name_must_not_be_empty(cls, v: Optional[str]) -> Optional[str]:
"""Validate that name is not empty or whitespace only."""
if v is not None and (not v or not v.strip()):
raise ValueError("name must not be empty")
return v.strip() if v else None
@field_validator("url")
@classmethod
def url_must_not_be_empty(cls, v: Optional[str]) -> Optional[str]:
"""Validate that url is not empty or whitespace only."""
if v is not None and (not v or not v.strip()):
raise ValueError("url must not be empty")
return v.strip() if v else None
@field_validator("api_token")
@classmethod
def api_token_must_not_be_empty(cls, v: Optional[str]) -> Optional[str]:
"""Validate that api_token is not empty or whitespace only."""
if v is not None and (not v or not v.strip()):
raise ValueError("api_token must not be empty")
return v.strip() if v else None
@field_validator("local_path")
@classmethod
def local_path_must_not_be_empty(cls, v: Optional[str]) -> Optional[str]:
"""Validate that local_path is not empty or whitespace only."""
if v is not None and (not v or not v.strip()):
raise ValueError("local_path must not be empty")
return v.strip() if v else None
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "updated-gitea",
"sync_enabled": True,
"schedule_cron": "0 */6 * * *"
}
]
}
}
class ServerResponse(BaseModel):
"""
Schema for server response.
"""
id: int = Field(description="Server ID")
name: str = Field(description="Server name")
url: str = Field(description="Gitea server URL")
ssh_key_id: int = Field(description="SSH key ID")
sync_enabled: bool = Field(description="Whether sync is enabled")
schedule_cron: Optional[str] = Field(default=None, description="Cron expression")
local_path: str = Field(description="Local storage path")
status: str = Field(description="Server status")
created_at: int = Field(description="Creation timestamp (Unix timestamp)")
updated_at: int = Field(description="Last update timestamp (Unix timestamp)")
model_config = {
"json_schema_extra": {
"examples": [
{
"id": 1,
"name": "my-gitea",
"url": "https://gitea.example.com",
"ssh_key_id": 1,
"sync_enabled": True,
"schedule_cron": "0 */6 * * *",
"local_path": "/data/gitea-mirror",
"status": "success",
"created_at": 1711804800,
"updated_at": 1711891200
}
]
}
}