Skip to content

Enhance Discord subscription filters and status rule formatting - #2

Merged
owens1127 merged 8 commits into
mainfrom
feature/discord-subscription-rule-filters
Apr 24, 2026
Merged

Enhance Discord subscription filters and status rule formatting#2
owens1127 merged 8 commits into
mainfrom
feature/discord-subscription-rule-filters

Conversation

@owens1127

Copy link
Copy Markdown
Contributor

Summary

  • add optional /subscribe raid filter choices sourced from RaidHub manifest sync data while keeping user-facing raid names
  • pass typed rule filters (fresh/completed/raid) through subscribe updates and unify subscription/unsubscribe command copy handling
  • standardize subscription status rule rendering so each player/clan line includes explicit rule tokens

Test plan

  • python3 -m unittest tests.test_manifest_commands tests.test_sync_commands
  • run full raidhub-discord test suite in environment with jwt dependency installed

Made with Cursor

This aligns slash-command raid selection with RaidHub manifest choices, sends typed rule filters to the API, and standardizes subscription status rule display per player/clan entry for clearer UX.

Made-with: Cursor
Copilot AI review requested due to automatic review settings April 24, 2026 02:57

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Enhances Discord slash-command subscriptions by adding optional raid filter choices sourced from the RaidHub manifest, passing rule filter options through subscribe operations, and standardizing how subscription status rules are rendered.

Changes:

  • Add manifest-sourced raid dropdown choices for /subscribe (player/clan) and thread them into command sync.
  • Consolidate unsubscribe UX into /unsubscribe subcommands (delete/player/clan) and centralize common message titles/copy.
  • Standardize subscription status rendering to include explicit rule tokens per player/clan and add a “Rule Filters” summary field.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_sync_commands.py Adds unit coverage for raid-choice extraction ordering/format.
tests/test_subscription_helpers.py Updates status embed expectations for new “Rule Filters” field and rule token formatting.
tests/test_manifest_commands.py Updates manifest expectations for new /subscribe options and unified /unsubscribe subcommands.
src/sync_commands.py Fetches RaidHub manifest to populate raid dropdown choices during Discord command sync.
src/manifest/schema.py Adds DTO support for Discord option choices serialization.
src/manifest/builders.py Adds raid filter options (with choices) to /subscribe and restructures /unsubscribe into subcommands.
src/manifest/init.py Plumbs optional raid choice data into manifest generation.
src/commands/unsubscribe.py Routes /unsubscribe by subcommand and unifies message copy; adds richer success embeds.
src/commands/subscription_messages.py Centralizes common subscription/unsubscribe message titles and shared descriptions.
src/commands/subscription_helpers.py Standardizes per-rule token rendering and adds “Rule Filters” summary to status embeds.
src/commands/subscription.py Switches to shared message titles for consistent UX.
src/commands/subscribe.py Accepts and forwards rule filters (fresh/completed/raid) and unifies success/error copy.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/commands/subscribe.py
Comment on lines 141 to +147
await patch_discord_followup_best_effort(
app_id,
token,
error_embed("Player Not Found", "Missing membership id for that player."),
error_embed(
PLAYER_NOT_FOUND_TITLE,
"Missing membership id for that player.",
),

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Missing membership id" branch here assumes resolved_id normalization always succeeds, but resolved_id = str(int(str(raw_mid).strip())) just above can raise ValueError before this check runs (e.g., if membershipId is non-numeric/empty). Consider switching to resolve_player_membership_id(...) (or the existing _norm_membership_id) so invalid IDs are handled as a normal control-flow case instead of an exception.

Copilot uses AI. Check for mistakes.
Comment thread src/commands/unsubscribe.py Outdated
Comment on lines +53 to +68
outcome = "completed"
try:
data = interaction.get("data") or {}
top_opts = data.get("options") or []
sub = ""
if top_opts and isinstance(top_opts[0], dict):
sub = str(top_opts[0].get("name") or "").strip().lower()
if not sub:
sub = "delete"

if sub == "player":
await run_unsubscribe_player_deferred(interaction, raidhub, settings)
return
if sub == "clan":
await run_unsubscribe_clan_deferred(interaction, raidhub, settings)
return

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

run_unsubscribe_deferred delegates to run_unsubscribe_player_deferred / run_unsubscribe_clan_deferred and then returns, but the finally block still records observe_deferred_completion(command="unsubscribe", ...). This will double-count metrics for /unsubscribe player|clan invocations (and may mark the wrapper as completed even if the delegated handler errors). Consider either (a) moving the dispatching logic outside the try/finally metrics block, (b) skipping wrapper metrics when delegating, or (c) recording a single metric with a subcommand dimension instead of recording both wrapper and sub-handler metrics.

Suggested change
outcome = "completed"
try:
data = interaction.get("data") or {}
top_opts = data.get("options") or []
sub = ""
if top_opts and isinstance(top_opts[0], dict):
sub = str(top_opts[0].get("name") or "").strip().lower()
if not sub:
sub = "delete"
if sub == "player":
await run_unsubscribe_player_deferred(interaction, raidhub, settings)
return
if sub == "clan":
await run_unsubscribe_clan_deferred(interaction, raidhub, settings)
return
data = interaction.get("data") or {}
top_opts = data.get("options") or []
sub = ""
if top_opts and isinstance(top_opts[0], dict):
sub = str(top_opts[0].get("name") or "").strip().lower()
if not sub:
sub = "delete"
if sub == "player":
await run_unsubscribe_player_deferred(interaction, raidhub, settings)
return
if sub == "clan":
await run_unsubscribe_clan_deferred(interaction, raidhub, settings)
return
outcome = "completed"
try:

Copilot uses AI. Check for mistakes.
Comment thread src/commands/unsubscribe.py Outdated
Comment on lines +174 to +176
raw_mid = prow.get("membershipId")
resolved_id = str(int(str(raw_mid).strip())) if raw_mid is not None else ""
if not resolved_id or not resolved_id.isdigit():

Copilot AI Apr 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved_id = str(int(str(raw_mid).strip())) can raise ValueError if membershipId is non-numeric/empty, which bypasses the intended "Missing membership id" handling and falls into the generic exception path. Consider using the existing normalization helper in subscribe_resolution (e.g., _norm_membership_id) or resolve_player_membership_id(...) to safely normalize/validate without throwing.

Copilot uses AI. Check for mistakes.
This avoids wrapper double-counting for delegated unsubscribe subcommands and prevents ValueError paths when membership ids are malformed in subscribe/unsubscribe player flows.

Made-with: Cursor
…ode.

This keeps `/unsubscribe` as the full remove-all command, restores dedicated `/unsubscribe-player` and `/unsubscribe-clan` commands, and limits `/subscription` to status-only behavior.

Made-with: Cursor
This switches `/unsubscribe` to all/player/clan subcommands and updates subscription status/unsubscribe wording to alert-focused language without internal webhook terminology.

Made-with: Cursor
Remove temporary raid option wiring from subscribe commands, keep display compatibility for raidIds, and leave explicit TODOs for a future multi-select-friendly design.

Made-with: Cursor
Drop unused raid choice construction now that raid filter inputs are deferred, while keeping status formatting compatible with raidIds payloads.

Made-with: Cursor
Reuse shared membership-id normalization for unsubscribe player flow so invalid or malformed IDs follow expected user-facing handling instead of exception fallback.

Made-with: Cursor
Rename the player search command to search and remove the instance command from the manifest to reduce command clutter.

Made-with: Cursor
@owens1127
owens1127 merged commit 75038f6 into main Apr 24, 2026
1 check passed
@owens1127
owens1127 deleted the feature/discord-subscription-rule-filters branch April 24, 2026 04:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants