feat: fix template preview links, default chat action, update default templates

- Fix sanitizePreview regex to match literal quotes instead of " entities
- Default telegram chat_action to "typing" in model and frontend
- Change "photo(s)" to "file(s)" in default templates (EN/RU)
- Remove redundant album URL line from assets_added templates
- Auto-refresh system-owned templates from files on server startup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 01:37:58 +03:00
parent 1d445f3980
commit 371ea70756
8 changed files with 37 additions and 29 deletions
@@ -1,12 +1,9 @@
📷 {{ added_count }} new photo(s) added to album {% if public_url %}<a href="{{ public_url }}">{{ album_name }}</a>{% else %}"{{ album_name }}"{% endif %}.
📷 {{ added_count }} new file(s) added to album {% if public_url %}<a href="{{ public_url }}">{{ album_name }}</a>{% else %}"{{ album_name }}"{% endif %}.
{%- if common_date %} 📅 {{ common_date }}{% endif %}
{%- if common_location %} 📍 {{ common_location }}{% endif %}
{%- if people %}
👤 {{ people | join(", ") }}
{%- endif %}
{%- if public_url %}
🔗 <a href="{{ public_url }}">Album URL</a>
{%- endif %}
{%- if added_assets %}
{%- for asset in added_assets %}
• {%- if asset.type == "VIDEO" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.filename }}</a>{% else %}{{ asset.filename }}{% endif %}
@@ -1 +1 @@
🗑️ {{ removed_count }} photo(s) removed from album {% if public_url %}<a href="{{ public_url }}">{{ album_name }}</a>{% else %}"{{ album_name }}"{% endif %}.
🗑️ {{ removed_count }} file(s) removed from album {% if public_url %}<a href="{{ public_url }}">{{ album_name }}</a>{% else %}"{{ album_name }}"{% endif %}.
@@ -1,12 +1,9 @@
📷 {{ added_count }} новых фото добавлено в альбом {% if public_url %}<a href="{{ public_url }}">{{ album_name }}</a>{% else %}"{{ album_name }}"{% endif %}.
📷 {{ added_count }} новых файл(ов) добавлено в альбом {% if public_url %}<a href="{{ public_url }}">{{ album_name }}</a>{% else %}"{{ album_name }}"{% endif %}.
{%- if common_date %} 📅 {{ common_date }}{% endif %}
{%- if common_location %} 📍 {{ common_location }}{% endif %}
{%- if people %}
👤 {{ people | join(", ") }}
{%- endif %}
{%- if public_url %}
🔗 <a href="{{ public_url }}">Ссылка на альбом</a>
{%- endif %}
{%- if added_assets %}
{%- for asset in added_assets %}
• {%- if asset.type == "VIDEO" %} 🎬{% else %} 🖼️{% endif %} {% if asset.public_url %}<a href="{{ asset.public_url }}">{{ asset.filename }}</a>{% else %}{{ asset.filename }}{% endif %}
@@ -1 +1 @@
🗑️ {{ removed_count }} фото удалено из альбома {% if public_url %}<a href="{{ public_url }}">{{ album_name }}</a>{% else %}"{{ album_name }}"{% endif %}.
🗑️ {{ removed_count }} файл(ов) удалено из альбома {% if public_url %}<a href="{{ public_url }}">{{ album_name }}</a>{% else %}"{{ album_name }}"{% endif %}.
@@ -164,7 +164,7 @@ class NotificationTarget(SQLModel, table=True):
name: str
icon: str = Field(default="")
config: dict[str, Any] = Field(default_factory=dict, sa_column=Column(JSON))
chat_action: str | None = Field(default=None) # e.g. "typing", "upload_photo"
chat_action: str | None = Field(default="typing") # e.g. "typing", "upload_photo"
created_at: datetime = Field(default_factory=_utcnow)
@@ -78,7 +78,7 @@ async def health():
async def _seed_default_templates():
"""Seed default templates on first startup if none exist."""
"""Seed or update default (system-owned) templates on startup."""
from sqlmodel import func, select
from sqlmodel.ext.asyncio.session import AsyncSession
from .database.engine import get_engine
@@ -89,22 +89,36 @@ async def _seed_default_templates():
async with AsyncSession(engine) as session:
result = await session.exec(select(func.count()).select_from(TemplateConfig))
count = result.one()
if count > 0:
return
for locale in ("en", "ru"):
slots = load_default_templates(locale)
if not slots:
continue
name = f"Default ({locale.upper()})"
config = TemplateConfig(
user_id=0,
provider_type="immich",
name=name,
description=f"Default Immich templates ({locale.upper()})",
**slots,
if count == 0:
# First startup — seed all defaults
for locale in ("en", "ru"):
slots = load_default_templates(locale)
if not slots:
continue
name = f"Default ({locale.upper()})"
config = TemplateConfig(
user_id=0,
provider_type="immich",
name=name,
description=f"Default Immich templates ({locale.upper()})",
**slots,
)
session.add(config)
else:
# Update existing system-owned templates from files
result = await session.exec(
select(TemplateConfig).where(TemplateConfig.user_id == 0)
)
session.add(config)
system_configs = result.all()
for config in system_configs:
locale = "ru" if "(RU)" in config.name else "en"
slots = load_default_templates(locale)
if not slots:
continue
for key, value in slots.items():
setattr(config, key, value)
session.add(config)
await session.commit()