feat(tracking): per-config quiet hours with app-level IANA timezone
Add quiet_hours_enabled/start/end to TrackingConfig (HH:MM strings interpreted in the app-level timezone AppSetting). The dispatch path loads the app timezone once per run and passes it through event_allowed_by_config -> in_quiet_hours, so overnight windows like 22:00-07:00 work correctly in any IANA tz. Frontend exposes a Timezone field under Settings and a Quiet Hours section on the Immich tracking-config form with time-picker inputs.
This commit is contained in:
@@ -22,6 +22,7 @@ _SETTING_KEYS = {
|
||||
"telegram_webhook_secret": "NOTIFY_BRIDGE_TELEGRAM_WEBHOOK_SECRET",
|
||||
"telegram_cache_ttl_hours": None, # no env fallback, default 48
|
||||
"supported_locales": None, # comma-separated locale codes
|
||||
"timezone": "NOTIFY_BRIDGE_TIMEZONE", # IANA tz (e.g. "Europe/Warsaw"); empty = UTC
|
||||
}
|
||||
|
||||
_DEFAULTS = {
|
||||
@@ -29,6 +30,7 @@ _DEFAULTS = {
|
||||
"telegram_webhook_secret": "",
|
||||
"telegram_cache_ttl_hours": "48",
|
||||
"supported_locales": "en,ru",
|
||||
"timezone": "UTC",
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +52,7 @@ class SettingsUpdate(BaseModel):
|
||||
telegram_webhook_secret: str | None = None
|
||||
telegram_cache_ttl_hours: str | None = None
|
||||
supported_locales: str | None = None
|
||||
timezone: str | None = None
|
||||
|
||||
|
||||
@router.get("")
|
||||
|
||||
@@ -54,6 +54,9 @@ class TrackingConfigCreate(BaseModel):
|
||||
memory_favorite_only: bool = False
|
||||
memory_asset_type: str = "all"
|
||||
memory_min_rating: int = 0
|
||||
quiet_hours_enabled: bool = False
|
||||
quiet_hours_start: str | None = None
|
||||
quiet_hours_end: str | None = None
|
||||
|
||||
|
||||
class TrackingConfigUpdate(BaseModel):
|
||||
@@ -93,6 +96,9 @@ class TrackingConfigUpdate(BaseModel):
|
||||
memory_favorite_only: bool | None = None
|
||||
memory_asset_type: str | None = None
|
||||
memory_min_rating: int | None = None
|
||||
quiet_hours_enabled: bool | None = None
|
||||
quiet_hours_start: str | None = None
|
||||
quiet_hours_end: str | None = None
|
||||
|
||||
|
||||
@router.get("")
|
||||
|
||||
@@ -27,7 +27,11 @@ from ..database.models import (
|
||||
ServiceProvider,
|
||||
WebhookPayloadLog,
|
||||
)
|
||||
from ..services.dispatch_helpers import event_allowed_by_config, load_link_data
|
||||
from ..services.dispatch_helpers import (
|
||||
event_allowed_by_config,
|
||||
get_app_timezone,
|
||||
load_link_data,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
@@ -144,6 +148,8 @@ async def _dispatch_webhook_event(
|
||||
if not link_data:
|
||||
continue
|
||||
|
||||
app_tz = await get_app_timezone(session)
|
||||
|
||||
# Log event
|
||||
extra_details = {k: v for k, v in event.extra.items() if k in detail_keys}
|
||||
session.add(EventLog(
|
||||
@@ -164,7 +170,7 @@ async def _dispatch_webhook_event(
|
||||
|
||||
# Dispatch to targets
|
||||
dispatcher = NotificationDispatcher()
|
||||
target_configs = _build_target_configs(event, link_data, provider_config)
|
||||
target_configs = _build_target_configs(event, link_data, provider_config, app_tz)
|
||||
if target_configs:
|
||||
results = await dispatcher.dispatch(event, target_configs)
|
||||
for r in results:
|
||||
@@ -513,12 +519,13 @@ def _build_target_configs(
|
||||
event: ServiceEvent,
|
||||
link_data: list[dict[str, Any]],
|
||||
provider_config: dict[str, Any],
|
||||
app_tz: str = "UTC",
|
||||
) -> list[TargetConfig]:
|
||||
"""Build TargetConfig objects for dispatch, applying tracking config filters."""
|
||||
target_configs: list[TargetConfig] = []
|
||||
for ld in link_data:
|
||||
tc = ld["tracking_config"]
|
||||
if tc and not event_allowed_by_config(event, tc):
|
||||
if tc and not event_allowed_by_config(event, tc, app_tz):
|
||||
continue
|
||||
|
||||
tmpl = ld["template_config"]
|
||||
|
||||
Reference in New Issue
Block a user