Repository navigation
feat: add self-timeout - #49
Conversation
| GuildID := e.GuildID() | ||
| if GuildID == nil { | ||
| // NOTE: should have been caught earlier | ||
| embed := selfTimeoutCommandEmbed("Command unavalible!", "This command can only be used in servers!", true) |
| return updateEmbed(e, embed) | ||
| } | ||
|
|
||
| embed := selfTimeoutCommandEmbed("Sucessfully timed out", "See you later!", false) |
| } | ||
|
|
||
| if e.GuildID() == nil { | ||
| embed = selfTimeoutCommandEmbed("Command unavalible!", "This command can only be used in servers!", true) |
|
|
||
| // confirmation message | ||
| embed = selfTimeoutCommandEmbed("Confirm timeout", fmt.Sprintf( | ||
| "You are about to time yourself out, **this action is irreversal**, "+ |
There was a problem hiding this comment.
shouldve been irreversible, not irreversal
There was a problem hiding this comment.
shouldve been irreversible, not irreversal
Fixed typos you noticed (x2)
Fixed the typos you noticed. |
79eee51 to
6cd7de7
Compare
dearfenane
left a comment
There was a problem hiding this comment.
also it seems like github didnt recognize the fixing thing, maybe do it "fixes #26" at the bottom of the pr
|
also i have just noticed you need to run |
|
Amended commit (again) to fix issues noted. |
dearfenane
left a comment
There was a problem hiding this comment.
change this and ill approve your pr (though you will need your pr reviewed by vuks as well)
|
Converting to draft: realized it should be in |
Vuks69
left a comment
There was a problem hiding this comment.
Overall pretty well executed, just some inconsistencies.
| if err != nil { | ||
| embed := selfTimeoutCommandEmbed("Invalid permissions!", fmt.Sprintf("The bot lacks permission to timeout <@%s>", e.Member().User.ID), true) | ||
| return updateEmbed(e, embed) | ||
| } |
There was a problem hiding this comment.
The error is discarded and misdiagnosed. Every UpdateMember failure renders as "Invalid permissions!". A 404 unknown-member, a 429, a 5xx, or a network blip all tell the user to check their permissions.
And because you return updateEmbed's error rather than the REST error, disgo's default error handler logs only the edit failure; the timeout failure itself leaves no trace. Use rest.IsJSONErrorCode(err, rest.JSONErrorCodeMissingAccess) / errors.As for the 403 branch and slog.Error the rest, the way tldr does.
|
|
||
| // buttons for embed | ||
| var buttons = [2]discord.ButtonComponent{ | ||
| discord.NewDangerButton("I understand", fmt.Sprintf("/"+selfTimeoutCommand+"/Confirm/%s", duration.String())), |
There was a problem hiding this comment.
AI raised a potential problem with no expiry, so someone could click the button a few days later and still get timed out. Not sure how much of a problem this really would be. Can be fixed by including an expiry timestamp in the ID and checking it on click.
There was a problem hiding this comment.
Not sure how much of a problem this really would be
I don't think it is that big of an issue. The message is ephemeral so it will go away after some time
| duration, err := time.ParseDuration(durationString) | ||
| if err != nil { | ||
| embed = selfTimeoutCommandEmbed("Invalid duration", fmt.Sprintf("'%s' is not a valid duration!", durationString), true) | ||
| return sendEmbed(e, embed, nil) | ||
| } | ||
|
|
||
| // Ensure ms/ns times are not accepted | ||
| duration = duration.Round(time.Second) | ||
|
|
||
| // ensure duration is not too long or too short | ||
| // NOTE: "duration.String()" is more verbose as it includes values not specified by the user (as '0') | ||
| if duration < 10*time.Second { | ||
| embed = selfTimeoutCommandEmbed("Invalid duration", fmt.Sprintf("`%s` is too short", durationString), true) | ||
| return sendEmbed(e, embed, nil) | ||
| } else if duration > 3*24*time.Hour { | ||
| embed = selfTimeoutCommandEmbed("Invalid duration", fmt.Sprintf("`%s` is longer than 3 days!", durationString), true) | ||
| return sendEmbed(e, embed, nil) | ||
| } |
There was a problem hiding this comment.
I'd separate this into a validateDuration function, and use that function as well in handleSelfTimeoutCommandConfirm instead of L68-74 there.
| if e.GuildID() == nil { | ||
| embed = selfTimeoutCommandEmbed("Command unavailable!", "This command can only be used in servers!", true) | ||
| return sendEmbed(e, embed, nil) | ||
| } |
There was a problem hiding this comment.
This could be a separate requiresGuild function somewhere in Core, many commands will need that check as well.
| // Ensure ms/ns times are not accepted | ||
| duration = duration.Round(time.Second) |
There was a problem hiding this comment.
The comment says "Ensure ms/ns times are not accepted", but nothing rejects them; Round(time.Second) silently truncates. The confirm prompt echoes the raw 1h0m0.4s while the button carries 1h0m0s. Sub-second input is rejected only incidentally, by the 10s floor.
validateDuration could return the normalized/truncated duration so we don't have that discrepancy too. durationString needs to be overwritten here.
| WithColor(color) | ||
| } | ||
|
|
||
| // helper to send discord message with the image |
There was a problem hiding this comment.
Not seeing an image anywhere (copypaste?), also doc comments should be full sentences (uppercase start, end with dot).
| return err | ||
| } | ||
|
|
||
| // same as sendEmbed but for button handlers |
There was a problem hiding this comment.
describes the wrong difference, the real one is that it edits a message and force-clears components
| func selfTimeoutCommandEmbed(title string, desc string, isError bool) discord.Embed { | ||
| var color int | ||
| if isError { | ||
| color = 0xff0000 // red | ||
| } else { | ||
| color = 0xffc34d // yellow-ish orange | ||
| } | ||
|
|
||
| return discord.NewEmbed(). | ||
| WithTitle(title). | ||
| WithDescription(desc). | ||
| WithColor(color) | ||
| } |
There was a problem hiding this comment.
I think separating this out into selfTimeoutEmbed/selfTimeoutErrorEmbed like tldr would be more readable on invocations.
|
|
||
| durationString, durationProvided := interaction.OptString("duration") | ||
| if !durationProvided { | ||
| embed = selfTimeoutCommandEmbed("Unset duration", "duration was not set!", true) |
There was a problem hiding this comment.
error message typo (capitalization)
| func handleSelfTimeoutCommandGoback(data discord.ButtonInteractionData, e *handler.ComponentEvent) error { | ||
| // overwrite the original message | ||
| embed := selfTimeoutCommandEmbed("Timeout Cancelled", "See you around!", false) | ||
| return updateEmbed(e, embed) | ||
| } | ||
|
|
||
| func handleSelfTimeoutCommandConfirm(data discord.ButtonInteractionData, e *handler.ComponentEvent) error { |
There was a problem hiding this comment.
$ pre-commit run --all
(snip...)
custom-gcl (golangci-lint + NilAway).....................................Failed
- hook id: custom-gcl
- exit code: 1
internal/moderation/self_timeout.go:61:37: unused-parameter: parameter 'data' seems to be unused, consider removing or renaming it as _ (revive)
func handleSelfTimeoutCommandGoback(data discord.ButtonInteractionData, e *handler.ComponentEvent) error {
^
internal/moderation/self_timeout.go:67:38: unused-parameter: parameter 'data' seems to be unused, consider removing or renaming it as _ (revive)
func handleSelfTimeoutCommandConfirm(data discord.ButtonInteractionData, e *handler.ComponentEvent) error {
^
2 issues:
* revive: 2| func handleSelfTimeoutCommandGoback(data discord.ButtonInteractionData, e *handler.ComponentEvent) error { | |
| // overwrite the original message | |
| embed := selfTimeoutCommandEmbed("Timeout Cancelled", "See you around!", false) | |
| return updateEmbed(e, embed) | |
| } | |
| func handleSelfTimeoutCommandConfirm(data discord.ButtonInteractionData, e *handler.ComponentEvent) error { | |
| func handleSelfTimeoutCommandGoback(_ discord.ButtonInteractionData, e *handler.ComponentEvent) error { | |
| // overwrite the original message | |
| embed := selfTimeoutCommandEmbed("Timeout Cancelled", "See you around!", false) | |
| return updateEmbed(e, embed) | |
| } | |
| func handleSelfTimeoutCommandConfirm(_ discord.ButtonInteractionData, e *handler.ComponentEvent) error { |
I amended my PR, should have addressed your issues (hopefully I didn't mess up anything when rebasing) |
4e54e2d to
045c314
Compare
Fixes Neon-Genesis-Linux#26 AI Usage disclosure: Stack overflow was down while I was working on part of this, so I used it to **ask** how to check if the duration is between a specific window and how to format a string. I just used chatgpt. AI Usage disclosure (Vuks edition): Vuks used opencode's big pickle model inorder to fix some issues with this commit (all the long comments are from the AI) Assisted-by: chatgpt Assisted-by: opencode's big pickle model Co-authored-by: dearfenane <302284256+dearfenane@users.noreply.github.com> Co-authored-by: Vuks69 <51289041+Vuks69@users.noreply.github.com> Signed-off-by: Uniolo1 <89284448+Uniolo1@users.noreply.github.com>
This PR adds a self-timeout feature, fixing #26. Thanks to @dearfenane for helping me with this!
AI Usage disclosure
Stack overflow was down while I was working on part of this, so I used it to ask how to check if the duration is between a specific window and how to format a string. I just used ChatGPT.
Tests and stuff
CONTRIBUTING.mdsays to run a bunch of commands and to copy the output, so here it is!FYI:
CONTRIBUTING.mdsays toRead DOCUMENTATION.md first, butDOCUMENTATION.mddoes not seem to existfixes #26