diff --git a/automod/effects.go b/automod/effects.go index a36b4c8f07..23a58d98e1 100644 --- a/automod/effects.go +++ b/automod/effects.go @@ -269,7 +269,7 @@ func (kick *KickUserEffect) Apply(ctxData *TriggeredRuleData, settings interface reason += ctxData.ConstructReason(true) } - err := moderation.KickUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, -1) + err := moderation.KickUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, -1, false) return err } @@ -340,7 +340,7 @@ func (ban *BanUserEffect) Apply(ctxData *TriggeredRuleData, settings interface{} } duration := time.Duration(settingsCast.Duration) * time.Minute - err := moderation.BanUserWithDuration(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, duration, settingsCast.MessageDeleteDays) + err := moderation.BanUserWithDuration(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, duration, settingsCast.MessageDeleteDays, false) return err } @@ -402,7 +402,7 @@ func (mute *MuteUserEffect) Apply(ctxData *TriggeredRuleData, settings interface reason += ctxData.ConstructReason(true) } - err := moderation.MuteUnmuteUser(nil, true, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, ctxData.MS, settingsCast.Duration) + err := moderation.MuteUnmuteUser(nil, true, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, ctxData.MS, settingsCast.Duration, false) return err } @@ -472,7 +472,7 @@ func (timeout *TimeoutUserEffect) Apply(ctxData *TriggeredRuleData, settings int } duration := time.Duration(settingsCast.Duration) * time.Minute - err := moderation.TimeoutUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, duration) + err := moderation.TimeoutUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, duration, false) return err } @@ -526,7 +526,7 @@ func (warn *WarnUserEffect) Apply(ctxData *TriggeredRuleData, settings interface reason += ctxData.ConstructReason(true) } - err := moderation.WarnUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, &ctxData.MS.User, reason) + err := moderation.WarnUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, &ctxData.MS.User, reason, false) return err } diff --git a/automod_legacy/bot.go b/automod_legacy/bot.go index d7992b2e2e..0aef47de2c 100644 --- a/automod_legacy/bot.go +++ b/automod_legacy/bot.go @@ -160,13 +160,13 @@ func CheckMessage(evt *eventsystem.EventData, m *discordgo.Message) bool { switch highestPunish { case PunishNone: - err = moderation.WarnUser(nil, cs.GuildID, cs, m, common.BotUser, &member.User, "Automoderator: "+punishMsg) + err = moderation.WarnUser(nil, cs.GuildID, cs, m, common.BotUser, &member.User, "Automoderator: "+punishMsg, false) case PunishMute: - err = moderation.MuteUnmuteUser(nil, true, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, member, muteDuration) + err = moderation.MuteUnmuteUser(nil, true, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, member, muteDuration, false) case PunishKick: - err = moderation.KickUser(nil, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, &member.User, -1) + err = moderation.KickUser(nil, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, &member.User, -1, false) case PunishBan: - err = moderation.BanUser(nil, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, &member.User) + err = moderation.BanUser(nil, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, &member.User, false) } // Execute the punishment before removing the message to make sure it's included in logs diff --git a/commands/commands.go b/commands/commands.go index 6d15c91dbd..ccc6e54dc4 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -25,6 +25,8 @@ const ( CtxKeyCmdSettings CtxKey = iota CtxKeyChannelOverride CtxKeyExecutedByCC + CtxKeyExecutedByCommandTemplate + CtxKeyExecutedByNestedCommandTemplate ) type MessageFilterFunc func(evt *eventsystem.EventData, msg *discordgo.Message) bool diff --git a/commands/tmplexec.go b/commands/tmplexec.go index 69b73c64ae..4d2c785de6 100644 --- a/commands/tmplexec.go +++ b/commands/tmplexec.go @@ -205,6 +205,13 @@ func execCmd(tmplCtx *templates.Context, dryRun bool, m *discordgo.MessageCreate data = data.WithContext(context.WithValue(data.Context(), paginatedmessages.CtxKeyNoPagination, true)) data = data.WithContext(context.WithValue(data.Context(), CtxKeyExecutedByCC, true)) + switch tmplCtx.ExecutedFrom { + case templates.ExecutedFromCommandTemplate: + data = data.WithContext(context.WithValue(data.Context(), CtxKeyExecutedByCommandTemplate, true)) + case templates.ExecutedFromNestedCommandTemplate: + data = data.WithContext(context.WithValue(data.Context(), CtxKeyExecutedByNestedCommandTemplate, true)) + } + cast := foundCmd.Command.(*YAGCommand) err = dcmd.ParseCmdArgs(data) diff --git a/common/templates/context.go b/common/templates/context.go index 2c46082fa2..3d813db5c2 100644 --- a/common/templates/context.go +++ b/common/templates/context.go @@ -160,10 +160,12 @@ var GuildPremiumFunc func(guildID int64) (bool, error) type ExecutedFromType int const ( - ExecutedFromStandard ExecutedFromType = 0 - ExecutedFromJoin ExecutedFromType = 1 - ExecutedFromLeave ExecutedFromType = 2 - ExecutedFromEvalCC ExecutedFromType = 3 + ExecutedFromStandard ExecutedFromType = 0 + ExecutedFromJoin ExecutedFromType = 1 + ExecutedFromLeave ExecutedFromType = 2 + ExecutedFromEvalCC ExecutedFromType = 3 + ExecutedFromCommandTemplate ExecutedFromType = 4 + ExecutedFromNestedCommandTemplate ExecutedFromType = 5 ) type Context struct { diff --git a/customcommands/tmplextensions.go b/customcommands/tmplextensions.go index 545889e41b..581d1aaec7 100644 --- a/customcommands/tmplextensions.go +++ b/customcommands/tmplextensions.go @@ -176,6 +176,10 @@ func (pa *ParsedArgs) IsSet(index int) interface{} { // or schedules a custom command to be run in the future sometime with the provided data placed in .ExecData func tmplRunCC(ctx *templates.Context) interface{} { return func(ccID int, channel interface{}, delaySeconds interface{}, data interface{}) (string, error) { + if ctx.ExecutedFrom == templates.ExecutedFromCommandTemplate || ctx.ExecutedFrom == templates.ExecutedFromNestedCommandTemplate { + return "", nil + } + if ctx.IncreaseCheckCallCounterPremium("runcc", 1, 10) { return "", templates.ErrTooManyCalls } diff --git a/moderation/commands.go b/moderation/commands.go index efaff1513f..3799c0ce35 100644 --- a/moderation/commands.go +++ b/moderation/commands.go @@ -169,6 +169,10 @@ var ModerationCommands = []*commands.YAGCommand{ DefaultEnabled: false, IsResponseEphemeral: true, RunFunc: func(parsed *dcmd.Data) (interface{}, error) { + if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true { + return nil, errors.New("cannot nest exec/execAdmin calls") + } + config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64()) if err != nil { return nil, err @@ -199,7 +203,7 @@ var ModerationCommands = []*commands.YAGCommand{ if parsed.TraditionalTriggerData != nil { msg = parsed.TraditionalTriggerData.Message } - err = BanUserWithDuration(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, target, banDuration, ddays) + err = BanUserWithDuration(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, target, banDuration, ddays, parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true) if err != nil { return nil, err } @@ -275,6 +279,10 @@ var ModerationCommands = []*commands.YAGCommand{ SlashCommandEnabled: true, IsResponseEphemeral: true, RunFunc: func(parsed *dcmd.Data) (interface{}, error) { + if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true { + return nil, errors.New("cannot nest exec/execAdmin calls") + } + config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64()) if err != nil { return nil, err @@ -310,7 +318,7 @@ var ModerationCommands = []*commands.YAGCommand{ msg = parsed.TraditionalTriggerData.Message } - err = KickUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, target, toDel) + err = KickUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, target, toDel, parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true) if err != nil { return nil, err } @@ -335,6 +343,10 @@ var ModerationCommands = []*commands.YAGCommand{ DefaultEnabled: false, IsResponseEphemeral: true, RunFunc: func(parsed *dcmd.Data) (interface{}, error) { + if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true { + return nil, errors.New("cannot nest exec/execAdmin calls") + } + config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64()) if err != nil { return nil, err @@ -369,7 +381,7 @@ var ModerationCommands = []*commands.YAGCommand{ if parsed.TraditionalTriggerData != nil { msg = parsed.TraditionalTriggerData.Message } - err = MuteUnmuteUser(config, true, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, member, int(d.Minutes())) + err = MuteUnmuteUser(config, true, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, member, int(d.Minutes()), parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true) if err != nil { return nil, err } @@ -394,6 +406,10 @@ var ModerationCommands = []*commands.YAGCommand{ DefaultEnabled: false, IsResponseEphemeral: true, RunFunc: func(parsed *dcmd.Data) (interface{}, error) { + if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true { + return nil, errors.New("cannot nest exec/execAdmin calls") + } + config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64()) if err != nil { return nil, err @@ -418,7 +434,7 @@ var ModerationCommands = []*commands.YAGCommand{ if parsed.TraditionalTriggerData != nil { msg = parsed.TraditionalTriggerData.Message } - err = MuteUnmuteUser(config, false, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, member, 0) + err = MuteUnmuteUser(config, false, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, member, 0, parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true) if err != nil { return nil, err } @@ -444,6 +460,9 @@ var ModerationCommands = []*commands.YAGCommand{ DefaultEnabled: false, IsResponseEphemeral: true, RunFunc: func(parsed *dcmd.Data) (interface{}, error) { + if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true { + return nil, errors.New("cannot nest exec/execAdmin calls") + } config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64()) if err != nil { return nil, err @@ -474,7 +493,7 @@ var ModerationCommands = []*commands.YAGCommand{ if parsed.TraditionalTriggerData != nil { msg = parsed.TraditionalTriggerData.Message } - err = TimeoutUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, &member.User, d) + err = TimeoutUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, &member.User, d, parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true) if err != nil { return nil, err } @@ -821,6 +840,10 @@ var ModerationCommands = []*commands.YAGCommand{ DefaultEnabled: false, IsResponseEphemeral: true, RunFunc: func(parsed *dcmd.Data) (interface{}, error) { + if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true { + return nil, errors.New("cannot nest exec/execAdmin calls") + } + config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64()) if err != nil { return nil, err @@ -839,7 +862,7 @@ var ModerationCommands = []*commands.YAGCommand{ if parsed.TraditionalTriggerData != nil { msg = parsed.TraditionalTriggerData.Message } - err = WarnUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, target, parsed.Args[1].Str()) + err = WarnUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, target, parsed.Args[1].Str(), parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true) if err != nil { return nil, err } diff --git a/moderation/plugin_bot.go b/moderation/plugin_bot.go index 08fd56f8d4..21791d8f7b 100644 --- a/moderation/plugin_bot.go +++ b/moderation/plugin_bot.go @@ -672,7 +672,7 @@ func handleScheduledUnmute(evt *seventsmodels.ScheduledEvent, data interface{}) return scheduledevents2.CheckDiscordErrRetry(err), err } - err = MuteUnmuteUser(nil, false, evt.GuildID, nil, nil, common.BotUser, "Mute Duration Expired", member, 0) + err = MuteUnmuteUser(nil, false, evt.GuildID, nil, nil, common.BotUser, "Mute Duration Expired", member, 0, false) if errors.Cause(err) != ErrNoMuteRole { return scheduledevents2.CheckDiscordErrRetry(err), err } diff --git a/moderation/punishments.go b/moderation/punishments.go index 09708de325..224496ab79 100644 --- a/moderation/punishments.go +++ b/moderation/punishments.go @@ -53,7 +53,7 @@ func getMemberWithFallback(gs *dstate.GuildSet, user *discordgo.User) (ms *dstat } // Kick or bans someone, uploading a hasebin log, and sending the report message in the action channel -func punish(config *Config, p Punishment, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, duration time.Duration, variadicBanDeleteDays ...int) error { +func punish(config *Config, p Punishment, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, duration time.Duration, executedFromCommandTemplate bool, variadicBanDeleteDays ...int) error { config, err := BotCachedGetConfigIfNotSet(guildID, config) if err != nil { @@ -90,7 +90,7 @@ func punish(config *Config, p Punishment, guildID int64, channel *dstate.Channel gs := bot.State.GetGuild(guildID) member, memberNotFound := getMemberWithFallback(gs, user) if !memberNotFound { - sendPunishDM(config, msg, action, gs, channel, message, author, member, duration, reason, -1) + sendPunishDM(config, msg, action, gs, channel, message, author, member, duration, reason, -1, executedFromCommandTemplate) } logLink := "" @@ -171,13 +171,18 @@ var ActionMap = map[string]string{ MATimeoutAdded.Prefix: "Timeout DM", } -func sendPunishDM(config *Config, dmMsg string, action ModlogAction, gs *dstate.GuildSet, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, member *dstate.MemberState, duration time.Duration, reason string, warningID int) { +func sendPunishDM(config *Config, dmMsg string, action ModlogAction, gs *dstate.GuildSet, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, member *dstate.MemberState, duration time.Duration, reason string, warningID int, executedFromCommandTemplate bool) { if dmMsg == "" { dmMsg = DefaultDMMessage } // Execute and send the DM message template ctx := templates.NewContext(gs, channel, member) + if executedFromCommandTemplate { + ctx.ExecutedFrom = templates.ExecutedFromNestedCommandTemplate + } else { + ctx.ExecutedFrom = templates.ExecutedFromCommandTemplate + } ctx.Data["Reason"] = reason if duration > 0 { ctx.Data["Duration"] = duration @@ -216,13 +221,13 @@ func sendPunishDM(config *Config, dmMsg string, action ModlogAction, gs *dstate. } } -func KickUser(config *Config, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, del int) error { +func KickUser(config *Config, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, del int, executedFromCommandTemplate bool) error { config, err := BotCachedGetConfigIfNotSet(guildID, config) if err != nil { return common.ErrWithCaller(err) } - err = punish(config, PunishmentKick, guildID, channel, message, author, reason, user, 0) + err = punish(config, PunishmentKick, guildID, channel, message, author, reason, user, 0, executedFromCommandTemplate) if err != nil { return err } @@ -279,7 +284,7 @@ func DeleteMessages(guildID, channelID int64, filterUser int64, deleteNum, fetch return len(toDelete), err } -func BanUserWithDuration(config *Config, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, duration time.Duration, deleteMessageDays int) error { +func BanUserWithDuration(config *Config, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, duration time.Duration, deleteMessageDays int, executedByCommandTemplate bool) error { // Set a key in redis that marks that this user has appeared in the modlog already common.RedisPool.Do(radix.Cmd(nil, "SETEX", RedisKeyBannedUser(guildID, user.ID), "60", "1")) if deleteMessageDays > 7 { @@ -289,7 +294,7 @@ func BanUserWithDuration(config *Config, guildID int64, channel *dstate.ChannelS deleteMessageDays = 0 } - err := punish(config, PunishmentBan, guildID, channel, message, author, reason, user, duration, deleteMessageDays) + err := punish(config, PunishmentBan, guildID, channel, message, author, reason, user, duration, executedByCommandTemplate, deleteMessageDays) if err != nil { return err } @@ -309,8 +314,8 @@ func BanUserWithDuration(config *Config, guildID int64, channel *dstate.ChannelS return nil } -func BanUser(config *Config, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User) error { - return BanUserWithDuration(config, guildID, channel, message, author, reason, user, 0, 1) +func BanUser(config *Config, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, executedByCommandTemplate bool) error { + return BanUserWithDuration(config, guildID, channel, message, author, reason, user, 0, 1, executedByCommandTemplate) } func UnbanUser(config *Config, guildID int64, author *discordgo.User, reason string, user *discordgo.User) (bool, error) { @@ -359,8 +364,8 @@ func UnbanUser(config *Config, guildID int64, author *discordgo.User, reason str return false, err } -func TimeoutUser(config *Config, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, duration time.Duration) error { - err := punish(config, PunishmentTimeout, guildID, channel, message, author, reason, user, duration, 0) +func TimeoutUser(config *Config, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, user *discordgo.User, duration time.Duration, executedByCommandTemplate bool) error { + err := punish(config, PunishmentTimeout, guildID, channel, message, author, reason, user, duration, executedByCommandTemplate, 0) if err != nil { return err } @@ -409,7 +414,7 @@ const ( // Unmut or mute a user, ignore duration if unmuting // TODO: i don't think we need to track mutes in its own database anymore now with the new scheduled event system -func MuteUnmuteUser(config *Config, mute bool, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, member *dstate.MemberState, duration int) error { +func MuteUnmuteUser(config *Config, mute bool, guildID int64, channel *dstate.ChannelState, message *discordgo.Message, author *discordgo.User, reason string, member *dstate.MemberState, duration int, executedByCommandTemplate bool) error { config, err := BotCachedGetConfigIfNotSet(guildID, config) if err != nil { return common.ErrWithCaller(err) @@ -533,7 +538,7 @@ func MuteUnmuteUser(config *Config, mute bool, guildID int64, channel *dstate.Ch gs := bot.State.GetGuild(guildID) if gs != nil { - go sendPunishDM(config, dmMsg, action, gs, channel, message, author, member, time.Duration(duration)*time.Minute, reason, -1) + go sendPunishDM(config, dmMsg, action, gs, channel, message, author, member, time.Duration(duration)*time.Minute, reason, -1, executedByCommandTemplate) } // Create the modlog entry @@ -614,7 +619,7 @@ func decideUnmuteRoles(config *Config, currentRoles []int64, mute *models.MutedU return newMemberRoles } -func WarnUser(config *Config, guildID int64, channel *dstate.ChannelState, msg *discordgo.Message, author *discordgo.User, target *discordgo.User, message string) error { +func WarnUser(config *Config, guildID int64, channel *dstate.ChannelState, msg *discordgo.Message, author *discordgo.User, target *discordgo.User, message string, executedByCommandTemplate bool) error { warning := &models.ModerationWarning{ GuildID: guildID, UserID: discordgo.StrID(target.ID), @@ -647,7 +652,7 @@ func WarnUser(config *Config, guildID int64, channel *dstate.ChannelState, msg * gs := bot.State.GetGuild(guildID) ms, _ := bot.GetMember(guildID, target.ID) if gs != nil && ms != nil { - sendPunishDM(config, config.WarnMessage, MAWarned, gs, channel, msg, author, ms, -1, message, int(warning.ID)) + sendPunishDM(config, config.WarnMessage, MAWarned, gs, channel, msg, author, ms, -1, message, int(warning.ID), executedByCommandTemplate) } // go bot.SendDM(target.ID, fmt.Sprintf("**%s**: You have been warned for: %s", bot.GuildName(guildID), message)) diff --git a/tickets/tickets_bot.go b/tickets/tickets_bot.go index ddb8583e4f..15667286f9 100644 --- a/tickets/tickets_bot.go +++ b/tickets/tickets_bot.go @@ -50,7 +50,7 @@ const ( ErrMaxOpenTickets TicketUserError = "You're currently in over 10 open tickets on this server, please close some of the ones you're in." ) -func CreateTicket(ctx context.Context, gs *dstate.GuildSet, ms *dstate.MemberState, conf *models.TicketConfig, topic string, checkMaxTickets bool) (*dstate.GuildSet, *models.Ticket, error) { +func CreateTicket(ctx context.Context, gs *dstate.GuildSet, ms *dstate.MemberState, conf *models.TicketConfig, topic string, checkMaxTickets, executedByCommandTemplate bool) (*dstate.GuildSet, *models.Ticket, error) { if gs.GetChannel(conf.TicketsChannelCategory) == nil { return gs, nil, ErrNoTicketCateogry } @@ -119,6 +119,11 @@ func CreateTicket(ctx context.Context, gs *dstate.GuildSet, ms *dstate.MemberSta gs.Channels = append(gs.Channels, cs) tmplCTX := templates.NewContext(gs, &cs, ms) + if executedByCommandTemplate { + tmplCTX.ExecutedFrom = templates.ExecutedFromNestedCommandTemplate + } else { + tmplCTX.ExecutedFrom = templates.ExecutedFromCommandTemplate + } tmplCTX.Name = "ticket open message" tmplCTX.Data["Reason"] = topic ticketOpenMsg := conf.TicketOpenMSG diff --git a/tickets/tickets_commands.go b/tickets/tickets_commands.go index 38f941cc80..ea61e1bd7c 100644 --- a/tickets/tickets_commands.go +++ b/tickets/tickets_commands.go @@ -6,6 +6,7 @@ import ( "context" "database/sql" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -51,12 +52,16 @@ func (p *Plugin) AddCommands() { {Name: "subject", Type: dcmd.String}, }, RunFunc: func(parsed *dcmd.Data) (interface{}, error) { + if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true { + return nil, errors.New("cannot nest exec/execAdmin calls") + } + conf := parsed.Context().Value(CtxKeyConfig).(*models.TicketConfig) if !conf.Enabled { return createTicketsDisabledError(parsed.GuildData), nil } - _, ticket, err := CreateTicket(parsed.Context(), parsed.GuildData.GS, parsed.GuildData.MS, conf, parsed.Args[0].Str(), true) + _, ticket, err := CreateTicket(parsed.Context(), parsed.GuildData.GS, parsed.GuildData.MS, conf, parsed.Args[0].Str(), true, parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true) if err != nil { switch t := err.(type) { case TicketUserError: diff --git a/tickets/tmplextensions.go b/tickets/tmplextensions.go index c2334d7e91..4c33a98139 100644 --- a/tickets/tmplextensions.go +++ b/tickets/tmplextensions.go @@ -25,6 +25,10 @@ func init() { // or schedules a custom command to be run in the future sometime with the provided data placed in .ExecData func tmplCreateTicket(ctx *templates.Context) interface{} { return func(author interface{}, topic string) (*TemplateTicket, error) { + if ctx.ExecutedFrom == templates.ExecutedFromNestedCommandTemplate { + return nil, errors.New("cannot nest exec/execAdmin/ticket creation") + } + if ctx.IncreaseCheckCallCounterPremium("ticket", 1, 1) { return nil, templates.ErrTooManyCalls } @@ -80,7 +84,7 @@ func tmplCreateTicket(ctx *templates.Context) interface{} { return nil, errors.New("tickets are disabled on this server") } - gs, ticket, err := CreateTicket(context.Background(), ctx.GS, ms, conf, topic, true) + gs, ticket, err := CreateTicket(context.Background(), ctx.GS, ms, conf, topic, true, ctx.ExecutedFrom == templates.ExecutedFromCommandTemplate) ctx.GS = gs if err != nil { diff --git a/verification/verification_bot.go b/verification/verification_bot.go index 2904f27312..5813c89157 100644 --- a/verification/verification_bot.go +++ b/verification/verification_bot.go @@ -334,7 +334,7 @@ func (p *Plugin) handleUserVerifiedScheduledEvent(ms *dstate.MemberState, guildI banReason = string(r) + "..." } - err := moderation.BanUser(nil, guildID, nil, nil, common.BotUser, banReason, &ms.User) + err := moderation.BanUser(nil, guildID, nil, nil, common.BotUser, banReason, &ms.User, false) if err != nil { return scheduledevents2.CheckDiscordErrRetry(err), err } @@ -674,7 +674,7 @@ func (p *Plugin) banAlts(ban *discordgo.GuildBanAdd, alts []*discordgo.User) { logger.WithField("guild", ban.GuildID).WithField("user", v.ID).WithField("dupe-of", ban.User.ID).Info("banning alt account") reason := fmt.Sprintf("Alt of banned user (%s (%d))", ban.User.String(), ban.User.ID) markRecentlyBannedByVerification(ban.GuildID, v.ID) - moderation.BanUser(nil, ban.GuildID, nil, nil, common.BotUser, reason, v) + moderation.BanUser(nil, ban.GuildID, nil, nil, common.BotUser, reason, v, false) continue } }