feat: person excludes for auto-organize rules, backup & restore system
Add person exclude criteria to Immich auto-organize — assets containing excluded persons are filtered out after candidate gathering. Also adds full backup/restore system with export, import, scheduled backups, and retention management.
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
"""Pydantic models for the configuration backup/restore file format."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class SecretsMode(str, Enum):
|
||||
EXCLUDE = "exclude"
|
||||
MASKED = "masked"
|
||||
INCLUDE = "include"
|
||||
|
||||
|
||||
class ConflictMode(str, Enum):
|
||||
SKIP = "skip"
|
||||
RENAME = "rename"
|
||||
OVERWRITE = "overwrite"
|
||||
|
||||
|
||||
class BackupCategory(str, Enum):
|
||||
PROVIDERS = "providers"
|
||||
TELEGRAM_BOTS = "telegram_bots"
|
||||
MATRIX_BOTS = "matrix_bots"
|
||||
EMAIL_BOTS = "email_bots"
|
||||
TARGETS = "targets"
|
||||
TRACKING_CONFIGS = "tracking_configs"
|
||||
TEMPLATE_CONFIGS = "template_configs"
|
||||
COMMAND_CONFIGS = "command_configs"
|
||||
COMMAND_TEMPLATE_CONFIGS = "command_template_configs"
|
||||
NOTIFICATION_TRACKERS = "notification_trackers"
|
||||
COMMAND_TRACKERS = "command_trackers"
|
||||
ACTIONS = "actions"
|
||||
APP_SETTINGS = "app_settings"
|
||||
|
||||
|
||||
ALL_CATEGORIES = list(BackupCategory)
|
||||
|
||||
# Secret fields in provider config dicts
|
||||
PROVIDER_SECRET_FIELDS = frozenset(
|
||||
("api_key", "api_token", "webhook_secret", "password",
|
||||
"client_secret", "refresh_token")
|
||||
)
|
||||
|
||||
|
||||
# ---------- nested child models ----------
|
||||
|
||||
class ReceiverData(BaseModel):
|
||||
name: str = ""
|
||||
config: dict[str, Any] = {}
|
||||
receiver_key: str = ""
|
||||
locale: str = ""
|
||||
enabled: bool = True
|
||||
|
||||
|
||||
class TargetData(BaseModel):
|
||||
id: int
|
||||
type: str
|
||||
name: str
|
||||
icon: str = ""
|
||||
config: dict[str, Any] = {}
|
||||
chat_action: str | None = "typing"
|
||||
receivers: list[ReceiverData] = []
|
||||
|
||||
|
||||
class TemplateSlotData(BaseModel):
|
||||
slot_name: str
|
||||
locale: str = "en"
|
||||
template: str = ""
|
||||
|
||||
|
||||
class TemplateConfigData(BaseModel):
|
||||
id: int
|
||||
provider_type: str
|
||||
name: str
|
||||
description: str = ""
|
||||
icon: str = ""
|
||||
locale: str = ""
|
||||
date_format: str = "%d.%m.%Y, %H:%M UTC"
|
||||
date_only_format: str = "%d.%m.%Y"
|
||||
slots: list[TemplateSlotData] = []
|
||||
|
||||
|
||||
class CommandTemplateSlotData(BaseModel):
|
||||
slot_name: str
|
||||
locale: str = "en"
|
||||
template: str = ""
|
||||
|
||||
|
||||
class CommandTemplateConfigData(BaseModel):
|
||||
id: int
|
||||
provider_type: str
|
||||
name: str
|
||||
description: str = ""
|
||||
icon: str = ""
|
||||
locale: str = ""
|
||||
slots: list[CommandTemplateSlotData] = []
|
||||
|
||||
|
||||
class TrackerTargetData(BaseModel):
|
||||
target_id: int
|
||||
tracking_config_id: int | None = None
|
||||
template_config_id: int | None = None
|
||||
enabled: bool = True
|
||||
quiet_hours_start: str | None = None
|
||||
quiet_hours_end: str | None = None
|
||||
|
||||
|
||||
class NotificationTrackerData(BaseModel):
|
||||
id: int
|
||||
provider_id: int
|
||||
name: str
|
||||
icon: str = ""
|
||||
collection_ids: list[str] = []
|
||||
filters: dict[str, Any] = {}
|
||||
scan_interval: int = 60
|
||||
batch_duration: int = 0
|
||||
default_tracking_config_id: int | None = None
|
||||
default_template_config_id: int | None = None
|
||||
enabled: bool = True
|
||||
targets: list[TrackerTargetData] = []
|
||||
|
||||
|
||||
class CommandTrackerListenerData(BaseModel):
|
||||
listener_type: str
|
||||
listener_id: int
|
||||
|
||||
|
||||
class CommandTrackerData(BaseModel):
|
||||
id: int
|
||||
provider_id: int
|
||||
command_config_id: int
|
||||
name: str
|
||||
icon: str = ""
|
||||
enabled: bool = True
|
||||
listeners: list[CommandTrackerListenerData] = []
|
||||
|
||||
|
||||
class ActionRuleData(BaseModel):
|
||||
name: str = ""
|
||||
rule_config: dict[str, Any] = {}
|
||||
enabled: bool = True
|
||||
order: int = 0
|
||||
|
||||
|
||||
class ActionData(BaseModel):
|
||||
id: int
|
||||
provider_id: int
|
||||
name: str
|
||||
icon: str = ""
|
||||
action_type: str
|
||||
config: dict[str, Any] = {}
|
||||
schedule_type: str = "interval"
|
||||
schedule_interval: int = 3600
|
||||
schedule_cron: str = ""
|
||||
enabled: bool = False
|
||||
rules: list[ActionRuleData] = []
|
||||
|
||||
|
||||
class ProviderData(BaseModel):
|
||||
id: int
|
||||
type: str
|
||||
name: str
|
||||
icon: str = ""
|
||||
config: dict[str, Any] = {}
|
||||
|
||||
|
||||
class TelegramBotData(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
token: str = ""
|
||||
icon: str = ""
|
||||
bot_username: str = ""
|
||||
update_mode: str = "polling"
|
||||
|
||||
|
||||
class MatrixBotData(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
icon: str = ""
|
||||
homeserver_url: str = ""
|
||||
access_token: str = ""
|
||||
display_name: str = ""
|
||||
|
||||
|
||||
class EmailBotData(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
icon: str = ""
|
||||
email: str = ""
|
||||
smtp_host: str = ""
|
||||
smtp_port: int = 587
|
||||
smtp_username: str = ""
|
||||
smtp_password: str = ""
|
||||
smtp_use_tls: bool = True
|
||||
|
||||
|
||||
class TrackingConfigData(BaseModel):
|
||||
id: int
|
||||
provider_type: str
|
||||
name: str
|
||||
icon: str = ""
|
||||
# All the boolean / int / str tracking fields are captured generically
|
||||
fields: dict[str, Any] = {}
|
||||
|
||||
|
||||
class CommandConfigData(BaseModel):
|
||||
id: int
|
||||
provider_type: str
|
||||
name: str
|
||||
icon: str = ""
|
||||
enabled_commands: list[str] = []
|
||||
response_mode: str = "media"
|
||||
default_count: int = 5
|
||||
rate_limits: dict[str, Any] = {}
|
||||
command_template_config_id: int | None = None
|
||||
|
||||
|
||||
class AppSettingData(BaseModel):
|
||||
key: str
|
||||
value: str = ""
|
||||
|
||||
|
||||
# ---------- top-level backup envelope ----------
|
||||
|
||||
class BackupData(BaseModel):
|
||||
providers: list[ProviderData] = []
|
||||
telegram_bots: list[TelegramBotData] = []
|
||||
matrix_bots: list[MatrixBotData] = []
|
||||
email_bots: list[EmailBotData] = []
|
||||
targets: list[TargetData] = []
|
||||
tracking_configs: list[TrackingConfigData] = []
|
||||
template_configs: list[TemplateConfigData] = []
|
||||
command_configs: list[CommandConfigData] = []
|
||||
command_template_configs: list[CommandTemplateConfigData] = []
|
||||
notification_trackers: list[NotificationTrackerData] = []
|
||||
command_trackers: list[CommandTrackerData] = []
|
||||
actions: list[ActionData] = []
|
||||
app_settings: list[AppSettingData] = []
|
||||
|
||||
|
||||
class BackupFile(BaseModel):
|
||||
format: str = "notify-bridge-backup"
|
||||
version: int = 1
|
||||
created_at: str = ""
|
||||
app_version: str = ""
|
||||
secrets_mode: SecretsMode = SecretsMode.EXCLUDE
|
||||
categories: list[str] = []
|
||||
data: BackupData = Field(default_factory=BackupData)
|
||||
|
||||
|
||||
# ---------- import result ----------
|
||||
|
||||
class ImportResult(BaseModel):
|
||||
created: int = 0
|
||||
skipped: int = 0
|
||||
overwritten: int = 0
|
||||
errors: list[str] = []
|
||||
warnings: list[str] = []
|
||||
|
||||
|
||||
class ValidateResult(BaseModel):
|
||||
valid: bool = True
|
||||
version: int = 0
|
||||
entity_counts: dict[str, int] = {}
|
||||
warnings: list[str] = []
|
||||
errors: list[str] = []
|
||||
Reference in New Issue
Block a user