github.com/starshine-sys/bcr@v0.21.0/execute_slash.go (about) 1 package bcr 2 3 import ( 4 "fmt" 5 "strings" 6 "sync" 7 8 "github.com/diamondburned/arikawa/v3/discord" 9 "github.com/diamondburned/arikawa/v3/gateway" 10 ) 11 12 // InteractionCreate is called when an interaction create event is received. 13 func (r *Router) InteractionCreate(ic *gateway.InteractionCreateEvent) { 14 if ic.Type != gateway.CommandInteraction { 15 return 16 } 17 18 ctx, err := r.NewSlashContext(ic) 19 if err != nil { 20 r.Logger.Error("Couldn't create slash context: %v", err) 21 return 22 } 23 24 err = r.ExecuteSlash(ctx) 25 if err != nil { 26 r.Logger.Error("Couldn't create slash context: %v", err) 27 } 28 } 29 30 // ExecuteSlash executes slash commands. Only one layer for now, so no subcommands, sorry :( 31 func (r *Router) ExecuteSlash(ctx *SlashContext) (err error) { 32 err = r.executeSlash(true, ctx, r.cmds, &r.cmdMu) 33 if err == errCommandRun { 34 return nil 35 } 36 return 37 } 38 39 func errCommand(err error) error { 40 if err == nil { 41 return errCommandRun 42 } 43 return err 44 } 45 46 func (r *Router) executeSlash(isTopLevel bool, ctx *SlashContext, cmds map[string]*Command, mu *sync.RWMutex) (err error) { 47 // first, check subcommands 48 if len(ctx.CommandOptions) > 0 && isTopLevel { 49 for _, g := range r.slashGroups { 50 if strings.EqualFold(g.Name, ctx.CommandName) { 51 nctx := &SlashContext{} 52 *nctx = *ctx 53 nctx.CommandName = ctx.CommandOptions[0].Name 54 nctx.CommandOptions = ctx.CommandOptions[0].Options 55 56 // convert subcommands slice to a map 57 m := map[string]*Command{} 58 for _, cmd := range g.Subcommands { 59 m[strings.ToLower(cmd.Name)] = cmd 60 } 61 var nmu sync.RWMutex // this doesn't matter so we just create a new one 62 63 return r.executeSlash(false, nctx, m, &nmu) 64 } 65 } 66 } 67 68 // else, we try top-level commands (or skip to this immediately if it isn't the top level) 69 mu.RLock() 70 cmd, ok := cmds[ctx.CommandName] 71 if !ok || cmd.SlashCommand == nil { 72 mu.RUnlock() 73 err = ctx.SendEphemeral(fmt.Sprintf("Looks like you found a command (``%v``) that's registered as a slash command, but doesn't work as one :(\nPlease report this to the bot developer as this is a bug!", EscapeBackticks(ctx.CommandName))) 74 return errCommand(err) 75 } 76 mu.RUnlock() 77 78 ctx.Command = cmd 79 80 if (cmd.GuildOnly || cmd.Permissions != 0) && !ctx.Event.GuildID.IsValid() { 81 err = ctx.SendEphemeral(":x: This command cannot be run in DMs.") 82 return errCommand(err) 83 } 84 85 if r.BlacklistFunc != nil && cmd.Blacklistable { 86 if r.BlacklistFunc(ctx) { 87 err = ctx.SendEphemeral("This command can't be used here.") 88 return errCommand(err) 89 } 90 } 91 92 if cmd.GuildPermissions != 0 { 93 if ctx.Guild == nil || ctx.Member == nil { 94 err = ctx.SendEphemeral(":x: This command cannot be used in DMs.") 95 return errCommand(err) 96 } 97 if !ctx.GuildPerms().Has(cmd.GuildPermissions) { 98 err = ctx.SendEphemeral(fmt.Sprintf(":x: You are not allowed to use this command. You are missing the following permissions:\n> ```%v```", strings.Join(PermStrings(cmd.GuildPermissions), ", "))) 99 return errCommand(err) 100 } 101 } 102 103 if cmd.Permissions != 0 { 104 if ctx.Member != nil && ctx.Guild != nil { 105 if !discord.CalcOverwrites(*ctx.Guild, *ctx.Channel, *ctx.Member).Has(cmd.Permissions) { 106 err = ctx.SendEphemeral(fmt.Sprintf(":x: You are not allowed to use this command. You are missing the following permissions:\n> ```%v```", strings.Join(PermStrings(cmd.Permissions), ", "))) 107 return errCommand(err) 108 } 109 } else { 110 err = ctx.SendEphemeral(":x: This command cannot be run in DMs.") 111 return errCommand(err) 112 } 113 } 114 115 if cmd.OwnerOnly { 116 isOwner := false 117 for _, u := range ctx.Router.BotOwners { 118 if ctx.Author.ID.String() == u { 119 isOwner = true 120 break 121 } 122 } 123 124 if !isOwner { 125 err = ctx.SendEphemeral(":x: This command can only be used by a bot owner.") 126 return errCommand(err) 127 } 128 } 129 130 if cmd.CustomPermissions != nil { 131 b, err := cmd.CustomPermissions.Check(ctx) 132 // if it errored, send that error and return 133 if err != nil { 134 err = ctx.SendEphemeral(fmt.Sprintf(":x: An internal error occurred when checking your permissions.\nThe following permission(s) could not be checked:\n> ```%s```", cmd.CustomPermissions)) 135 return errCommand(err) 136 } 137 138 // else if it returned false, show that error and return 139 if !b { 140 err = ctx.SendEphemeral(fmt.Sprintf(":x: You are not allowed to use this command. You are missing the following permission(s):\n> ```%s```", cmd.CustomPermissions)) 141 return errCommand(err) 142 } 143 } 144 145 err = cmd.SlashCommand(ctx) 146 return errCommand(err) 147 }