Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto moderation #1201

Merged
merged 6 commits into from Jul 3, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions endpoints.go
Expand Up @@ -68,6 +68,9 @@ var (
EndpointUserConnections = func(uID string) string { return EndpointUsers + uID + "/connections" }

EndpointGuild = func(gID string) string { return EndpointGuilds + gID }
EndpointGuildAutoModeration = func(gID string) string { return EndpointGuild(gID) + "/auto-moderation" }
EndpointGuildAutoModerationRules = func(gID string) string { return EndpointGuildAutoModeration(gID) + "/rules" }
EndpointGuildAutoModerationRule = func(gID, rID string) string { return EndpointGuildAutoModerationRules(gID) + "/" + rID }
EndpointGuildThreads = func(gID string) string { return EndpointGuild(gID) + "/threads" }
EndpointGuildActiveThreads = func(gID string) string { return EndpointGuildThreads(gID) + "/active" }
EndpointGuildPreview = func(gID string) string { return EndpointGuilds + gID + "/preview" }
Expand Down
96 changes: 96 additions & 0 deletions eventhandlers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions events.go
Expand Up @@ -406,3 +406,33 @@ type InviteDelete struct {
type ApplicationCommandPermissionsUpdate struct {
*GuildApplicationCommandPermissions
}

// AutoModerationRuleCreate is the data for an AutoModerationRuleCreate event.
type AutoModerationRuleCreate struct {
*AutoModerationRule
}

// AutoModerationRuleUpdate is the data for an AutoModerationRuleUpdate event.
type AutoModerationRuleUpdate struct {
*AutoModerationRule
}

// AutoModerationRuleDelete is the data for an AutoModerationRuleDelete event.
type AutoModerationRuleDelete struct {
*AutoModerationRule
}

// AutoModerationActionExecution is the data for an AutoModerationActionExecution event.
type AutoModerationActionExecution struct {
GuildID string `json:"guild_id"`
Action AutoModerationAction `json:"action"`
RuleID string `json:"rule_id"`
RuleTriggerType AutoModerationRuleTriggerType `json:"rule_trigger_type"`
UserID string `json:"user_id"`
ChannelID string `json:"channel_id"`
MessageID string `json:"message_id"`
AlertSystemMessageID string `json:"alert_system_message_id"`
Content string `json:"content"`
MatchedKeyword string `json:"matched_keyword"`
MatchedContent string `json:"matched_content"`
}
117 changes: 117 additions & 0 deletions examples/auto_moderation/main.go
@@ -0,0 +1,117 @@
package main

import (
"flag"
"fmt"
"log"
"os"
"os/signal"
"sync"

"github.com/bwmarrin/discordgo"
)

// Command line flags
var (
BotToken = flag.String("token", "", "Bot authorization token")
GuildID = flag.String("guild", "", "ID of the testing guild")
ChannelID = flag.String("channel", "", "ID of the testing channel")
)

func init() { flag.Parse() }

func main() {
session, _ := discordgo.New("Bot " + *BotToken)
session.Identify.Intents |= discordgo.IntentAutoModerationExecution
session.Identify.Intents |= discordgo.IntentMessageContent

enabled := true
rule, err := session.AutoModerationRuleCreate(*GuildID, &discordgo.AutoModerationRule{
Name: "Auto Moderation example",
EventType: discordgo.AutoModerationEventMessageSend,
TriggerType: discordgo.AutoModerationEventTriggerKeyword,
TriggerMetadata: &discordgo.AutoModerationTriggerMetadata{
KeywordFilter: []string{"*cat*"},
},

Enabled: &enabled,
Actions: []discordgo.AutoModerationAction{
{Type: discordgo.AutoModerationRuleActionBlockMessage},
},
})
if err != nil {
panic(err)
}

fmt.Println("Successfully created the rule")
defer session.AutoModerationRuleDelete(*GuildID, rule.ID)

session.AddHandlerOnce(func(s *discordgo.Session, e *discordgo.AutoModerationActionExecution) {
_, err = session.AutoModerationRuleEdit(*GuildID, rule.ID, &discordgo.AutoModerationRule{
TriggerMetadata: &discordgo.AutoModerationTriggerMetadata{
KeywordFilter: []string{"cat"},
},
Actions: []discordgo.AutoModerationAction{
{Type: discordgo.AutoModerationRuleActionTimeout, Metadata: &discordgo.AutoModerationActionMetadata{Duration: 60}},
{Type: discordgo.AutoModerationRuleActionSendAlertMessage, Metadata: &discordgo.AutoModerationActionMetadata{
ChannelID: e.ChannelID,
}},
},
})
if err != nil {
session.AutoModerationRuleDelete(*GuildID, rule.ID)
panic(err)
}

s.ChannelMessageSend(e.ChannelID, "Congratulations! You have just triggered an auto moderation rule.\n"+
"The current trigger can match anywhere in the word, so even if you write the trigger word as a part of another word, it will still match.\n"+
"The rule has now been changed, now the trigger matches only in the full words.\n"+
"Additionally, when you send a message, an alert will be sent to this channel and you will be **timed out** for a minute.\n")

var counter int
var counterMutex sync.Mutex
session.AddHandler(func(s *discordgo.Session, e *discordgo.AutoModerationActionExecution) {
action := "unknown"
switch e.Action.Type {
case discordgo.AutoModerationRuleActionBlockMessage:
action = "block message"
case discordgo.AutoModerationRuleActionSendAlertMessage:
action = "send alert message into <#" + e.Action.Metadata.ChannelID + ">"
case discordgo.AutoModerationRuleActionTimeout:
action = "timeout"
}

counterMutex.Lock()
counter++
if counter == 1 {
counterMutex.Unlock()
s.ChannelMessageSend(e.ChannelID, "Nothing has changed, right? "+
"Well, since separate gateway events are fired per each action (current is "+action+"), "+
"you'll see a second message about an action pop up soon")
} else if counter == 2 {
counterMutex.Unlock()
s.ChannelMessageSend(e.ChannelID, "Now the second ("+action+") action got executed.")
s.ChannelMessageSend(e.ChannelID, "And... you've made it! That's the end of the example.\n"+
"For more information about the automod and how to use it, "+
"you can visit the official Discord docs: https://discord.dev/resources/auto-moderation or ask in our server: https://discord.gg/6dzbuDpSWY",
)

session.Close()
session.AutoModerationRuleDelete(*GuildID, rule.ID)
os.Exit(0)
}
})
})

err = session.Open()
if err != nil {
log.Fatalf("Cannot open the session: %v", err)
}
defer session.Close()

stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt)
<-stop
log.Println("Graceful shutdown")

}
77 changes: 77 additions & 0 deletions restapi.go
Expand Up @@ -3111,3 +3111,80 @@ func (s *Session) GuildScheduledEventUsers(guildID, eventID string, limit int, w
err = unmarshal(body, &st)
return
}

// ----------------------------------------------------------------------
// Functions specific to auto moderation
// ----------------------------------------------------------------------

// AutoModerationRules returns a list of auto moderation rules.
// guildID : ID of the guild
func (s *Session) AutoModerationRules(guildID string) (st []*AutoModerationRule, err error) {
endpoint := EndpointGuildAutoModerationRules(guildID)

var body []byte
body, err = s.RequestWithBucketID("GET", endpoint, nil, endpoint)
if err != nil {
return
}

err = unmarshal(body, &st)
return
}

// AutoModerationRule returns an auto moderation rule.
// guildID : ID of the guild
// ruleID : ID of the auto moderation rule
func (s *Session) AutoModerationRule(guildID, ruleID string) (st *AutoModerationRule, err error) {
endpoint := EndpointGuildAutoModerationRule(guildID, ruleID)

var body []byte
body, err = s.RequestWithBucketID("GET", endpoint, nil, endpoint)
if err != nil {
return
}

err = unmarshal(body, &st)
return
}

// AutoModerationRuleCreate creates an auto moderation rule with the given data and returns it.
// guildID : ID of the guild
// rule : Rule data
func (s *Session) AutoModerationRuleCreate(guildID string, rule *AutoModerationRule) (st *AutoModerationRule, err error) {
endpoint := EndpointGuildAutoModerationRules(guildID)

var body []byte
body, err = s.RequestWithBucketID("POST", endpoint, rule, endpoint)
if err != nil {
return
}

err = unmarshal(body, &st)
return
}

// AutoModerationRuleEdit edits and returns the updated auto moderation rule.
// guildID : ID of the guild
// ruleID : ID of the auto moderation rule
// rule : New rule data
func (s *Session) AutoModerationRuleEdit(guildID, ruleID string, rule *AutoModerationRule) (st *AutoModerationRule, err error) {
endpoint := EndpointGuildAutoModerationRule(guildID, ruleID)

var body []byte
body, err = s.RequestWithBucketID("PATCH", endpoint, rule, endpoint)
if err != nil {
return
}

err = unmarshal(body, &st)
return
}

// AutoModerationRuleDelete deletes an auto moderation rule.
// guildID : ID of the guild
// ruleID : ID of the auto moderation rule
func (s *Session) AutoModerationRuleDelete(guildID, ruleID string) (err error) {
endpoint := EndpointGuildAutoModerationRule(guildID, ruleID)
_, err = s.RequestWithBucketID("DELETE", endpoint, nil, endpoint)
return
}