Add block list, live panel state, and admin-override audit logging - #14
Merged
Conversation
- Block list: /yap block, /yap unblock, and a panel Block button. A block applies a persistent per-member deny overwrite (survives leaving, works regardless of lock/hide state) and disconnects the member if present. Block and Permit are mutually exclusive per member -- applying one clears the other. Blocked members now also show in /yap room, mirroring the existing Permitted list. - Live panel state: the persistent room panel embed now shows live locked/hidden state and the current permit list, not just the owner. refresh_panel_message re-derives owner and state from the channel itself rather than requiring callers to pass them, so it's now wired into lock/unlock/hide/unhide/permit/unpermit (previously only transfer/claim refreshed it). The reconcile-time panel backfill for pre-migration rooms now also reflects actual state instead of posting with default values. - Admin-override audit logging: every admin-override room action (a non-owner Manage Channels admin acting on someone else's room) is now logged to the console, and optionally to a configurable channel via the new /yap modlog command, shown in /yap config. - Deduped has_manage_channels: services/ownership.py now imports the canonical implementation from services/permissions.py instead of keeping an identical copy.
Not project content -- excluding it the same way .vscode/ already is.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 69511d38b7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ries - Departure cleanup (cleanup_temp_channel) was calling revoke_member_overwrites for a blocked member disconnected by apply_block, immediately clearing the deny overwrite that was just applied -- the block database record stayed but the actual Discord permission was wiped, letting the member see/rejoin right away. Blocked IDs are now exempted from that revocation, same as owner/permitted IDs. - Admin-override logging moved from authorization time to actual execution time. Panel actions that open a modal or select (Rename, Limit, Transfer, Kick, Permit, Block) authorize twice per logical action -- once opening the UI, again on submit -- so logging inside _authorize_channel produced two log entries per completed action, plus phantom entries when an admin cancelled or picked an invalid target. log_admin_action is now called explicitly at the end of each apply_* function's success path instead. apply_transfer captures the pre-transfer owner record before mutating, since a post-mutation re-fetch would compare the actor against the *new* owner and wrongly flag an ordinary owner-initiated transfer as an admin override.
4 tasks
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
Third batch from the ongoing audit — remaining QoL items plus operational visibility, coordinated alongside the independent test/CI suite in #13 (disjoint files, no overlap).
Block list — the counterpart to the existing Permit list.
/yap block user:,/yap unblock user:, and a new panel Block button. A block applies a persistent per-member deny overwrite (view_channel/connectbothFalse) that survives the member leaving and holds regardless of the room's lock/hide state — Discord resolves per-member overwrites ahead of role/@everyoneoverwrites, so no bot-side join handling is needed for enforcement. Blocking disconnects the member if currently present. Block and Permit are mutually exclusive per member — applying one clears the other, mirroring how Kick already clears a permit. Blocked members now also appear in/yap room, alongside the existing Permitted list.Live panel state — the persistent room panel embed previously only reflected the owner (and only after PR Fix room permission bypass and stale panel embed after ownership change #12's fix for that). It now shows live locked/hidden state and the current permit list too.
refresh_panel_messagewas redesigned to re-derive the owner and state from the channel/DB itself rather than requiring every caller to pass them in — this let it get wired intoapply_lock/apply_unlock/apply_hide/apply_unhide/apply_permit/apply_unpermit(previously onlyapply_transfer/apply_claimrefreshed it) with no extra bookkeeping at each call site. The reconcile-time backfill for rooms that predatepanel_message_id(added in Fix room permission bypass and stale panel embed after ownership change #12) now also posts with the room's actual current state instead of always defaulting to unlocked/visible/no-permits.Admin-override audit logging — every admin-override room action (a non-owner Manage Channels admin acting on someone else's room, now gated on presence since Fix room permission bypass and stale panel embed after ownership change #12) is logged to the console, and optionally posted to a configurable channel via the new
/yap modlogcommand (shown in/yap config). This gives server owners visibility into moderation actions taken on rooms they don't own.Deduped
has_manage_channels—services/ownership.pypreviously carried a byte-for-byte copy ofservices/permissions.py::require_manage_channels. It now imports the canonical implementation under its existing local name, so no call sites changed.Changes
schema.sql,storage.py: newtemp_channel_blockstable (mirrorstemp_channel_permits, purged with the room) andguild_configs.mod_log_channel_idcolumn, both via the established guarded-migration pattern; newadd_block/remove_block/list_blocks/set_mod_log_channel.services/permissions.py: newdeny_member_access(Block's counterpart to the existinggrant_member_access).services/room_actions.py:apply_block/apply_unblock,blocked_members;apply_permit/apply_blockcross-clear each other;build_room_info_embedgains ablockedfield;apply_unlock/apply_unhidegain abotparameter (needed for the refresh call).services/panel.py:build_panel_embed/send_room_panel/refresh_panel_messagetake/derive lock/hide/permit state; new Block button + select (row 2); lock/unlock/hide/unhide/permit/unpermit now trigger a refresh.services/ownership.py:_log_admin_override, called from_authorize_channelright after the presence check passes; dedupe ofhas_manage_channels.services/temp_channels.py: reconcile backfill posts real current state.commands/setup.py,commands/owner_controls.py:/yap block,/yap unblock,/yap modlog; help/config text updated.Test plan
py_compileclean; circular-import hazard re-verified in both orders after the newservices.panel↔services.room_actionssurface area grewyap block/yap unblock/yap modlogpresent (22 commands total); panel is persistent with 11 buttons across 3 rowsapply_block: overwrite applied, stored, clears any existing permit, disconnects a present target, self-block rejected;apply_unblockclears the record;apply_permitclears any existing block (mutual exclusivity both directions)mod_log_channel_idsetter round-trip, including auto-creating the guild config row when it doesn't exist yetpanel_message_id,mod_log_channel_id, and the blocks table all at once — all three added, existing rows preserved, immediately usable; double-init idempotentrefresh_panel_messagereflects live locked/hidden state and the permit list; no-ops cleanly if the current owner has left the guild_authorize_channeladmin-override path: posts to the configured mod-log channel with the correct content; no-ops cleanly when unconfigured; never fires for an owner's own actionapply_lock/apply_unlock/apply_hide/apply_unhideeach callrefresh_panel_message(bot, channel)exactly onceGenerated by Claude Code