commands

package
v2.37.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2024 License: MIT Imports: 43 Imported by: 1

README

The commands plugin handles the configuration of the global command settings.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	CategoryGeneral = &dcmd.Category{
		Name:        "General",
		Description: "General & informational commands",
		HelpEmoji:   "ℹ️",
		EmbedColor:  0xe53939,
	}
	CategoryTool = &dcmd.Category{
		Name:        "Tools & Utilities",
		Description: "Various miscellaneous commands",
		HelpEmoji:   "🔨",
		EmbedColor:  0xeaed40,
	}
	CategoryModeration = &dcmd.Category{
		Name:        "Moderation",
		Description: "Moderation commands",
		HelpEmoji:   "👮",
		EmbedColor:  0xdb0606,
	}
	CategoryFun = &dcmd.Category{
		Name:        "Fun",
		Description: "Various commands meant for entertainment",
		HelpEmoji:   "🎉",
		EmbedColor:  0x5ae26c,
	}
	CategoryDebug = &dcmd.Category{
		Name:        "Debug & Maintenance",
		Description: "Debug and other commands to inspect the bot",
		HelpEmoji:   "🖥",
		EmbedColor:  0,
	}
)
View Source
var (
	RKeyCommandCooldown      = func(uID int64, cmd string) string { return "cmd_cd:" + discordgo.StrID(uID) + ":" + cmd }
	RKeyCommandCooldownGuild = func(gID int64, cmd string) string { return "cmd_guild_cd:" + discordgo.StrID(gID) + ":" + cmd }
	RKeyCommandLock          = func(uID int64, cmd string) string { return "cmd_lock:" + discordgo.StrID(uID) + ":" + cmd }

	CommandExecTimeout = time.Minute
)
View Source
var (
	CommandSystem *dcmd.System
)
View Source
var DBSchemas = []string{`
CREATE TABLE IF NOT EXISTS commands_channels_overrides (
	id BIGSERIAL PRIMARY KEY,
	guild_id BIGINT NOT NULL,

	channels BIGINT[],
	channel_categories BIGINT[],
	global bool NOT NULL,

	commands_enabled BOOL NOT NULL,

	autodelete_response BOOL NOT NULL,
	autodelete_trigger BOOL NOT NULL,

	autodelete_response_delay INT NOT NULL,
	autodelete_trigger_delay INT NOT NULL,

	require_roles BIGINT[] NOT NULL,
	ignore_roles BIGINT[] NOT NULL
);
`, `
CREATE INDEX IF NOT EXISTS commands_channels_overrides_guild_idx ON commands_channels_overrides(guild_id);
`, `
CREATE UNIQUE INDEX IF NOT EXISTS commands_channels_overrides_global_uniquex ON commands_channels_overrides (guild_id) WHERE global;
`, `
CREATE TABLE IF NOT EXISTS commands_command_overrides (
	id BIGSERIAL PRIMARY KEY,
	guild_id BIGINT NOT NULL,
	commands_channels_overrides_id BIGINT references commands_channels_overrides(id) ON DELETE CASCADE NOT NULL,
	
	commands TEXT[] NOT NULL,

	commands_enabled BOOL NOT NULL,

	autodelete_response BOOL NOT NULL,
	autodelete_trigger BOOL NOT NULL,

	autodelete_response_delay INT NOT NULL,
	autodelete_trigger_delay INT NOT NULL,

	require_roles BIGINT[] NOT NULL,
	ignore_roles BIGINT[] NOT NULL
);
`, `
CREATE INDEX IF NOT EXISTS commands_command_groups_channels_override_idx ON commands_command_overrides(commands_channels_overrides_id);
`}
View Source
var MessageFilterFuncs []MessageFilterFunc

These functions are called on every message, and should return true if the message should be checked for commands, false otherwise

View Source
var PageHTML string

Functions

func AddRootCommands

func AddRootCommands(p common.Plugin, cmds ...*YAGCommand)

func AddRootCommandsWithMiddlewares

func AddRootCommandsWithMiddlewares(p common.Plugin, middlewares []dcmd.MiddleWareFunc, cmds ...*YAGCommand)

func BlockingAddRunningCommand

func BlockingAddRunningCommand(guildID int64, channelID int64, authorID int64, cmd *YAGCommand, timeout time.Duration) bool

func CensorError

func CensorError(err error) string

Keys and other sensitive information shouldnt be sent in error messages, but just in case it is

func ChannelOverrideMiddleware

func ChannelOverrideMiddleware(inner func(w http.ResponseWriter, r *http.Request, override *models.CommandsChannelsOverride) (web.TemplateData, error)) web.ControllerHandlerFunc

Channel override handlers

func CmdNotFound

func CmdNotFound(search string) string

func CommonContainerNotFoundHandler

func CommonContainerNotFoundHandler(container *dcmd.Container, fixedMessage string) func(data *dcmd.Data) (interface{}, error)

CommonContainerNotFoundHandler is a common "NotFound" handler that should be used with dcmd containers it ensures that no messages is sent if none of the commands in te container is enabeld if "fixedMessage" is empty, then it shows default generated container help

func ContainerSlashCommandPermissions

func ContainerSlashCommandPermissions(container *slashCommandsContainer, overrides []*models.CommandsChannelsOverride, gs *dstate.GuildSet) ([]*discordgo.ApplicationCommandPermissions, error)

Since we can't put permissions on subcommands we do a similar thing we do to command settings that is

func FilterBadInvites

func FilterBadInvites(msg string, guildID int64, replacement string) string

func FilterResp

func FilterResp(in interface{}, guildID int64) interface{}

func GetAllOverrides

func GetAllOverrides(ctx context.Context, guildID int64) ([]*models.CommandsChannelsOverride, error)

GetAllOverrides returns all channel overrides and ensures the global override with atleast a default is present

func GetCommandPrefixBotEvt

func GetCommandPrefixBotEvt(evt *eventsystem.EventData) (string, error)

func GetOverridesForChannel

func GetOverridesForChannel(channelID, channelParentID, guildID int64) ([]*models.CommandsChannelsOverride, error)

func HandleCommands

func HandleCommands(w http.ResponseWriter, r *http.Request) (web.TemplateData, error)

Servers the command page with current config

func HandleCreateChannelsOverride

func HandleCreateChannelsOverride(w http.ResponseWriter, r *http.Request) (web.TemplateData, error)

func HandleCreateCommandOverride

func HandleCreateCommandOverride(w http.ResponseWriter, r *http.Request, channelOverride *models.CommandsChannelsOverride) (web.TemplateData, error)

Command handlers

func HandleDeleteChannelsOverride

func HandleDeleteChannelsOverride(w http.ResponseWriter, r *http.Request, currentOverride *models.CommandsChannelsOverride) (web.TemplateData, error)

func HandleDeleteCommandOverride

func HandleDeleteCommandOverride(w http.ResponseWriter, r *http.Request, channelOverride *models.CommandsChannelsOverride) (web.TemplateData, error)

func HandlePostCommands

func HandlePostCommands(w http.ResponseWriter, r *http.Request) (web.TemplateData, error)

Handles the updating of global and per channel command settings

func HandleUpdateChannelsOverride

func HandleUpdateChannelsOverride(w http.ResponseWriter, r *http.Request, currentOverride *models.CommandsChannelsOverride) (web.TemplateData, error)

func HandleUpdateCommandOVerride

func HandleUpdateCommandOVerride(w http.ResponseWriter, r *http.Request, channelOverride *models.CommandsChannelsOverride) (web.TemplateData, error)

func InitCommands

func InitCommands()

func IsSlashCommandPermissionCommandEnabled

func IsSlashCommandPermissionCommandEnabled(fullName string, overrides []*models.CommandsChannelsOverride) bool

IsSlashCommandPermissionCommandEnabled following up on the no per channel permissions for slash commands This might seem like a mouthfull but essentially for us to be able to disable a command in a guild it has to be disabled in all channels. If its enabled it atleast 1 channel override of command override we need to be able to pick it from the slash command list

func NewUserError

func NewUserError(a ...interface{}) error

func NewUserErrorf

func NewUserErrorf(f string, a ...interface{}) error

func PubsubSendUpdateSlashCommandsPermissions

func PubsubSendUpdateSlashCommandsPermissions(gID int64)

func RegisterPlugin

func RegisterPlugin()

func RegisterSlashCommandsContainer

func RegisterSlashCommandsContainer(container *dcmd.Container, defaultPermissions bool, rolesRunFunc RolesRunFunc)

register containers seperately as they need special handling

note: we could infer all the info from the members of the container but i felt that this explicit method was better and less quirky

func TmplExecCmdFuncs

func TmplExecCmdFuncs(ctx *templates.Context, maxExec int, dryRun bool) (userCtxCommandExec cmdExecFunc, botCtxCommandExec cmdExecFunc)

Returns 2 functions to execute commands in user or bot context with limited about of commands executed

func YAGCommandMiddleware

func YAGCommandMiddleware(inner dcmd.RunFunc) dcmd.RunFunc

Types

type CanExecuteError

type CanExecuteError struct {
	Type    CanExecuteType
	Message string
}

type CanExecuteType

type CanExecuteType int
const (
	ReasonError CanExecuteType = iota
	ReasonCommandDisabaledSettings
	ReasonMissingRole
	ReasonIgnoredRole
	ReasonUserMissingPerms
	ReasonBotMissingPerms
	ReasonCooldown
)

type ChannelOverrideForm

type ChannelOverrideForm struct {
	Channels                []int64 `valid:"channel,true"`
	ChannelCategories       []int64 `valid:"channel,true"`
	Global                  bool
	CommandsEnabled         bool
	AutodeleteResponse      bool
	AutodeleteTrigger       bool
	AutodeleteResponseDelay int     `valid:"0,2678400"`
	AutodeleteTriggerDelay  int     `valid:"0,2678400"`
	RequireRoles            []int64 `valid:"role,true"`
	IgnoreRoles             []int64 `valid:"role,true"`
}

type CommandOverrideForm

type CommandOverrideForm struct {
	Commands                []string
	CommandsEnabled         bool
	AutodeleteResponse      bool
	AutodeleteTrigger       bool
	AutodeleteResponseDelay int     `valid:"0,2678400"`
	AutodeleteTriggerDelay  int     `valid:"0,2678400"`
	RequireRoles            []int64 `valid:"role,true"`
	IgnoreRoles             []int64 `valid:"role,true"`
}

type CommandProvider

type CommandProvider interface {
	// This is where you should register your commands, called on both the webserver and the bot
	AddCommands()
}

type CommandSettings

type CommandSettings struct {
	Enabled bool

	DelTrigger       bool
	DelResponse      bool
	DelTriggerDelay  int
	DelResponseDelay int

	RequiredRoles []int64
	IgnoreRoles   []int64
}

type ContextKey

type ContextKey int
const (
	CtxKeyRedisClient ContextKey = iota
)

type CtxKey

type CtxKey int
const (
	CtxKeyCmdSettings CtxKey = iota
	CtxKeyChannelOverride
	CtxKeyExecutedByCC
)

type DurationArg

type DurationArg struct {
	Min, Max time.Duration
}

func (*DurationArg) CheckCompatibility added in v2.1.0

func (d *DurationArg) CheckCompatibility(def *dcmd.ArgDef, part string) dcmd.CompatibilityResult

func (*DurationArg) HelpName

func (d *DurationArg) HelpName() string

func (*DurationArg) ParseFromInteraction

func (d *DurationArg) ParseFromInteraction(def *dcmd.ArgDef, data *dcmd.Data, options *dcmd.SlashCommandsParseOptions) (val interface{}, err error)

func (*DurationArg) ParseFromMessage

func (d *DurationArg) ParseFromMessage(def *dcmd.ArgDef, part string, data *dcmd.Data) (interface{}, error)

func (*DurationArg) SlashCommandOptions

func (d *DurationArg) SlashCommandOptions(def *dcmd.ArgDef) []*discordgo.ApplicationCommandOption

type DurationOutOfRangeError

type DurationOutOfRangeError struct {
	Min, Max time.Duration
	Got      time.Duration
	ArgName  string
}

func (*DurationOutOfRangeError) Error

func (o *DurationOutOfRangeError) Error() string

type EphemeralOrGuild

type EphemeralOrGuild struct {
	Content string
	Embed   *discordgo.MessageEmbed
}

func (*EphemeralOrGuild) Send

func (e *EphemeralOrGuild) Send(data *dcmd.Data) ([]*discordgo.Message, error)

type EphemeralOrNone

type EphemeralOrNone struct {
	Content string
	Embed   *discordgo.MessageEmbed
}

func (*EphemeralOrNone) Send

func (e *EphemeralOrNone) Send(data *dcmd.Data) ([]*discordgo.Message, error)

type MemberArg

type MemberArg struct{}

MemberArg matches a id or mention and returns a MemberState object for the user

func (*MemberArg) CheckCompatibility added in v2.1.0

func (ma *MemberArg) CheckCompatibility(def *dcmd.ArgDef, part string) dcmd.CompatibilityResult

func (*MemberArg) ExtractID

func (ma *MemberArg) ExtractID(part string, data *dcmd.Data) int64

func (*MemberArg) HelpName

func (ma *MemberArg) HelpName() string

func (*MemberArg) ParseFromInteraction

func (ma *MemberArg) ParseFromInteraction(def *dcmd.ArgDef, data *dcmd.Data, options *dcmd.SlashCommandsParseOptions) (val interface{}, err error)

func (*MemberArg) ParseFromMessage

func (ma *MemberArg) ParseFromMessage(def *dcmd.ArgDef, part string, data *dcmd.Data) (interface{}, error)

func (*MemberArg) SlashCommandOptions

func (ma *MemberArg) SlashCommandOptions(def *dcmd.ArgDef) []*discordgo.ApplicationCommandOption

type MessageFilterFunc

type MessageFilterFunc func(evt *eventsystem.EventData, msg *discordgo.Message) bool

type Plugin

type Plugin struct{}

func (*Plugin) AllFeatureFlags

func (p *Plugin) AllFeatureFlags() []string

func (*Plugin) BotInit

func (p *Plugin) BotInit()

func (*Plugin) InitWeb

func (p *Plugin) InitWeb()

func (*Plugin) LoadServerHomeWidget

func (p *Plugin) LoadServerHomeWidget(w http.ResponseWriter, r *http.Request) (web.TemplateData, error)

func (*Plugin) PluginInfo

func (p *Plugin) PluginInfo() *common.PluginInfo

func (*Plugin) Prefix

func (p *Plugin) Prefix(data *dcmd.Data) string

func (*Plugin) StopBot

func (p *Plugin) StopBot(wg *sync.WaitGroup)

func (*Plugin) UpdateFeatureFlags

func (p *Plugin) UpdateFeatureFlags(guildID int64) ([]string, error)

type PublicError

type PublicError string

PublicError is a error that is both logged and returned as a response

func NewPublicError

func NewPublicError(a ...interface{}) PublicError

func NewPublicErrorF

func NewPublicErrorF(f string, a ...interface{}) PublicError

func (PublicError) Error

func (p PublicError) Error() string

type RoleArg

type RoleArg struct{}

RoleArg matches an id or name and returns a discordgo.Role

func (*RoleArg) CheckCompatibility added in v2.1.0

func (ra *RoleArg) CheckCompatibility(def *dcmd.ArgDef, part string) dcmd.CompatibilityResult

func (*RoleArg) ExtractID

func (ra *RoleArg) ExtractID(part string, data *dcmd.Data) interface{}

func (*RoleArg) HelpName

func (ra *RoleArg) HelpName() string

func (*RoleArg) ParseFromInteraction

func (ra *RoleArg) ParseFromInteraction(def *dcmd.ArgDef, data *dcmd.Data, options *dcmd.SlashCommandsParseOptions) (val interface{}, err error)

func (*RoleArg) ParseFromMessage

func (ra *RoleArg) ParseFromMessage(def *dcmd.ArgDef, part string, data *dcmd.Data) (interface{}, error)

func (*RoleArg) SlashCommandOptions

func (ra *RoleArg) SlashCommandOptions(def *dcmd.ArgDef) []*discordgo.ApplicationCommandOption

type RolesRunFunc

type RolesRunFunc func(gs *dstate.GuildSet) ([]int64, error)

type RunningCommand

type RunningCommand struct {
	GuildID   int64
	ChannelID int64
	AuthorID  int64

	Command *YAGCommand
}

type UserError

type UserError string

UserError is a special error type that is only sent as a response, and not logged

func (UserError) Error

func (ue UserError) Error() string

func (UserError) IsUserError

func (ue UserError) IsUserError() bool

type YAGCommand

type YAGCommand struct {
	Name            string   // Name of command, what its called from
	Aliases         []string // Aliases which it can also be called from
	Description     string   // Description shown in non targetted help
	LongDescription string   // Longer description when this command was targetted

	Arguments      []*dcmd.ArgDef // Slice of argument definitions, ctx.Args will always be the same size as this slice (although the data may be nil)
	RequiredArgs   int            // Number of reuquired arguments, ignored if combos is specified
	ArgumentCombos [][]int        // Slice of argument pairs, will override RequiredArgs if specified
	ArgSwitches    []*dcmd.ArgDef // Switches for the commadn to use

	AllowEveryoneMention bool

	HideFromCommandsPage bool   // Set to  hide this command from the commands page
	Key                  string // GuildId is appended to the key, e.g if key is "test:", it will check for "test:<guildid>"
	CustomEnabled        bool   // Set to true to handle the enable check itself
	Default              bool   // The default enabled state of this command

	Cooldown           int // Cooldown in seconds before user can use it again
	CmdCategory        *dcmd.Category
	GuildScopeCooldown int

	RunInDM      bool // Set to enable this commmand in DM's
	HideFromHelp bool // Set to hide from help

	RequireDiscordPerms      []int64   // Require users to have one of these permission sets to run the command
	RequiredDiscordPermsHelp string    // Optional message that shows up when users run the help command that documents user permission requirements for the command
	RequireBotPerms          [][]int64 // Discord permissions that the bot needs to run the command, (([0][0] && [0][1] && [0][2]) || ([1][0] && [1][1]...))

	Middlewares []dcmd.MiddleWareFunc

	// Run is ran when the command has sucessfully been parsed
	// It returns a reply and an error
	// the reply can have a type of string, *MessageEmbed or error
	RunFunc dcmd.RunFunc

	Plugin common.Plugin

	// Slash commands integration (this is unused on sub commands)
	//
	// Note about channel overrides:
	// Since the slash commands permissions is limited to roles/users only and can't be per channel, it takes the common set of roles required to run the command between all overrides
	// e.g if the command does not require a role in one channel, but it requires one in another channel, then the required permission for the slash command will be none set,
	// note that these settings are still checked when the command is run, but they just show the command in the client even if you can't use it in this case, so its just a visual limitation of slash commands.
	//
	// If it's disabled in all chanels, then for default_enabled = true commands, it adds the everyone role to the blacklist, otherwise it adds no role to the whitelist (does this even work? can i use the everyone role in this context?)
	SlashCommandEnabled bool

	// Wether the command is enabled in all guilds by default or not
	DefaultEnabled bool

	// If default enabled = false
	// then this returns the roles that CAN use the command
	// if default enabled = true
	// then this returns the roles that CAN'T use the command
	RolesRunFunc RolesRunFunc

	IsResponseEphemeral bool
	NSFW                bool
	// contains filtered or unexported fields
}

Slight extension to the simplecommand, it will check if the command is enabled in the HandleCommand func And invoke a custom handlerfunc with provided redis client

func (*YAGCommand) ArgDefs

func (yc *YAGCommand) ArgDefs(data *dcmd.Data) (args []*dcmd.ArgDef, required int, combos [][]int)

func (*YAGCommand) Category

func (yc *YAGCommand) Category() *dcmd.Category

CmdWithCategory puts the command in a category, mostly used for the help generation

func (*YAGCommand) Descriptions

func (yc *YAGCommand) Descriptions(data *dcmd.Data) (short, long string)

func (*YAGCommand) FindNameFromContainerChain

func (yc *YAGCommand) FindNameFromContainerChain(cc []*dcmd.Container) string

func (*YAGCommand) GetSettings

func (cs *YAGCommand) GetSettings(containerChain []*dcmd.Container, channelID, channelParentID, guildID int64) (settings *CommandSettings, err error)

GetSettings returns the settings from the command, generated from the servers channel and command overrides

func (*YAGCommand) GetSettingsWithLoadedOverrides

func (cs *YAGCommand) GetSettingsWithLoadedOverrides(containerChain []*dcmd.Container, guildID int64, channelOverrides []*models.CommandsChannelsOverride) (settings *CommandSettings, err error)

func (*YAGCommand) GetTrigger

func (yc *YAGCommand) GetTrigger() *dcmd.Trigger

func (*YAGCommand) GuildScopeCooldownLeft

func (cs *YAGCommand) GuildScopeCooldownLeft(cc []*dcmd.Container, guildID int64) (int, error)

GuildScopeCooldownLeft returns the number of seconds before a command can be used again on this server

func (*YAGCommand) Logger

func (yc *YAGCommand) Logger(data *dcmd.Data) *logrus.Entry

func (*YAGCommand) LongestCooldownLeft

func (cs *YAGCommand) LongestCooldownLeft(cc []*dcmd.Container, userID int64, guildID int64) (int, error)

LongestCooldownLeft returns the longest cooldown for this command, either user scoped or guild scoped

func (*YAGCommand) PostCommandExecuted

func (yc *YAGCommand) PostCommandExecuted(settings *CommandSettings, cmdData *dcmd.Data, resp interface{}, err error)

PostCommandExecuted sends the response and handles the trigger and response deletions

func (*YAGCommand) Run

func (yc *YAGCommand) Run(data *dcmd.Data) (interface{}, error)

func (*YAGCommand) SetCooldownGuild

func (cs *YAGCommand) SetCooldownGuild(cc []*dcmd.Container, guildID int64) error

SetCooldownGuild sets the guild scoped cooldown of the command as it's defined in the struct

func (*YAGCommand) SetCooldownUser

func (cs *YAGCommand) SetCooldownUser(cc []*dcmd.Container, userID int64) error

SetCooldownUser sets the user scoped cooldown of the command as it's defined in the struct

func (*YAGCommand) SetCooldowns

func (cs *YAGCommand) SetCooldowns(cc []*dcmd.Container, userID int64, guildID int64) error

SetCooldowns is a helper that serts both User and Guild cooldown

func (*YAGCommand) SlashCommandPermissions

func (yc *YAGCommand) SlashCommandPermissions(overrides []*models.CommandsChannelsOverride, defaultEnabeld bool, containerChain []*dcmd.Container, gs *dstate.GuildSet) (allowRoles []int64, denyRoles []int64, allowAll bool, denyAll bool, err error)

func (*YAGCommand) Switches

func (yc *YAGCommand) Switches() []*dcmd.ArgDef

func (*YAGCommand) TopLevelSlashCommandPermissions

func (yc *YAGCommand) TopLevelSlashCommandPermissions(overrides []*models.CommandsChannelsOverride, gs *dstate.GuildSet) ([]*discordgo.ApplicationCommandPermissions, error)

func (*YAGCommand) UserScopeCooldownLeft

func (cs *YAGCommand) UserScopeCooldownLeft(cc []*dcmd.Container, userID int64) (int, error)

UserScopeCooldownLeft returns the number of seconds before a command can be used again by this user

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL