github_backup.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. """Pydantic schemas for GitHub backup configuration."""
  2. import re
  3. from datetime import datetime
  4. from pydantic import BaseModel, Field, field_validator
  5. from backend.app.core.compat import StrEnum
  6. class ScheduleType(StrEnum):
  7. """Backup schedule types."""
  8. HOURLY = "hourly"
  9. DAILY = "daily"
  10. WEEKLY = "weekly"
  11. class GitHubBackupConfigCreate(BaseModel):
  12. """Schema for creating/updating GitHub backup config."""
  13. repository_url: str = Field(..., min_length=1, max_length=500, description="GitHub repository URL")
  14. access_token: str = Field(..., min_length=1, description="Personal Access Token")
  15. branch: str = Field(default="main", max_length=100, description="Branch to push to")
  16. schedule_enabled: bool = Field(default=False, description="Enable scheduled backups")
  17. schedule_type: ScheduleType = Field(default=ScheduleType.DAILY, description="Schedule frequency")
  18. backup_kprofiles: bool = Field(default=True, description="Backup K-profiles")
  19. backup_cloud_profiles: bool = Field(default=True, description="Backup Bambu Cloud profiles")
  20. backup_settings: bool = Field(default=False, description="Backup app settings")
  21. enabled: bool = Field(default=True, description="Enable backup feature")
  22. @field_validator("repository_url")
  23. @classmethod
  24. def validate_repo_url(cls, v: str) -> str:
  25. """Validate GitHub repository URL format."""
  26. # Accept various GitHub URL formats
  27. patterns = [
  28. r"^https://github\.com/[\w.-]+/[\w.-]+(?:\.git)?$",
  29. r"^git@github\.com:[\w.-]+/[\w.-]+(?:\.git)?$",
  30. ]
  31. v = v.strip().rstrip("/")
  32. if not any(re.match(p, v) for p in patterns):
  33. raise ValueError("Invalid GitHub repository URL. Expected format: https://github.com/owner/repo")
  34. return v
  35. class GitHubBackupConfigUpdate(BaseModel):
  36. """Schema for updating GitHub backup config (all fields optional)."""
  37. repository_url: str | None = Field(default=None, max_length=500)
  38. access_token: str | None = Field(default=None)
  39. branch: str | None = Field(default=None, max_length=100)
  40. schedule_enabled: bool | None = None
  41. schedule_type: ScheduleType | None = None
  42. backup_kprofiles: bool | None = None
  43. backup_cloud_profiles: bool | None = None
  44. backup_settings: bool | None = None
  45. enabled: bool | None = None
  46. @field_validator("repository_url")
  47. @classmethod
  48. def validate_repo_url(cls, v: str | None) -> str | None:
  49. if v is None:
  50. return v
  51. patterns = [
  52. r"^https://github\.com/[\w.-]+/[\w.-]+(?:\.git)?$",
  53. r"^git@github\.com:[\w.-]+/[\w.-]+(?:\.git)?$",
  54. ]
  55. v = v.strip().rstrip("/")
  56. if not any(re.match(p, v) for p in patterns):
  57. raise ValueError("Invalid GitHub repository URL")
  58. return v
  59. class GitHubBackupConfigResponse(BaseModel):
  60. """Schema for GitHub backup config API response."""
  61. id: int
  62. repository_url: str
  63. has_token: bool = Field(description="Whether an access token is configured")
  64. branch: str
  65. schedule_enabled: bool
  66. schedule_type: str
  67. backup_kprofiles: bool
  68. backup_cloud_profiles: bool
  69. backup_settings: bool
  70. enabled: bool
  71. last_backup_at: datetime | None
  72. last_backup_status: str | None
  73. last_backup_message: str | None
  74. last_backup_commit_sha: str | None
  75. next_scheduled_run: datetime | None
  76. created_at: datetime
  77. updated_at: datetime
  78. class Config:
  79. from_attributes = True
  80. class GitHubBackupLogResponse(BaseModel):
  81. """Schema for backup log API response."""
  82. id: int
  83. config_id: int
  84. started_at: datetime
  85. completed_at: datetime | None
  86. status: str
  87. trigger: str
  88. commit_sha: str | None
  89. files_changed: int
  90. error_message: str | None
  91. class Config:
  92. from_attributes = True
  93. class GitHubBackupStatus(BaseModel):
  94. """Schema for current backup status."""
  95. configured: bool = Field(description="Whether backup is configured")
  96. enabled: bool = Field(description="Whether backup is enabled")
  97. is_running: bool = Field(description="Whether a backup is currently running")
  98. progress: str | None = Field(default=None, description="Current backup progress message")
  99. last_backup_at: datetime | None
  100. last_backup_status: str | None
  101. next_scheduled_run: datetime | None
  102. class GitHubTestConnectionResponse(BaseModel):
  103. """Schema for test connection response."""
  104. success: bool
  105. message: str
  106. repo_name: str | None = None
  107. permissions: dict | None = None
  108. class GitHubBackupTriggerResponse(BaseModel):
  109. """Schema for manual backup trigger response."""
  110. success: bool
  111. message: str
  112. log_id: int | None = None
  113. commit_sha: str | None = None
  114. files_changed: int = 0