Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 26 additions & 9 deletions NHCogs/nhmisc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,9 @@ Gate 6 users remain visible but cannot be selected.
The action requires Manage Messages and uses a durable one-use source lock. A second
message cannot reserve the same member's next Gate while an earlier increment is still
pending. Successful users are publicly pinged beside a non-pinging mention of their
new Gate role. Manual Gate role changes are reverted; Gate progress must be changed
through the bot.
new Gate role. The completion message used for the increment is stored as the new Gate's
proof. Manual Gate role changes are reverted; Gate progress must be changed through the
bot.

## Gate Revoke

Expand All @@ -226,14 +227,16 @@ increment action.

```ini
Apps → Add Gate Proof
[p]achievement proof <message_link>
```

Use a historical completion message's Apps menu to attach it as proof for Gate records
that were imported without one. The action requires Manage Messages and opens an
ephemeral review for the message author and mentioned members. Each user defaults to
`Don't add proof` and can independently select one of their completed Gate ordinals that
still has no proof. Four users are shown per page, with no total candidate limit imposed
by the action.
Use a historical completion message's Apps menu or pass its link to the text command to
attach it as proof for Gate records that were imported without one. Both entry points
require Manage Messages and open the same review for the message author and mentioned
members. The text command is available only in private moderator channels. Each user
defaults to `Don't add proof` and can independently select one of their completed Gate
ordinals that still has no proof. Four users are shown per page, with no total candidate
limit imposed by the action.

Confirmation changes only the selected proof-message references. It does not increment
Gate progress or change any roles. The interactive picker only offers Gates without a
Expand All @@ -260,24 +263,37 @@ attach only missing proofs, or cancel. The entire multi-user operation is atomic
invalid target, missing Gate, duplicate user-and-ordinal pair, changed proof, or stale
source message prevents every write.

Content beginning with a number and one space is treated as an intended batch. If its
format or Gate assignments are invalid, the review shows the error and lets the moderator
open the same message as a normal Gate proof instead or cancel. The fallback never writes
without the normal review and confirmation.

## Achievements

```ini
[p]achievement
/achievements [user]
Apps → View achievements
Apps → Grant achievements
[p]achievement proof <message_link>
[p]achievement create <display name>
[p]achievement list
[p]achievement missingproofs
[p]achievement rename <key> <new display name>
[p]achievement delete <key>
[p]achievement role
[p]achievement role bind @Role
[p]achievement role unbind @Role
[p]achievement role replace @OldRole @NewRole
[p]achievement role list
[p]achievement revoke <users...>
```

`achievement` shows a compact overview of the profile, Apps, Gate proof, Gate
increment, Gate revoke, and text-command entry points. `achievement role` shows the
complete syntax and a short description for `bind`, `unbind`, `replace`, and `list`.
Listing the configured bindings remains an explicit `achievement role list` action.

`/achievements` and the user Apps action show the same member profile ephemerally, with
the same `Send publicly` button and published attribution. Both are available to every
server member.
Expand Down Expand Up @@ -305,7 +321,8 @@ stable keys required by these commands. Because keys are internal identifiers, `
`achievement missingproofs` reports current non-bot server members who have at least one
Gate without a proof link. It previews the first 20 affected members and attaches the full
result as CSV, or as a ZIP when needed. The command requires a complete member cache and
is unavailable in channels visible to `@everyone`.
is unavailable in channels visible to `@everyone`. Attach missing proofs with
`achievement proof <message_link>` or Apps → Add Gate Proof.

Gate increments, proof attachments and revokes, achievement grants and revokes,
achievement definition changes, and role binding changes are recorded in the configured
Expand Down
58 changes: 58 additions & 0 deletions NHCogs/nhmisc/achievement_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,64 @@ def _configure_controls(self) -> None:
self.review.disabled = not self.selected_assignments


class GateProofBatchFallbackView(discord.ui.View):
def __init__(
self,
cog: NHMisc,
source_message: discord.Message,
opener_id: int,
error_message: str,
) -> None:
super().__init__(timeout=300)
self.cog = cog
self.source_message = source_message
self.opener_id = opener_id
self.error_message = error_message
self.message: discord.Message | None = None

async def interaction_check(self, interaction: discord.Interaction) -> bool:
if interaction.user.id == self.opener_id:
return True
await interaction.response.send_message(
"Only the moderator who opened this review can control it",
ephemeral=True,
)
return False

async def on_timeout(self) -> None:
for child in self.children:
child.disabled = True
if self.message is not None:
try:
await self.message.edit(view=self)
except discord.HTTPException:
pass

@discord.ui.button(
label="Use normal Gate proof",
style=discord.ButtonStyle.primary,
)
async def use_normal(
self,
interaction: discord.Interaction,
_button: discord.ui.Button,
) -> None:
await self.cog._open_normal_gate_proof_fallback(interaction, self)

@discord.ui.button(label="Cancel", style=discord.ButtonStyle.danger)
async def cancel(
self,
interaction: discord.Interaction,
_button: discord.ui.Button,
) -> None:
self.stop()
await interaction.response.edit_message(
content="Gate proof attachment cancelled",
embed=None,
view=None,
)


class GateProofBatchView(discord.ui.View):
def __init__(
self,
Expand Down
4 changes: 1 addition & 3 deletions NHCogs/nhmisc/bot_proxy_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@
_get_channel_or_thread,
_moderator_mention,
)
from .discord_links import MESSAGE_LINK_PATTERN

MESSAGE_LINK_PATTERN = re.compile(
r"^https://(?:canary\.|ptb\.)?discord\.com/channels/(\d+)/(\d+)/(\d+)$"
)
CHANNEL_MENTION_PATTERN = re.compile(r"^<#(\d+)>$")
LOG_CONTENT_PREVIEW_LENGTH = 300
log = logging.getLogger(__name__)
Expand Down
5 changes: 5 additions & 0 deletions NHCogs/nhmisc/discord_links.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import re

MESSAGE_LINK_PATTERN = re.compile(
r"^https://(?:canary\.|ptb\.)?discord\.com/channels/(\d+)/(\d+)/(\d+)$"
)
Loading
Loading