feat(immich): per-album scheduled/memory dispatch + template tooling
Dispatch: honor {kind}_collection_mode on TrackingConfig — "per_collection"
fans out one event per album; "combined" pools assets as before. Extract
build_immich_dispatch_events shared by cron and test paths.
Assets: collect_scheduled_assets attaches album_name/album_url/album_public_url
to each asset so combined-mode templates can attribute rows to their source
album. Default scheduled_assets templates render a multi-album header with
inline album list and per-row album link; memory_mode follows the same pattern.
UI: "Reset to default" buttons on notification and command template slots
(per-slot and whole-template), backed by new GET /*-template-configs/defaults
endpoints. tracking-configs "Preview template" now opens an inline preview
modal with locale tabs instead of navigating away; Edit button deep-links
with ?edit_slot=<name> so the destination auto-opens the config and scrolls
to the slot. Reset confirmations use ConfirmModal instead of window.confirm.
Fixes:
* NotificationDispatcher._session_ctx infinite recursion when no shared
aiohttp.ClientSession was passed — broke test dispatch for periodic/
scheduled/memory (cron path was unaffected).
* telegram-bots /chats/{id}/test now resolves chat.language_override /
language_code instead of using the raw ?locale query param, matching
the resolution the tracker-target test endpoint already used.
* scheduled_assets default template no longer emits a blank line between
header and the first asset when the multi-album branch is taken.
This commit is contained in:
@@ -426,19 +426,45 @@ async def get_album_shared_links(
|
||||
return []
|
||||
|
||||
|
||||
class CreateSharedLinkRequest(BaseModel):
|
||||
"""Options for POST /shared-links.
|
||||
|
||||
``replace=True`` deletes every existing link for the album before creating
|
||||
the new one, which is the only way to repair an expired or password-
|
||||
protected link in the Immich API (there is no in-place "reset" endpoint).
|
||||
Default ``False`` preserves the original additive behaviour used by the
|
||||
"auto-create missing links" flow.
|
||||
"""
|
||||
|
||||
replace: bool = False
|
||||
|
||||
|
||||
@router.post("/{provider_id}/albums/{album_id}/shared-links")
|
||||
async def create_album_shared_link(
|
||||
provider_id: int,
|
||||
album_id: str,
|
||||
body: CreateSharedLinkRequest | None = None,
|
||||
user: User = Depends(get_current_user),
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
"""Auto-create a public shared link for an album."""
|
||||
"""Auto-create a public shared link for an album.
|
||||
|
||||
With ``replace=True`` existing links for the album are deleted first, so
|
||||
expired/password-protected links are effectively recycled into a fresh
|
||||
public one.
|
||||
"""
|
||||
provider = await _get_user_provider(session, provider_id, user.id)
|
||||
|
||||
if provider.type == "immich":
|
||||
http_session = await get_http_session()
|
||||
immich = make_immich_provider(http_session, provider)
|
||||
if body and body.replace:
|
||||
# Best-effort delete; if any delete fails we still try to create —
|
||||
# the user will see the new link co-exist alongside the old one,
|
||||
# which is better than a hard failure that leaves them stuck.
|
||||
existing = await immich.client.get_shared_links(album_id)
|
||||
for link in existing:
|
||||
await immich.client.delete_shared_link(link.id)
|
||||
success = await immich.client.create_shared_link(album_id)
|
||||
if success:
|
||||
return {"success": True}
|
||||
|
||||
Reference in New Issue
Block a user