Documentation
¶
Index ¶
- Constants
- Variables
- func AdvancedDeleteMessages(channelID int64, filterUser int64, regex string, maxAge time.Duration, ...) (int, error)
- func BanUser(client *redis.Client, config *Config, guildID, channelID int64, ...) error
- func BanUserWithDuration(client *redis.Client, config *Config, guildID, channelID int64, ...) error
- func CreateLogs(guildID, channelID int64, user *discordgo.User) string
- func CreateModlogEmbed(channelID int64, author *discordgo.User, action string, target *discordgo.User, ...) error
- func DeleteMessages(channelID int64, filterUser int64, deleteNum, fetchNum int) (int, error)
- func Dir(useLocal bool, name string) http.FileSystem
- func FS(useLocal bool) http.FileSystem
- func FSByte(useLocal bool, name string) ([]byte, error)
- func FSMustByte(useLocal bool, name string) []byte
- func FSMustString(useLocal bool, name string) string
- func FSString(useLocal bool, name string) (string, error)
- func HandleGuildBanAddRemove(evt *eventsystem.EventData)
- func HandleMemberJoin(evt *eventsystem.EventData)
- func HandleModeration(w http.ResponseWriter, r *http.Request) (web.TemplateData, error)
- func HandlePostModeration(w http.ResponseWriter, r *http.Request) (web.TemplateData, error)
- func KickUser(config *Config, guildID, channelID int64, author *discordgo.User, ...) error
- func ModBaseCmd(neededPerm, cmd int, inner dcmd.RunFunc) dcmd.RunFunc
- func MuteUnmuteUser(config *Config, client *redis.Client, mute bool, guildID, channelID int64, ...) error
- func RedisKeyBannedUser(guildID, userID int64) string
- func RedisKeyMutedUser(guildID, userID int64) string
- func RedisKeyUnbannedUser(guildID, userID int64) string
- func RegisterPlugin()
- func SafeArgString(data *dcmd.Data, arg int) string
- func WarnUser(config *Config, guildID, channelID int64, author *discordgo.User, ...) error
- type Config
- type ContextKey
- type Plugin
- type Punishment
- type WarningModel
Constants ¶
const ( ActionMuted = "Muted" ActionUnMuted = "Unmuted" ActionKicked = "Kicked" ActionBanned = "Banned" ActionUnbanned = "Unbanned" ActionWarned = "Warned" )
const ( ModCmdBan int = iota ModCmdKick ModCmdMute ModCmdUnMute ModCmdClean ModCmdReport ModCmdReason ModCmdWarn )
Variables ¶
var (
ErrFailedPerms = errors.New("Failed retrieving perms")
)
var (
ErrNoMuteRole = errors.New("No mute role")
)
var ModerationCommands = []*commands.YAGCommand{ &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "Ban", Description: "Bans a member, specify a duration with -d", RequiredArgs: 1, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "User", Type: dcmd.UserReqMention}, &dcmd.ArgDef{Name: "Reason", Type: dcmd.String}, }, ArgSwitches: []*dcmd.ArgDef{ &dcmd.ArgDef{Switch: "d", Default: time.Duration(0), Name: "Duration", Type: &commands.DurationArg{}}, }, RunFunc: ModBaseCmd(discordgo.PermissionBanMembers, ModCmdBan, func(parsed *dcmd.Data) (interface{}, error) { config := parsed.Context().Value(ContextKeyConfig).(*Config) reason := SafeArgString(parsed, 1) target := parsed.Args[0].Value.(*discordgo.User) err := BanUserWithDuration(parsed.Context().Value(commands.CtxKeyRedisClient).(*redis.Client), config, parsed.GS.ID(), parsed.Msg.ChannelID, parsed.Msg.Author, reason, target, parsed.Switches["d"].Value.(time.Duration)) if err != nil { if cast, ok := err.(*discordgo.RESTError); ok && cast.Message != nil { return cast.Message.Message, err } else { return "An error occurred", err } } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "Banid", Description: "Bans a user by id, specify a duration with -d", RequiredArgs: 1, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "User", Type: dcmd.Int}, &dcmd.ArgDef{Name: "Reason", Type: dcmd.String}, }, ArgSwitches: []*dcmd.ArgDef{ &dcmd.ArgDef{Switch: "d", Default: time.Duration(0), Name: "Duration", Type: &commands.DurationArg{}}, }, RunFunc: ModBaseCmd(discordgo.PermissionBanMembers, ModCmdBan, func(parsed *dcmd.Data) (interface{}, error) { config := parsed.Context().Value(ContextKeyConfig).(*Config) reason := SafeArgString(parsed, 1) targetID := parsed.Args[0].Int64() targetMember := parsed.GS.MemberCopy(true, targetID, false) var target *discordgo.User if targetMember == nil { target = &discordgo.User{ Username: "unknown", Discriminator: "????", ID: targetID, } } else { target = targetMember.User } err := BanUserWithDuration(parsed.Context().Value(commands.CtxKeyRedisClient).(*redis.Client), config, parsed.GS.ID(), parsed.Msg.ChannelID, parsed.Msg.Author, reason, target, parsed.Switches["d"].Value.(time.Duration)) if err != nil { if cast, ok := err.(*discordgo.RESTError); ok && cast.Message != nil { return cast.Message.Message, err } else { return "An error occurred", err } } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "Kick", Description: "Kicks a member", RequiredArgs: 1, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "User", Type: dcmd.UserReqMention}, &dcmd.ArgDef{Name: "Reason", Type: dcmd.String}, }, RunFunc: ModBaseCmd(discordgo.PermissionKickMembers, ModCmdKick, func(parsed *dcmd.Data) (interface{}, error) { config := parsed.Context().Value(ContextKeyConfig).(*Config) reason := SafeArgString(parsed, 1) target := parsed.Args[0].Value.(*discordgo.User) err := KickUser(config, parsed.GS.ID(), parsed.Msg.ChannelID, parsed.Msg.Author, reason, target) if err != nil { if cast, ok := err.(*discordgo.RESTError); ok && cast.Message != nil { return cast.Message.Message, err } else { return "An error occurred", err } } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "Mute", Description: "Mutes a member", Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "User", Type: dcmd.UserReqMention}, &dcmd.ArgDef{Name: "Minutes", Default: 10, Type: &dcmd.IntArg{Min: 1, Max: 1440}}, &dcmd.ArgDef{Name: "Reason", Type: dcmd.String}, }, ArgumentCombos: [][]int{[]int{0, 1, 2}, []int{0, 1}, []int{0, 2}, []int{0}}, RunFunc: ModBaseCmd(discordgo.PermissionKickMembers, ModCmdMute, func(parsed *dcmd.Data) (interface{}, error) { config := parsed.Context().Value(ContextKeyConfig).(*Config) if config.MuteRole == "" { return "No mute role set up, assign a mute role in the control panel", nil } target := parsed.Args[0].Value.(*discordgo.User) muteDuration := parsed.Args[1].Int() reason := parsed.Args[2].Str() member, err := bot.GetMember(parsed.GS.ID(), target.ID) if err != nil || member == nil { return "Member not found", err } err = MuteUnmuteUser(config, parsed.Context().Value(commands.CtxKeyRedisClient).(*redis.Client), true, parsed.GS.ID(), parsed.Msg.ChannelID, parsed.Msg.Author, reason, member, muteDuration) if err != nil { if cast, ok := err.(*discordgo.RESTError); ok && cast.Message != nil { return "API Error: " + cast.Message.Message, err } else { return "An error occurred", err } } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "Unmute", Description: "Unmutes a member", RequiredArgs: 1, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "User", Type: dcmd.UserReqMention}, &dcmd.ArgDef{Name: "Reason", Type: dcmd.String}, }, RunFunc: ModBaseCmd(discordgo.PermissionKickMembers, ModCmdUnMute, func(parsed *dcmd.Data) (interface{}, error) { config := parsed.Context().Value(ContextKeyConfig).(*Config) if config.MuteRole == "" { return "No mute role set up, assign a mute role in the control panel", nil } target := parsed.Args[0].Value.(*discordgo.User) reason := parsed.Args[1].Str() member, err := bot.GetMember(parsed.GS.ID(), target.ID) if err != nil || member == nil { return "Member not found", err } err = MuteUnmuteUser(config, parsed.Context().Value(commands.CtxKeyRedisClient).(*redis.Client), false, parsed.GS.ID(), parsed.Msg.ChannelID, parsed.Msg.Author, reason, member, 0) if err != nil { if cast, ok := err.(*discordgo.RESTError); ok && cast.Message != nil { return "API Error: " + cast.Message.Message, err } else { return "An error occurred", err } } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, Cooldown: 5, CmdCategory: commands.CategoryModeration, Name: "Report", Description: "Reports a member to the server's staff", RequiredArgs: 2, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "User", Type: dcmd.UserReqMention}, &dcmd.ArgDef{Name: "Reason", Type: dcmd.String}, }, RunFunc: ModBaseCmd(0, ModCmdReport, func(parsed *dcmd.Data) (interface{}, error) { config := parsed.Context().Value(ContextKeyConfig).(*Config) logLink := CreateLogs(parsed.GS.ID(), parsed.CS.ID(), parsed.Msg.Author) channelID := config.IntReportChannel() if channelID == 0 { return "No report channel set up", nil } reportBody := fmt.Sprintf("<@%d> Reported <@%d> in <#%d> For `%s`\nLast 100 messages from channel: <%s>", parsed.Msg.Author.ID, parsed.Args[0].Value.(*discordgo.User).ID, parsed.Msg.ChannelID, parsed.Args[1].Str(), logLink) _, err := common.BotSession.ChannelMessageSend(channelID, common.EscapeSpecialMentions(reportBody)) if err != nil { return "Failed sending report, check perms for report channel", err } if channelID != parsed.Msg.ChannelID { return "User reported to the proper authorities", nil } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "Clean", Description: "Delete the last number of messages from chat, optionally filtering by user, max age and regex.", LongDescription: "Specify a regex with \"-r regex_here\" and max age with \"-ma 1h10m\"\nNote: Will only look in the last 1k messages", Aliases: []string{"clear", "cl"}, RequiredArgs: 1, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "Num", Type: &dcmd.IntArg{Min: 1, Max: 100}}, &dcmd.ArgDef{Name: "User", Type: dcmd.UserReqMention}, }, ArgSwitches: []*dcmd.ArgDef{ &dcmd.ArgDef{Switch: "r", Name: "Regex", Type: dcmd.String}, &dcmd.ArgDef{Switch: "ma", Default: time.Duration(0), Name: "Max age", Type: &commands.DurationArg{}}, &dcmd.ArgDef{Switch: "i", Name: "Regex case insensitive"}, }, ArgumentCombos: [][]int{[]int{0}, []int{0, 1}, []int{1, 0}}, RunFunc: ModBaseCmd(discordgo.PermissionManageMessages, ModCmdClean, func(parsed *dcmd.Data) (interface{}, error) { var userFilter int64 if parsed.Args[1].Value != nil { userFilter = parsed.Args[1].Value.(*discordgo.User).ID } logrus.Println(parsed.Switches) num := parsed.Args[0].Int() if userFilter == 0 || userFilter == parsed.Msg.Author.ID { num++ } if num > 100 { num = 100 } if num < 1 { if num < 0 { return errors.New("Bot is having a stroke <https://www.youtube.com/watch?v=dQw4w9WgXcQ>"), nil } return errors.New("Can't delete nothing"), nil } filtered := false re := "" if parsed.Switches["r"].Value != nil { filtered = true re = parsed.Switches["r"].Str() if parsed.Switches["i"].Value != nil && parsed.Switches["i"].Value.(bool) { if !strings.HasPrefix(re, "(?i)") { re = "(?i)" + re } } } ma := parsed.Switches["ma"].Value.(time.Duration) if ma != 0 { filtered = true } limitFetch := num if userFilter != 0 || filtered { limitFetch = num * 50 } if limitFetch > 1000 { limitFetch = 1000 } time.Sleep(time.Second) numDeleted, err := AdvancedDeleteMessages(parsed.Msg.ChannelID, userFilter, re, ma, num, limitFetch) return dcmd.NewTemporaryResponse(time.Second*5, fmt.Sprintf("Deleted %d message(s)! :')", numDeleted), true), err }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "Reason", Description: "Add/Edit a modlog reason", RequiredArgs: 2, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "ID", Type: dcmd.Int}, &dcmd.ArgDef{Name: "Reason", Type: dcmd.String}, }, RunFunc: ModBaseCmd(discordgo.PermissionKickMembers, ModCmdReason, func(parsed *dcmd.Data) (interface{}, error) { config := parsed.Context().Value(ContextKeyConfig).(*Config) if config.ActionChannel == "" { return "No mod log channel set up", nil } msg, err := common.BotSession.ChannelMessage(config.IntActionChannel(), parsed.Args[0].Int64()) if err != nil { if cast, ok := err.(*discordgo.RESTError); ok && cast.Message != nil { return "Failed retrieving the message: " + cast.Message.Message, nil } return "Failed retrieving the message", err } if msg.Author.ID != common.Conf.BotID { return "I didn't make that message", nil } if len(msg.Embeds) < 1 { return "This entry is either too old or you're trying to mess with me...", nil } embed := msg.Embeds[0] updateEmbedReason(parsed.Msg.Author, parsed.Args[1].Str(), embed) _, err = common.BotSession.ChannelMessageEditEmbed(config.IntActionChannel(), msg.ID, embed) if err != nil { return "Failed updating the modlog entry", err } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "Warn", Description: "Warns a user, warnings are saved using the bot. Use -warnings to view them.", RequiredArgs: 2, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "User", Type: dcmd.UserReqMention}, &dcmd.ArgDef{Name: "Reason", Type: dcmd.String}, }, RunFunc: ModBaseCmd(discordgo.PermissionManageMessages, ModCmdWarn, func(parsed *dcmd.Data) (interface{}, error) { config := parsed.Context().Value(ContextKeyConfig).(*Config) err := WarnUser(config, parsed.GS.ID(), parsed.CS.ID(), parsed.Msg.Author, parsed.Args[0].Value.(*discordgo.User), parsed.Args[1].Str()) if err != nil { return "Seomthing went wrong warning this user, make sure the bot has all the proper perms. (if you have the modlog enabled the bot need to be able to send messages in the modlog for example)", err } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "Warnings", Description: "Lists warning of a user.", Aliases: []string{"Warns"}, RequiredArgs: 1, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "User", Type: dcmd.UserReqMention}, }, RunFunc: ModBaseCmd(discordgo.PermissionManageMessages, ModCmdWarn, func(parsed *dcmd.Data) (interface{}, error) { var result []*WarningModel err := common.GORM.Where("user_id = ? AND guild_id = ?", parsed.Args[0].Value.(*discordgo.User).ID, parsed.GS.ID()).Order("id desc").Find(&result).Error if err != nil && err != gorm.ErrRecordNotFound { return "An error occured...", err } if len(result) < 1 { return "This user has not received any warnings", nil } out := "" for _, entry := range result { out += fmt.Sprintf("#%d: `%20s` **%s** (%13s) - **%s**\n", entry.ID, entry.CreatedAt.Format(time.RFC822), entry.AuthorUsernameDiscrim, entry.AuthorID, entry.Message) if entry.LogsLink != "" { out += "^logs: <" + entry.LogsLink + ">\n" } } return out, nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "EditWarning", Description: "Edit a warning, id is the first number of each warning from the warnings command", RequiredArgs: 2, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "Id", Type: dcmd.Int}, &dcmd.ArgDef{Name: "NewMessage", Type: dcmd.String}, }, RunFunc: ModBaseCmd(discordgo.PermissionManageMessages, ModCmdWarn, func(parsed *dcmd.Data) (interface{}, error) { rows := common.GORM.Model(WarningModel{}).Where("guild_id = ? AND id = ?", parsed.GS.ID(), parsed.Args[0].Int()).Update( "message", fmt.Sprintf("%s (updated by %s#%s (%s))", parsed.Args[1].Str(), parsed.Msg.Author.Username, parsed.Msg.Author.Discriminator, parsed.Msg.Author.ID)).RowsAffected if rows < 1 { return "Failed updating, most likely couldn't find the warning", nil } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "DelWarning", Aliases: []string{"dw"}, Description: "Deletes a warning, id is the first number of each warning from the warnings command", RequiredArgs: 1, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "Id", Type: dcmd.Int}, }, RunFunc: ModBaseCmd(discordgo.PermissionManageMessages, ModCmdWarn, func(parsed *dcmd.Data) (interface{}, error) { rows := common.GORM.Where("guild_id = ? AND id = ?", parsed.GS.ID(), parsed.Args[0].Int()).Delete(WarningModel{}).RowsAffected if rows < 1 { return "Failed deleting, most likely couldn't find the warning", nil } return "👌", nil }), }, &commands.YAGCommand{ CustomEnabled: true, CmdCategory: commands.CategoryModeration, Name: "ClearWarnings", Aliases: []string{"clw"}, Description: "Clears the warnings of a user", RequiredArgs: 1, Arguments: []*dcmd.ArgDef{ &dcmd.ArgDef{Name: "User", Type: dcmd.UserReqMention}, }, RunFunc: ModBaseCmd(discordgo.PermissionManageMessages, ModCmdWarn, func(parsed *dcmd.Data) (interface{}, error) { rows := common.GORM.Where("guild_id = ? AND user_id = ?", parsed.GS.ID(), parsed.Args[0].Value.(*discordgo.User).ID).Delete(WarningModel{}).RowsAffected return fmt.Sprintf("Deleted %d warnings.", rows), nil }), }, }
Functions ¶
func AdvancedDeleteMessages ¶
func BanUserWithDuration ¶
func CreateModlogEmbed ¶
func DeleteMessages ¶
func Dir ¶
func Dir(useLocal bool, name string) http.FileSystem
Dir returns a http.Filesystem for the embedded assets on a given prefix dir. If useLocal is true, the filesystem's contents are instead used.
func FS ¶
func FS(useLocal bool) http.FileSystem
FS returns a http.Filesystem for the embedded assets. If useLocal is true, the filesystem's contents are instead used.
func FSByte ¶
FSByte returns the named file from the embedded assets. If useLocal is true, the filesystem's contents are instead used.
func FSMustByte ¶
FSMustByte is the same as FSByte, but panics if name is not present.
func FSMustString ¶
FSMustString is the string version of FSMustByte.
func HandleGuildBanAddRemove ¶
func HandleGuildBanAddRemove(evt *eventsystem.EventData)
func HandleMemberJoin ¶
func HandleMemberJoin(evt *eventsystem.EventData)
func HandleModeration ¶
func HandleModeration(w http.ResponseWriter, r *http.Request) (web.TemplateData, error)
The moderation page itself
func HandlePostModeration ¶
func HandlePostModeration(w http.ResponseWriter, r *http.Request) (web.TemplateData, error)
Update the settings
func ModBaseCmd ¶
ModBaseCmd is the base command for moderation commands, it makes sure proper permissions are there for the user invoking it and that the command is required and the reason is specified if required
func MuteUnmuteUser ¶
func MuteUnmuteUser(config *Config, client *redis.Client, mute bool, guildID, channelID int64, author *discordgo.User, reason string, member *discordgo.Member, duration int) error
Unmut or mute a user, ignore duration if unmuting
func RedisKeyBannedUser ¶
func RedisKeyMutedUser ¶
func RedisKeyUnbannedUser ¶
func RegisterPlugin ¶
func RegisterPlugin()
Types ¶
type Config ¶
type Config struct { configstore.GuildConfigModel // Kick command KickEnabled bool DeleteMessagesOnKick bool KickReasonOptional bool KickMessage string `valid:"template,1900"` // Ban BanEnabled bool BanReasonOptional bool BanMessage string `valid:"template,1900"` // Mute/unmute MuteEnabled bool MuteRole string `valid:"role,true"` MuteReasonOptional bool UnmuteReasonOptional bool // Warn WarnCommandsEnabled bool WarnIncludeChannelLogs bool WarnSendToModlog bool // Misc CleanEnabled bool ReportEnabled bool ActionChannel string `valid:"channel,true"` ReportChannel string `valid:"channel,true"` LogUnbans bool LogBans bool }
func (*Config) IntActionChannel ¶
func (*Config) IntMuteRole ¶
func (*Config) IntReportChannel ¶
type WarningModel ¶
type WarningModel struct { common.SmallModel GuildID int64 `gorm:"index"` UserID string AuthorID string // Username and discrim for author incase he/she leaves AuthorUsernameDiscrim string Message string LogsLink string }
func (*WarningModel) TableName ¶
func (w *WarningModel) TableName() string