feat(commands): per-chat album scope derived from notification routing
The "per-chat album scope" feature stored on CommandTrackerListener was
really per-bot: listener_id = bot.id, and every chat that bot served
shared the same scope. Commands like /albums, /random, /status,
/events leaked the full provider catalog into chats that were never
wired up to receive notifications from those trackers.
New model: the album scope for /commands in a given chat is derived
from the notification-routing graph. For a (provider, bot, chat_id)
triple we walk TargetReceiver (chat_id match, enabled) →
NotificationTarget (telegram or broadcast parent) →
NotificationTrackerTarget → NotificationTracker (provider match) and
union their collection_ids. That's the natural "what does this chat
get notifications about" set, and it becomes the command scope.
- New helper: command_utils.resolve_chat_album_scope(provider_id,
bot_id, chat_id) -> set[str]. Empty set is the default for chats
with no routing — commands return nothing rather than leaking the
provider's catalog.
- Dispatcher computes the scope per (tracker, bot, chat) and threads
it through handler.handle(..., allowed_album_ids=...). Explicit
CommandTrackerListener.allowed_album_ids override, when set, still
wins verbatim (kept as an escape hatch for users who want a divergent
scope for a whole bot).
- /status, /albums, /events, and all /_cmd_immich-routed commands
(/random, /search, /find, /latest, /memory, /summary, /favorites,
/place, /person) now intersect with the resolved scope.
- UI scope modal relabeled: it's an explicit *override for this bot*,
not a per-chat setting. Default is "derive from notification
routing", which matches what users already configured elsewhere.
Also:
- /search, /find, /person, /place — _enrich_assets return value was
discarded, dropping public_url enrichment. Assign the return value.
- search_smart / search_metadata — consolidated into _search_items
helper that logs non-200 responses and transport errors instead of
silently returning []. Makes "always no results" bugs actually
diagnosable. Also accepts the alternate {"assets": [...]} flat-list
shape from older Immich versions.
- Immich search error bodies go through _redact_body so credentials
echoed by authenticating proxies don't land in server logs.
This commit is contained in:
@@ -56,6 +56,7 @@ class ProviderCommandHandler(ABC):
|
||||
config: CommandConfig,
|
||||
*,
|
||||
listener: CommandTrackerListener | None = None,
|
||||
allowed_album_ids: set[str] | None = None,
|
||||
page: int = 1,
|
||||
) -> CommandResponse | None:
|
||||
"""Handle a provider-specific command for a single tracker.
|
||||
@@ -71,6 +72,13 @@ class ProviderCommandHandler(ABC):
|
||||
bot: The Telegram bot instance.
|
||||
tracker: The command tracker being dispatched.
|
||||
config: The command config for this tracker.
|
||||
listener: The listener row for this (tracker, bot) pair.
|
||||
allowed_album_ids: Precomputed album scope for this (bot, chat)
|
||||
pair. Resolved by the dispatcher from the listener override
|
||||
(if set) or the notification-routing graph. ``None`` means
|
||||
"no scope restriction" (rarely the right default for album
|
||||
providers — empty set is the common case).
|
||||
page: 1-based page number for paginated commands (/search, /find).
|
||||
|
||||
Returns:
|
||||
A CommandResponse, or None if unhandled.
|
||||
|
||||
Reference in New Issue
Block a user