feat: add Gitea as webhook-based service provider

First webhook-based provider integration (Immich uses polling).
Gitea pushes events via POST /api/webhooks/gitea/{provider_id} with
HMAC-SHA256 signature validation.

- 9 event types: push, issue opened/closed/commented, PR opened/closed/merged/commented, release published
- Generic filters system on NotificationTracker (collections, senders, exclude_senders)
- Provider capabilities include supported_filters and webhook_based flag
- Gitea API client for connection testing and repository listing
- 18 default Jinja2 notification templates (EN + RU)
- Frontend: conditional provider forms, Gitea event toggles in tracking config
- Auto-migration for filters column and Gitea tracking flags
This commit is contained in:
2026-03-22 12:58:35 +03:00
parent 1167d138a3
commit 6d28cfb8d8
39 changed files with 1588 additions and 25 deletions
@@ -130,6 +130,34 @@ async def migrate_schema(engine: AsyncEngine) -> None:
)
logger.info("Added memory_source column to tracking_config table")
# Add filters JSON column to notification_tracker if missing
if await _has_table(conn, tracker_table):
if not await _has_column(conn, tracker_table, "filters"):
await conn.execute(
text(f"ALTER TABLE {tracker_table} ADD COLUMN filters TEXT DEFAULT '{{}}'")
)
logger.info("Added filters column to %s table", tracker_table)
# Add Gitea tracking flags to tracking_config if missing
if await _has_table(conn, "tracking_config"):
gitea_flags = [
("track_push", "INTEGER DEFAULT 1"),
("track_issue_opened", "INTEGER DEFAULT 1"),
("track_issue_closed", "INTEGER DEFAULT 1"),
("track_issue_commented", "INTEGER DEFAULT 0"),
("track_pr_opened", "INTEGER DEFAULT 1"),
("track_pr_closed", "INTEGER DEFAULT 1"),
("track_pr_merged", "INTEGER DEFAULT 1"),
("track_pr_commented", "INTEGER DEFAULT 0"),
("track_release_published", "INTEGER DEFAULT 1"),
]
for col_name, col_type in gitea_flags:
if not await _has_column(conn, "tracking_config", col_name):
await conn.execute(
text(f"ALTER TABLE tracking_config ADD COLUMN {col_name} {col_type}")
)
logger.info("Added %s column to tracking_config table", col_name)
# Add collection_name and shared to tracker_state if missing
state_table = "notification_tracker_state" if await _has_table(conn, "notification_tracker_state") else "tracker_state"
if await _has_table(conn, state_table):