Completes TODO #3. Submissions are gated behind ACCEPT_SUBMISSIONS,
which defaults to off: is_allowed() treats everyone as allowed when
ALLOWED_USERS is empty, so opening submissions implicitly would have
accepted media from anyone who found the bot.
- Schema v3 adds status, reviewed_by and reviewed_at. Existing rows
default to approved, so upgrading changes nothing for a running bot.
- Search, /list and counts only return approved items; callers that
need everything pass status=None.
- /review shows the oldest pending item with approve, reject, fix
keywords and stop. No cursor is stored anywhere: each action just
asks for the next pending item, which is what lets a moderator stop
and resume later, and lets several moderators share one queue.
- set_status only updates rows still pending, so if two moderators open
the same item the first decision wins and the second is told so.
- A failed send no longer wedges the queue; the item's details are
shown anyway so it can still be rejected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Completes TODO #6. The bot accepted photo, animation, video, voice and
sticker; music files, documents and round videos were silently dropped.
- Replace the five near-identical media handlers with one dispatch table.
Animations are matched before documents because Telegram populates
both fields for a GIF, so the old ordering would have filed every GIF
as a document once document support existed.
- Store video notes as "video". Telegram has no cached inline result for
video notes, so this is what keeps round videos searchable; it costs
the round presentation on playback.
- Build inline results from a table keyed by media_type, and cover audio
and document. A test asserts every storable type has a builder, so a
new media type cannot be added without a way to return it.
- Reuse one MEDIA_FILTER for both the idle and mid-keyword handlers;
the second list had already drifted from the first.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
VERSION had been left at 1.0.0 while the registry already carried 1.0.1, so
push.sh (which defaults to the VERSION file) would have rebuilt an existing
tag. This realigns the file with what is actually published.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Split docker-compose into build (docker-compose.build.yaml) and deploy (docker-compose.yaml pulls from registry)
- Add push.sh for building and pushing versioned images to git.goyban.com/goyban/bot_meme
- Add ADMIN_USERS env var; admins can add/edit/delete, users can search
- Add /edit command with inline keyboard to update meme keywords
- Add sticker support (save and serve via inline)
- Switch /delete to use numeric row ID instead of file_unique_id
- Search is now global (shared pool) instead of per-user
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>