feat: move dynamic Discord roles from env vars to database#179
Open
feat: move dynamic Discord roles from env vars to database#179
Conversation
Introduces the DynamicRole SQLAlchemy model with RoleCategory enum to store dynamic Discord roles (ranks, certs, seasons, subscriptions, creators, positions, joinable) in the database instead of requiring env vars. Includes cert_full_name and cert_integer_id columns for academy certs to eliminate hardcoded platform mappings.
…back In-memory cache loaded from DB with dual-read fallback to env vars during transition. Provides typed lookups (cert by ID, by full name, by abbreviation), cross-category search (get_post_or_rank), group lookups, joinable role queries, and CRUD operations. Handles CBBH legacy alias and explicit search priority for cross-category lookups.
…dition Load RoleManager synchronously in __main__.py before starting the webhook server or Discord bot, ensuring roles are available before any webhook can arrive. Add role_manager attribute to Bot and refresh cache on Discord reconnects via on_ready() with error handling.
Make dynamic role fields Optional in Roles class (dual-read fallback). Remove AcademyCertificates class, roles_to_join, dynamic role_groups, and helper methods from Global (moved to RoleManager). Update all consumers: verification.py (thread role_manager, replace hardcoded cert mapping), mp.py, academy.py, verify.py (add None guard), user.py (autocomplete for /join and /leave instead of static choices).
Slash command group with add/remove/update/list/reload subcommands. Write operations restricted to ALL_ADMINS, list also available to ALL_MODS. Auto-reloads RoleManager cache after mutations.
One-time migration tool that reads ROLE_* env vars and inserts them as DynamicRole rows with correct categories, display names, cert metadata, and joinable role descriptions.
Add MockRoleManager to test helpers, update MockBot with role_manager attribute. Rewrite webhook handler tests (mp, academy) to set up role_manager on bot instead of patching settings. Update verification tests to use test role IDs via MockRoleManager. Update config tests for new Optional fields and removed role_groups. Fix pre-existing role_data KeyError for py-cord compatibility.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #179 +/- ##
==========================================
+ Coverage 62.10% 64.76% +2.66%
==========================================
Files 50 53 +3
Lines 2953 3057 +104
==========================================
+ Hits 1834 1980 +146
+ Misses 1119 1077 -42 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
- Add tests for UserCog: autocomplete, join/leave with role_manager - Add tests for VerifyCog: cert_role not configured, empty certid, bad prefix - Create test_role_admin.py with full coverage for add/remove/update/list/reload
Change from /role-admin {add|remove|update|list|reload} to
/admin role {add|remove|update|list|reload} to allow future admin
subcommands like /admin config, /admin user, etc.
Create src/cmds/core/admin.py to define the top-level /admin command group. RoleAdminCog now imports from admin.py and adds the "role" subgroup via create_subgroup(). This allows other cogs to easily add their own /admin subcommands by importing the admin group.
Member
|
Looks good to me, but I think we are missing the alembic migration for DynamicRole? |
0xRy4n
reviewed
Apr 3, 2026
…d script - Remove version attribute from docker-compose.yml (obsolete in Compose spec) - Change seed script to use MariaDB upsert (INSERT ... ON DUPLICATE KEY UPDATE) so it can safely be re-run without errors on the unique constraint
- Add migration to align htb_discord_link columns with models - Add migration to create dynamic_role table for DB-backed roles
- Remove deprecated 'version' key from docker-compose.yml - Replace healthcheck.sh with explicit mariadb-admin ping - Increase start_period to 30s for slower startup
0xRy4n
approved these changes
Apr 4, 2026
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.
Summary
DynamicRoletable with in-memory cache/admin roleCRUD commands so bot admins can manage roles at runtime without redeployment/admin role addcommandMotivation
PR #177 added
ACADEMY_CWPEas a required env var but it was forgotten in production config, crashing the bot on deploy. This makes the bot resilient to missing dynamic roles (graceful degradation) and eliminates the need for code changes when adding new roles.Key Design Decisions
__main__.pybefore either the webhook server or Discord bot startsOptional[int] = Nonein the Roles class. RoleManager tries DB first, falls back to env vars if set. Safe to deploy with empty DB table.cert_full_nameandcert_integer_idcolumns on academy_cert rows replace the hardcodedAcademyCertificatesclass andprocess_certification()mappingchoices=with dynamic autocomplete from DB/admingroup defined inadmin.py, subgroups added viaadmin.create_subgroup()New Commands
/admin role add/admin role remove/admin role update/admin role list/admin role reloadDeployment Steps
dynamic_roletableENV_PATH=/path/to/.env python -m scripts.seed_dynamic_rolesto populate DB from existing env varsTest plan
/admin role add,/admin role list,/admin role removein Discord/joinautocomplete works/verifycertificationwith a valid cert