Phase 8: Server health, album filter, Jinja2 engine, password change
Some checks failed
Validate / Hassfest (push) Has been cancelled

5 features implemented:

1. Server health indicator: green/red/yellow dot on each server card.
   Pings Immich in background on page load. New GET /api/servers/{id}/ping.

2. Album selector filter: search input above album list in tracker form.
   Filters by name as you type (case-insensitive). Shows total count.

3. Album last update time: each album in the selector shows its
   updatedAt date. Backend now returns updatedAt from Immich API.

4. Full Jinja2 template engine in notifier:
   - build_full_context() assembles all ~40 variables from blueprint
   - Common date/location detection across assets
   - Per-asset date/location when they differ
   - Favorite indicator, people formatting, asset list with truncation
   - Video warning for Telegram
   - All template slots from TemplateConfig used contextually

5. Password change: PUT /api/auth/password endpoint (validates current
   password, min 6 chars). UI in sidebar footer with inline form.

Also: Phase 9 plan (Telegram bot management) added.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 17:27:00 +03:00
parent 431069fbdb
commit 0200b9929f
10 changed files with 269 additions and 52 deletions

View File

@@ -130,6 +130,28 @@ async def me(user: User = Depends(get_current_user)):
return UserResponse(id=user.id, username=user.username, role=user.role)
class PasswordChangeRequest(BaseModel):
current_password: str
new_password: str
@router.put("/password")
async def change_password(
body: PasswordChangeRequest,
user: User = Depends(get_current_user),
session: AsyncSession = Depends(get_session),
):
"""Change current user's password."""
if not _verify_password(body.current_password, user.hashed_password):
raise HTTPException(status_code=400, detail="Current password is incorrect")
if len(body.new_password) < 6:
raise HTTPException(status_code=400, detail="New password must be at least 6 characters")
user.hashed_password = _hash_password(body.new_password)
session.add(user)
await session.commit()
return {"success": True}
@router.get("/needs-setup")
async def needs_setup(session: AsyncSession = Depends(get_session)):
"""Check if initial setup is needed (no users exist)."""