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:
|
||||
* 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