parent
1c6570d157
commit
b027e15cac
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Dusty.P (https://github.com/dustinpianalto)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
## Disgoman
|
||||||
|
Disgoman is a command handler for DiscordGo, inspired by [Anpan](https://github.com/MikeModder/anpan)
|
||||||
|
|
||||||
|
## Status
|
||||||
|
[](https://goreportcard.com/report/github.com/MikeModder/disgoman)
|
||||||
|
|
||||||
|
##
|
||||||
@ -0,0 +1,183 @@
|
|||||||
|
package disgoman
|
||||||
|
|
||||||
|
/* command-manager.go
|
||||||
|
* The main command manager code
|
||||||
|
*
|
||||||
|
* Disgoman (c) 2020 Dusty.P/dustinpianalto
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/kballard/go-shellquote"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *CommandManager) AddCommand(name string, aliases []string, desc string, ownerOnly, hidden bool, perms Permission, command CommandInvokeFunc) error {
|
||||||
|
if _, ok := c.Commands[name]; ok {
|
||||||
|
return errors.New(fmt.Sprintf("A command named %v already exists", name))
|
||||||
|
}
|
||||||
|
for _, alias := range aliases {
|
||||||
|
if _, ok := c.Aliases[alias]; ok {
|
||||||
|
return errors.New(fmt.Sprintf("An alias named %v already exists", alias))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.Commands[name] = &Command{
|
||||||
|
Name: name,
|
||||||
|
Description: desc,
|
||||||
|
OwnerOnly: ownerOnly,
|
||||||
|
Hidden: hidden,
|
||||||
|
RequiredPermissions: perms,
|
||||||
|
Invoke: command,
|
||||||
|
}
|
||||||
|
if len(aliases) > 0 {
|
||||||
|
for _, alias := range aliases {
|
||||||
|
c.Aliases[alias] = name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandManager) RemoveAliasesFor(name string) {
|
||||||
|
for alias, cmd := range c.Aliases {
|
||||||
|
if cmd == name {
|
||||||
|
delete(c.Aliases, alias)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandManager) RemoveCommand(name string) error {
|
||||||
|
if _, ok := c.Commands[name]; ok {
|
||||||
|
delete(c.Commands, name)
|
||||||
|
c.RemoveAliasesFor(name)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New(fmt.Sprintf("%v not in commands", name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandManager) RemoveAlias(alias string) error {
|
||||||
|
if _, ok := c.Aliases[alias]; ok {
|
||||||
|
delete(c.Aliases, alias)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New(fmt.Sprintf("%v not in aliases", alias))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandManager) IsOwner(id string) bool {
|
||||||
|
for _, o := range c.Owners {
|
||||||
|
if o == id {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandManager) OnMessage(session *discordgo.Session, m *discordgo.MessageCreate) {
|
||||||
|
if m.Author.Bot && c.IgnoreBots {
|
||||||
|
return // If the author is a bot and ignore bots is set then just exit
|
||||||
|
}
|
||||||
|
|
||||||
|
content := m.Content
|
||||||
|
|
||||||
|
prefixes := c.Prefixes(m.GuildID)
|
||||||
|
var prefix string
|
||||||
|
for _, prefix = range prefixes {
|
||||||
|
if strings.HasPrefix(content, prefix) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if prefix == "" {
|
||||||
|
return // If we didn't find a valid prefix then exit
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found our prefix then remove it and split the command into pieces
|
||||||
|
cmd, err := shellquote.Split(strings.TrimPrefix(content, prefix))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var command *Command
|
||||||
|
invoked := cmd[0]
|
||||||
|
if n, ok := c.Aliases[invoked]; ok {
|
||||||
|
if cmnd, ok := c.Commands[n]; ok {
|
||||||
|
command = cmnd
|
||||||
|
} else {
|
||||||
|
log.Fatal("Alias Not Found in Commands")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if cmnd, ok := c.Commands[invoked]; ok {
|
||||||
|
command = cmnd
|
||||||
|
} else {
|
||||||
|
log.Fatal("Command Not Found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
channel, err := session.Channel(m.ChannelID)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Couldn't retrieve Channel.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !CheckPermissions(session, *m.Member, *channel, command.RequiredPermissions) {
|
||||||
|
embed := &discordgo.MessageEmbed{
|
||||||
|
Title: "Insufficient Permissions",
|
||||||
|
Description: "You don't have the correct permissions to run this command.",
|
||||||
|
Color: 0xFF0000,
|
||||||
|
}
|
||||||
|
if !command.Hidden {
|
||||||
|
session.ChannelMessageSendEmbed(m.ChannelID, embed)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
me, err := session.GuildMember(m.GuildID, session.State.User.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !CheckPermissions(session, *me, *channel, command.RequiredPermissions) {
|
||||||
|
embed := &discordgo.MessageEmbed{
|
||||||
|
Title: "Insufficient Permissions",
|
||||||
|
Description: "I don't have the correct permissions to run this command.",
|
||||||
|
Color: 0xFF0000,
|
||||||
|
}
|
||||||
|
if !command.Hidden {
|
||||||
|
session.ChannelMessageSendEmbed(m.ChannelID, embed)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if command.OwnerOnly && !c.IsOwner(m.Author.ID) {
|
||||||
|
embed := &discordgo.MessageEmbed{
|
||||||
|
Title: "You can't run that command!",
|
||||||
|
Description: "Sorry, only the bot owner(s) can run that command!",
|
||||||
|
Color: 0xff0000,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !command.Hidden {
|
||||||
|
session.ChannelMessageSendEmbed(m.ChannelID, embed)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guild, _ := session.Guild(m.GuildID)
|
||||||
|
|
||||||
|
context := Context{
|
||||||
|
Session: session,
|
||||||
|
Channel: channel,
|
||||||
|
Message: m.Message,
|
||||||
|
User: m.Author,
|
||||||
|
Guild: guild,
|
||||||
|
Member: m.Member,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = command.Invoke(context, cmd[1:])
|
||||||
|
if err != nil && c.OnErrorFunc != nil {
|
||||||
|
c.OnErrorFunc(context, cmd[0], err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package disgoman
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* context.go:
|
||||||
|
* Utility functions for command context
|
||||||
|
*
|
||||||
|
* Disgoman (c) 2020 Dusty.P/dustinpianalto
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Send message to originating channel
|
||||||
|
func (c *Context) Send(message string) (*discordgo.Message, error) {
|
||||||
|
return c.Session.ChannelMessageSend(c.Channel.ID, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send embed to originating channel
|
||||||
|
func (c *Context) SendEmbed(embed *discordgo.MessageEmbed) (*discordgo.Message, error) {
|
||||||
|
return c.Session.ChannelMessageSendEmbed(c.Channel.ID, embed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send embed to originating channel
|
||||||
|
func (c *Context) SendFile(filename string, file io.Reader) (*discordgo.Message, error) {
|
||||||
|
return c.Session.ChannelFileSend(c.Channel.ID, filename, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Combine these to all use ChannelMessageSendComplex
|
||||||
@ -1 +1,37 @@
|
|||||||
package disgoman
|
package disgoman
|
||||||
|
|
||||||
|
/* Package Disgoman:
|
||||||
|
* Command Handler for DisgordGo.
|
||||||
|
* Inspired by:
|
||||||
|
* - Anpan (https://github.com/MikeModder/anpan)
|
||||||
|
*
|
||||||
|
* Disgoman (c) 2020 Dusty.P/dustinpianalto
|
||||||
|
*/
|
||||||
|
|
||||||
|
func GetCommandManager(prefixes PrefixesFunc, owners []string, ignoreBots, checkPerms bool) CommandManager {
|
||||||
|
return CommandManager{
|
||||||
|
Prefixes: prefixes,
|
||||||
|
Owners: owners,
|
||||||
|
StatusManager: GetDefaultStatusManager(),
|
||||||
|
Commands: make(map[string]*Command),
|
||||||
|
Aliases: make(map[string]string),
|
||||||
|
IgnoreBots: ignoreBots,
|
||||||
|
CheckPermissions: checkPerms,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStatusManager(values []string, interval string) StatusManager {
|
||||||
|
return StatusManager{
|
||||||
|
Values: values,
|
||||||
|
Interval: interval,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDefaultStatusManager() StatusManager {
|
||||||
|
return GetStatusManager(
|
||||||
|
[]string{
|
||||||
|
"Golang!",
|
||||||
|
"DiscordGo!",
|
||||||
|
"Disgoman!",
|
||||||
|
}, "10s")
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,61 @@
|
|||||||
|
package disgoman
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* status-manager.go:
|
||||||
|
* Built in status manager which cycles through a list of status at a specified interval
|
||||||
|
*
|
||||||
|
* Disgoman (c) 2020 Dusty.P/dustinpianalto
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Add a status to the manager
|
||||||
|
func (s *StatusManager) AddStatus(status string) {
|
||||||
|
s.Values = append(s.Values, status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a status from the manager
|
||||||
|
func (s *StatusManager) RemoveStatus(status string) []string {
|
||||||
|
for i, v := range s.Values {
|
||||||
|
if v == status {
|
||||||
|
s.Values = append(s.Values[:i], s.Values[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.Values
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets interval to new value
|
||||||
|
func (s *StatusManager) SetInterval(interval string) {
|
||||||
|
s.Interval = interval
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StatusManager) UpdateStatus(session *discordgo.Session) error {
|
||||||
|
i := rand.Intn(len(s.Values))
|
||||||
|
err := session.UpdateStatus(0, s.Values[i])
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StatusManager) OnReady(session *discordgo.Session, _ *discordgo.Ready) {
|
||||||
|
interval, err := time.ParseDuration(s.Interval)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.UpdateStatus(session)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ticker := time.NewTicker(interval)
|
||||||
|
for range ticker.C {
|
||||||
|
err = s.UpdateStatus(session)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package disgoman
|
||||||
|
|
||||||
|
/* structs.go
|
||||||
|
* Contains structs used in Disgoman
|
||||||
|
*
|
||||||
|
* Disgoman (c) 2020 Dusty.P/dustinpianalto
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "github.com/bwmarrin/discordgo"
|
||||||
|
|
||||||
|
type CommandManager struct {
|
||||||
|
Prefixes PrefixesFunc
|
||||||
|
Owners []string
|
||||||
|
StatusManager StatusManager
|
||||||
|
OnErrorFunc OnErrorFunc
|
||||||
|
Commands map[string]*Command
|
||||||
|
Aliases map[string]string
|
||||||
|
IgnoreBots bool
|
||||||
|
CheckPermissions bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatusManager struct {
|
||||||
|
Values []string
|
||||||
|
Interval string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
OwnerOnly bool
|
||||||
|
Hidden bool
|
||||||
|
RequiredPermissions Permission
|
||||||
|
Invoke CommandInvokeFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
Session *discordgo.Session
|
||||||
|
Channel *discordgo.Channel
|
||||||
|
Message *discordgo.Message
|
||||||
|
User *discordgo.User
|
||||||
|
Guild *discordgo.Guild
|
||||||
|
Member *discordgo.Member
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package disgoman
|
||||||
|
|
||||||
|
/* types.go
|
||||||
|
* Defines function types and other types
|
||||||
|
*
|
||||||
|
* Disgoman (c) 2020 Dusty.P/dustinpianalto
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Function to invoke for command
|
||||||
|
type CommandInvokeFunc func(Context, []string) error
|
||||||
|
|
||||||
|
// Function to get prefixes
|
||||||
|
type PrefixesFunc func(string) []string
|
||||||
|
|
||||||
|
// Function to run on command error
|
||||||
|
type OnErrorFunc func(Context, string, error)
|
||||||
|
|
||||||
|
type Permission int
|
||||||
|
|
||||||
|
// Defining permissions based on the Discord API
|
||||||
|
const (
|
||||||
|
PermissionAdministrator Permission = 8
|
||||||
|
PermissionViewAuditLog Permission = 128
|
||||||
|
PermissionViewServerInsights Permission = 524288
|
||||||
|
PermissionManageServer Permission = 32
|
||||||
|
PermissionManageRoles Permission = 268435456
|
||||||
|
PermissionManageChannels Permission = 16
|
||||||
|
PermissionKickMembers Permission = 2
|
||||||
|
PermissionBanMembers Permission = 4
|
||||||
|
PermissionCreateInstantInvite Permission = 1
|
||||||
|
PermissionChangeNickname Permission = 67108864
|
||||||
|
PermissionManageNicknames Permission = 134217728
|
||||||
|
PermissionManageEmojis Permission = 1073741824
|
||||||
|
PermissionManageWebhooks Permission = 536870912
|
||||||
|
PermissionViewChannels Permission = 1024
|
||||||
|
|
||||||
|
PermissionMessagesSend Permission = 2048
|
||||||
|
PermissionMessagesSendTTS Permission = 4096
|
||||||
|
PermissionMessagesManage Permission = 8192
|
||||||
|
PermissionMessagesEmbedLinks Permission = 16384
|
||||||
|
PermissionMessagesAttachFiles Permission = 32768
|
||||||
|
PermissionMessagesReadHistory Permission = 65536
|
||||||
|
PermissionMessagesMentionEveryone Permission = 131072
|
||||||
|
PermissionMessagesUseExternalEmojis Permission = 262144
|
||||||
|
PermissionMessagesAddReactions Permission = 64
|
||||||
|
|
||||||
|
PermissionVoiceConnect Permission = 1048576
|
||||||
|
PermissionVoiceSpeak Permission = 2097152
|
||||||
|
PermissionVoiceMuteMembers Permission = 4194304
|
||||||
|
PermissionVoiceDeafenMembers Permission = 8388608
|
||||||
|
PermissionVoiceUseMembers Permission = 16777216
|
||||||
|
PermissionVoiceUseActivity Permission = 33554432
|
||||||
|
PermissionVoicePrioritySpeaker Permission = 256
|
||||||
|
)
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
package disgoman
|
||||||
|
|
||||||
|
/* helpers.go:
|
||||||
|
* Utility functions to make my life easier.
|
||||||
|
*
|
||||||
|
* Disgoman (c) 2020 Dusty.P/dustinpianalto
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "github.com/bwmarrin/discordgo"
|
||||||
|
|
||||||
|
// Checks the channel and guild permissions to see if the member has the needed permissions
|
||||||
|
func CheckPermissions(session *discordgo.Session, member discordgo.Member, channel discordgo.Channel, perms Permission) bool {
|
||||||
|
if perms == 0 {
|
||||||
|
return true // If no permissions are required then just return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, overwrite := range channel.PermissionOverwrites {
|
||||||
|
if overwrite.ID == member.User.ID {
|
||||||
|
if overwrite.Allow&int(perms) != 0 {
|
||||||
|
return true // If the channel has an overwrite for the user then true
|
||||||
|
} else if overwrite.Deny&int(perms) != 0 {
|
||||||
|
return false // If there is an explicit deny then false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, roleID := range member.Roles {
|
||||||
|
role, err := session.State.Role(member.GuildID, roleID)
|
||||||
|
if err != nil {
|
||||||
|
return false // There is something wrong with the role, default to false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, overwrite := range channel.PermissionOverwrites {
|
||||||
|
if overwrite.ID == roleID {
|
||||||
|
if overwrite.Allow&int(perms) != 0 {
|
||||||
|
return true // If the channel has an overwrite for the role then true
|
||||||
|
} else if overwrite.Deny&int(perms) != 0 {
|
||||||
|
return false // If there is an explicit deny then false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if role.Permissions&int(PermissionAdministrator) != 0 {
|
||||||
|
return true // If they are an administrator then they automatically have all permissions
|
||||||
|
}
|
||||||
|
|
||||||
|
if role.Permissions&int(perms) != 0 {
|
||||||
|
return true // The role has the required permissions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false // Default to false
|
||||||
|
}
|
||||||
Loading…
Reference in new issue