feat(bot): drive episode upload dialog via dialog-engine#29
Merged
Conversation
Replace the aiogram UploadFile StatesGroup with the dialog-engine library. The three-step flow (episode type, MP3, metadata template) is now described as an engine schema; step order, validation and answer storage live in the library, while the handlers keep doing the Telegram-side work. Progress is stored as a serialised DialogSession in FSMContext, so a running upload still survives restarts. Routing moves from StateFilter to OnStep / InDialog filters backed by the session. dialog-engine is pulled from GitHub until it ships on PyPI.
Poetry's bundled dulwich client cannot install the dialog-engine git
dependency ("No module named dulwich.worktree"). Switch the bot env install
to the system git binary in CI and the Docker build, and add git to the
Docker base image.
Recent Poetry uses dulwich's new WorkTree API (module dulwich.worktree, dulwich>=0.24) for git dependencies; an older dulwich on the runner/base image breaks installing dialog-engine. Pin it when installing Poetry in CI and the Docker build. Replaces the earlier system-git-client attempt, which did not take effect.
The dev group pulls poetry-plugin-up, which drags in an old poetry and
dulwich<0.22. With virtualenvs.create false that dulwich overwrites Poetry's
own client during install and breaks fetching the dialog-engine git
dependency ("No module named dulwich.worktree"). Move pytest-cov to the
testing group and install only that group in CI. Reverts the earlier
dulwich/system-git-client workarounds; the Docker build only installs the
main group, so it was never affected.
--with adds optional groups but non-optional groups (dev) still install by default, so the dev group's poetry-plugin-up kept dragging in dulwich<0.22 and breaking the dialog-engine git install. --only restricts the install to exactly main + testing.
The main protection ruleset requires a status check named 'test', but the single-value matrix made the job report as 'test (3.12)', leaving the requirement permanently unmet. Drop the matrix so the context matches.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Migrates the episode upload conversation from the hand-rolled aiogram
UploadFileStatesGroupto the dialog-enginelibrary.
The three-step flow is unchanged for the user — pick episode type → send the
MP3 → send the metadata template — but step order, validation and answer
storage now live in the library instead of being spread across handler code.
The handlers keep doing all the Telegram-side work (download, tagging, upload).
How
forms/upload_file.pynow defines a dialog-engine schema (the three steps,the episode-type choice, the file/text validators) instead of a StatesGroup.
utils/dialog.pyis a thin adapter that stores theDialogSessionasserialised data inside
FSMContext, so an in-progress upload still survives arestart (same as the old FSM state did, Redis-backed in prod).
filters/dialog_filters.pyaddsOnStep(...)/InDialog()filters thatroute messages by the session's current step, replacing
StateFilter.engine; the per-step side effects are untouched.
type_episodewas only read insidepodcast_handleritself (the FTP/WordPress/Boosty handlers get it from the sidecar metadata), so moving where it's stored
is safe.
Dependency
dialog-engineis pulled from GitHub for now; it'll switch to a PyPI versionconstraint once it's published. Lockfile updated accordingly.
Tests
podcast_handlertests against the session model.tests/unit/forms), the FSM adapter(
tests/unit/utils/dialog) and the routing filters (tests/unit/filters).Holding for a prod smoke test before merge.