Commit Graph

16 Commits

Author SHA1 Message Date
alexei.dolgolyov d0bc767e98 feat: rich command templates with public links + media text-first flow
- Command templates now match notification template style: type icons,
  linked filenames via album shared links, location, favorite status
- Media mode sends text message first, then media as reply (was media-only)
- Search/find/person/place resolve asset public URLs from tracked albums'
  shared links (share/{key}/photos/{id})
- Albums/summary commands include album public_url in context
- Enriched command template preview sample context with public_url, city,
  country, is_favorite
- Extract sanitizePreview to shared lib/sanitize.ts
- Command template preview now renders HTML links (was raw text)
- Global provider filter moved above search in sidebar
- CLAUDE.md: template consistency + context variable sync rules
2026-03-24 16:48:57 +03:00
alexei.dolgolyov 68ac13b452 feat: NUT (Network UPS Tools) service provider + provider-agnostic UI
Add full NUT support as a polling-based service provider:
- Async TCP client for upsd protocol (port 3493, configurable)
- 8 event types: online, on_battery, low_battery, battery_restored,
  comms_lost, comms_restored, replace_battery, overload
- 3 bot commands: /status, /devices, /battery
- 38 Jinja2 templates (EN+RU notification + command templates)
- Database: tracking config fields, migration, seeds
- Frontend: provider form with host/port/credentials, grid items, i18n

Provider-agnostic UI improvements:
- Remove hardcoded 'immich' defaults from all config forms
- Dynamic collection labels per provider type (Albums/Repos/Boards/UPS Devices)
- Capability-driven test types instead of provider type checks
- Template variable helpers for all providers (was Immich-only)
- Guard Immich-only shared link check to Immich providers
- Auto-clear stale global provider filter from localStorage
- EntitySelect search placeholder shows current selection
- Fix noneLabel in linked target config selectors

New CLAUDE.md rule #8: no provider-specific hardcoding
2026-03-23 23:23:58 +03:00
alexei.dolgolyov 1cfa72888c feat: Receiver OOP hierarchy with per-receiver locale resolution
- Introduce Receiver base class + typed subclasses (TelegramReceiver,
  WebhookReceiver, EmailReceiver, etc.) in core/notifications/receiver.py
- Dispatcher uses typed Receiver objects instead of raw dicts, with
  per-receiver locale-aware template rendering
- load_link_data resolves locale from TelegramChat.language_override at
  load time: TargetReceiver.locale || chat.language_override || chat.language_code
- Add language_override field to TelegramChat (separate from auto-detected
  language_code), with per-chat commands toggle and command dispatch using
  override language
- Add locale field to TargetReceiver for explicit per-receiver overrides
2026-03-23 21:20:31 +03:00
alexei.dolgolyov b3b6c31c4d feat: per-chat command toggle, listener name + toggle in bot tab
- Add commands_enabled field to TelegramChat (default off) with
  migration, gating command dispatch in both poller and webhook
- Show toggle switch per chat in bot tab for enabling/disabling commands
- Fix listener response to include bot name instead of just type
- Replace listener "Enabled" label + "Edit" link with toggle switch
  and crosslink to command-trackers page
2026-03-23 19:23:37 +03:00
alexei.dolgolyov 0fde3c6b3d feat: add Planka service provider with full notification and command support
Webhook-based provider for Planka (self-hosted Kanban board) with:
- 15 event types (cards, boards, lists, comments, tasks, attachments, labels)
- Bearer token webhook authentication
- Async API client for boards/cards/lists
- 30 notification templates (en/ru) + 26 command templates (en/ru)
- Bot commands: /status, /boards, /cards, /lists
- Default tracking config, template config, command config seeded on startup
- DB migration for 15 new tracking_config columns
- Frontend: provider config UI with auto-name, Planka-specific hints
- Frontend: tracking config event toggles for all 15 Planka events
2026-03-23 15:54:00 +03:00
alexei.dolgolyov e0bae394ee feat: comprehensive code review fixes — security, performance, quality
Backend security:
- Reject Gitea webhooks when webhook_secret is empty (was silently skipping)
- Add slowapi rate limiting on login (5/min) and setup (3/min) endpoints
- Add CORS middleware with configurable origins
- Mask telegram_webhook_secret in settings API response
- Protect system-owned command template configs from regular user modification
- Increase minimum password length to 8 characters

Backend performance:
- Batch queries in _resolve_command_context (3 queries instead of 3N)
- Concurrent album fetching with asyncio.gather in immich commands
- Singleton Jinja2 SandboxedEnvironment (reuse instead of per-render creation)
- TTLCache for rate limits (bounded memory, auto-eviction)
- Optional aiohttp session reuse in send_reply/send_media_group

Backend code quality:
- Extract dispatch_helpers.py (shared link_data loading + event filtering)
- Extract database/seeds.py from main.py (490 lines → dedicated module)
- Split immich_handler.py (415 lines) into commands/immich/ subpackage
- Replace bare except blocks with logged warnings
- Add per-provider config validation (Pydantic models)
- Truncate command input to 512 chars
- Expose usage_* and desc_* slots in capabilities and variables API

Frontend security:
- CSS.escape() for user-controlled querySelector in highlight.ts
- Client-side password min 8 chars validation on setup and password change

Frontend code quality:
- Replace any types with proper interfaces across top files
- Decompose targets/+page.svelte into TargetForm + ReceiverSection
- Fix $derived.by usage, $state mutation patterns
- Add console.warn to empty catch blocks

Frontend UX:
- Auth redirect via goto() with "Redirecting..." state
- Platform-aware Ctrl/Cmd K keyboard hint
- Remove stat-card hover transform

Frontend accessibility:
- Modal: role=dialog, aria-modal, focus trap, restore focus
- EntitySelect/IconGridSelect: listbox/option roles, aria-selected/disabled
2026-03-23 01:59:51 +03:00
alexei.dolgolyov 82e400ddcd feat: chat language display, disabled EntitySelect items, dev scripts
Chat language:
- Added language_code field to TelegramChat model + migration
- Saved from message.from.language_code on webhook/polling
- Displayed as badge on bot chat cards and target receiver items
- Resolved from DB in target API response (works for existing receivers)
- Shown in chat picker dropdown (desc includes language)

EntitySelect improvements:
- Tracker-target link selector shows all targets, already-linked ones
  appear disabled with "Already linked" hint
- Receiver chat picker shows already-added chats as disabled

Dev scripts:
- scripts/restart-backend.sh and restart-frontend.sh
- Updated .claude/docs/dev-servers.md to reference scripts
2026-03-22 23:39:52 +03:00
alexei.dolgolyov 63437c1841 refactor: provider-agnostic bot command system + Gitea commands
Refactored the monolithic command handler (707 lines) into a pluggable
provider-handler architecture:

- Abstract ProviderCommandHandler interface (base.py)
- Handler dispatch registry routes commands by provider type
- Extracted all Immich logic into ImmichCommandHandler
- New GiteaCommandHandler with /status, /repos, /issues, /prs, /commits
- Multi-provider routing: groups context by provider type, finds handler
- handler.py reduced to ~280 line thin orchestrator

Gitea commands:
- Extended GiteaClient with get_repo_issues, get_repo_pulls, get_repo_commits
- 30 Jinja2 command templates (15 EN + 15 RU)
- Gitea capabilities updated with 6 commands + 15 command_slots
- Default command config + command template config seeded on startup
- Rate limiting: Gitea API commands share "api" category (15s cooldown)

Also:
- Command configs API accepts "gitea" provider type
- System command configs (user_id=0) visible to all users
- Webhook URL shown on Gitea provider card and edit form
- Scan interval hidden for webhook-based providers
2026-03-22 17:44:47 +03:00
alexei.dolgolyov 1167d138a3 feat: locale-aware command templates, debounced auto-sync, entity pickers
- Locale-aware templates: CommandTemplateSlot now has a locale column,
  allowing each slot to have per-language variants (EN/RU). Templates
  are resolved at runtime from the Telegram user's language_code.

- Merged system configs: "Default Commands (EN)" and "(RU)" merged
  into a single "Default Commands" config with locale-aware slots.
  Migration handles existing data automatically.

- Configurable command descriptions: hardcoded COMMAND_DESCRIPTIONS
  replaced with desc_* template slots (desc_status, desc_help, etc.)
  that users can customize per locale. setMyCommands registers all
  locales explicitly.

- Removed locale from CommandConfig: no longer needed since locale
  is derived from the Telegram user's language at runtime.

- Debounced command auto-sync: after command config/tracker changes,
  affected bots are marked dirty and synced after a 30s debounce
  window. Manual "Sync with Telegram" button still works.

- Entity pickers in LinkedTargetsSection: replaced 6 plain <select>
  elements with EntitySelect components (search, icons, keyboard nav).
  Added onselect callback and size="sm" props to EntitySelect.
2026-03-22 03:14:51 +03:00
alexei.dolgolyov 751097b347 feat: comprehensive code review fixes + receivers-only architecture
Security:
- Refuse startup with default secret_key in production (was just logging)
- Settings endpoint now requires admin role
- Password validation on initial setup
- DOM-based HTML sanitizer replaces regex in template previews
- Add *.log to .gitignore

Performance & reliability:
- Token refresh deduplication prevents race condition on concurrent 401s
- Theme media query listener registered once (no leak)
- IconPicker uses $derived instead of function call per render
- Snackbar uses single-batch state update instead of while loop
- Replace 11 inline hover handlers with CSS :hover in layout

Architecture - receivers-only:
- Delivery endpoints (chat_id, email, url, room_id, topic) now stored
  exclusively in TargetReceiver rows, never in target.config
- Migration extracts existing delivery fields to receiver rows
- Notifier and dispatcher remove all config fallbacks
- Frontend targets page shows receivers list per target with
  add/remove/toggle/test per receiver
- Single-receiver test endpoint: POST /targets/{id}/receivers/{id}/test

Code quality:
- Extract AuthLayout.svelte from login/setup (150 lines CSS dedup)
- Split telegram-bots page (754→51 lines + 3 tab components)
- Split notification-trackers page (547→432 lines + 4 components)
- Deduplicate _send_reply into shared handler.send_reply()
- Add locale column to template models, replace name-based detection
- Fix delete_notification_tracker dead protection check
- Fix check_telegram_bot query (filter by type, remove bogus OR)
- Add graceful scheduler shutdown in lifespan
- Consistent /bots?tab=telegram URLs across all nav links

i18n:
- Error page, chat actions, target types, provider types internationalized
- All new receiver UI strings in EN + RU
2026-03-22 02:19:31 +03:00
alexei.dolgolyov ddcbfdaa0b feat: remove hardcoded command templates, enforce template system exclusively
- Remove ALL hardcoded EN/RU fallback strings from handler.py — every
  command response now renders through CommandTemplateSlot templates
- _render_cmd_template now returns error placeholder instead of None
  when template is missing, ensuring no silent failures
- Fix register_commands_with_telegram tuple unpacking bug (was ignoring
  cmd_template_slots from _resolve_command_context)
- Auto-assign system default template (matching locale) on command
  config creation when none specified
- Add command_template_config_id to CommandConfigCreate model
- Remove "no template" option from frontend dropdown — template is
  now required for command configs
- Auto-select first matching template when creating new command config
- Fix || vs ?? for command_template_config_id, default_count, and
  rate_limits in frontend edit function (0 was treated as falsy)
2026-03-21 22:53:07 +03:00
alexei.dolgolyov 3e3a6f0777 feat: Discord/Slack/ntfy/Matrix targets, command templates, delete protection, email/matrix bots
- Discord, Slack, ntfy, Matrix notification target types with clients and dispatch
- MatrixBot model + API + frontend in Bots tab
- Command template system fully wired into all handler commands
- Default command templates seeded (EN/RU, 14 slots each)
- Command template editor with variables reference including child fields
- Delete protection on all 10 entity types (409 with consumer details)
- Provider type selector on template config forms
- Target type selector as dropdown with all 7 types
- Response template selector on command config form
- CLAUDE.md: mandatory server restart rule, child properties rule
2026-03-21 20:36:12 +03:00
alexei.dolgolyov 846d480d38 feat: provider-strict configs, slot-based templates, broadcast targets, email bots, command templates
Major architectural improvements:
- Provider-type enforcement: configs validated against provider type at assignment
- TemplateConfig migrated to slot-based pattern (TemplateSlot child table)
- Broadcast targets: TargetReceiver child table for multi-receiver dispatch
- EmailBot: first-class email sender entity with SMTP config, test connection
- CommandTemplateConfig: generic slot-based command response templates
- Provider capability registry: dynamic slot/event/command definitions per provider
- CommandTracker play/pause button matches NotificationTracker style
2026-03-21 16:33:24 +03:00
alexei.dolgolyov 1d445f3980 feat: entity relationship refactor — notification trackers, command system, chat actions
Rework entity schema: rename Tracker→NotificationTracker, add CommandConfig/
CommandTracker/CommandTrackerListener entities for decoupled command handling.
Commands now resolve through CommandTracker→CommandConfig instead of
TelegramBot.commands_config. Smart ref-counted bot polling based on active
listeners. Add chat_action to telegram targets. Full frontend CRUD pages
for command configs and command trackers. Idempotent SQLite migrations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 01:27:20 +03:00
alexei.dolgolyov 0dcca2fbe6 chore: remove accidentally committed __pycache__
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 23:11:53 +03:00
alexei.dolgolyov 03ec9b3c86 feat: telegram commands, app settings, bot polling, webhook handling, UI improvements
Adds telegram bot command system with 13 commands (search, latest, random, etc.),
webhook/polling handlers, rate limiting, app settings page, and various UI/UX
improvements across all entity pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 23:11:42 +03:00