tons of clean up, removed stuff from the upstream codebase

This commit is contained in:
vel 2021-08-21 17:39:42 -07:00
parent 8e2b31059a
commit 3376c69e86
Signed by: velvox
GPG Key ID: 1C8200C1D689CEF5
8 changed files with 300 additions and 509 deletions

View File

@ -1,7 +0,0 @@
package framework
import "testing"
func TestParseArguments(t *testing.T) {
}

View File

@ -12,7 +12,8 @@ import (
// commands.go
// This file contains everything required to add core commands to the bot, and parse commands from a message
// GroupTypes
// Group
// Defines different "groups" of commands for ordering in a help command
type Group string
var (
@ -62,14 +63,6 @@ type Command struct {
// Defines how child commands are stored
type ChildCommand map[string]map[string]Command
// CustomCommand
// A type that defines a custom command
type CustomCommand struct {
Content string // The content of the custom command. Custom commands are just special strings after all
InvokeCount int64 // How many times the command has been invoked; int64 for easier use with json
Public bool // Whether non-admins and non-mods can use this command
}
// commands
// All the registered core commands (not custom commands)
// This is private so that other commands cannot modify it
@ -174,12 +167,6 @@ func GetCommands() map[string]CommandInfo {
return list
}
// customCommandHandler
// Given a custom command, interpret and run it
func customCommandHandler(command CustomCommand, args []string, message *discordgo.Message) {
//TODO
}
// commandHandler
// This handler will be added to a *discordgo.Session, and will scan an incoming messages for commands to run
func commandHandler(session *discordgo.Session, message *discordgo.MessageCreate) {
@ -202,14 +189,6 @@ func commandHandler(session *discordgo.Session, message *discordgo.MessageCreate
if trigger == nil {
return
}
isCustom := false
if _, ok := commands[commandAliases[*trigger]]; !ok {
if !g.IsCustomCommand(*trigger) {
return
} else {
isCustom = true
}
}
// Only do further checks if the user is not a bot admin
if !IsAdmin(message.Author.ID) {
// Ignore the command if it is globally disabled
@ -217,8 +196,8 @@ func commandHandler(session *discordgo.Session, message *discordgo.MessageCreate
return
}
// Ignore the command if this channel has blocked the trigger
if g.TriggerIsDisabledInChannel(*trigger, message.ChannelID) {
// Ignore the command if this channel has blocked the command
if g.CommandIsDisabledInChannel(*trigger, message.ChannelID) {
return
}
@ -233,16 +212,11 @@ func commandHandler(session *discordgo.Session, message *discordgo.MessageCreate
}
}
if !isCustom {
//Get the command to run
// Error Checking
command, ok := commands[commandAliases[*trigger]]
if !ok {
log.Errorf("Command was not found")
if IsAdmin(message.Author.ID) {
Session.MessageReactionAdd(message.ChannelID, message.ID, "<:redtick:861413502991073281>")
Session.ChannelMessageSendReply(message.ChannelID, "<:redtick:861413502991073281> Error! Command not found!", message.MessageReference)
}
return
}
// Check if the command is public, or if the current user is a bot moderator
@ -280,7 +254,7 @@ func commandHandler(session *discordgo.Session, message *discordgo.MessageCreate
}
return
}
}
}
// -- Helper Methods

176
fs-win.go Normal file
View File

@ -0,0 +1,176 @@
//go:build windows
// +build windows
package framework
import (
"encoding/json"
"golang.org/x/sys/windows"
"io/ioutil"
"os"
"path"
"strings"
"sync"
)
// fs.go
// This file contains functions that pertain to interacting with the filesystem, including mutex locking of files
// GuildsDir
// The directory to use for reading and writing guild .json files. Defaults to ./guilds
// todo abstract this into a database module (being completed in feature/database)
var GuildsDir = ""
// saveLock
// A map that stores mutexes for each guild, which will be locked every time that guild's data is written
// This ensures files are written to synchronously, avoiding file race conditions
var saveLock = make(map[string]*sync.Mutex)
// loadGuilds
// Load all known guilds from the filesystem, from inside GuildsDir
func loadGuilds() {
// Check if the configured guild directory exists, and create it if otherwise
if _, existErr := os.Stat(GuildsDir); os.IsNotExist(existErr) {
mkErr := os.MkdirAll(GuildsDir, 0755)
if mkErr != nil {
log.Fatalf("Failed to create guild directory: %s", mkErr)
}
log.Warningf("There are no Guilds to load; data for new Guilds will be saved to: %s", GuildsDir)
// There are no guilds to load, so we can return early
return
}
// Get a list of files in the directory
files, rdErr := ioutil.ReadDir(GuildsDir)
if rdErr != nil {
log.Fatalf("Failed to read guild directory: %s", rdErr)
}
// Iterate over each file
for _, file := range files {
// Ignore directories
if file.IsDir() {
continue
}
// Get the file name, convert to lowercase so ".JSON" is also valid
fName := strings.ToLower(file.Name())
// File name must end in .json
if !strings.HasSuffix(fName, ".json") {
continue
}
// Split ".json" from the string name, and check that the remaining characters:
// - Add up to at least 17 characters (it must be a Discord snowflake)
// - Are all numbers
guildId := strings.Split(fName, ".json")[0]
if len(guildId) < 17 || guildId != EnsureNumbers(guildId) {
continue
}
// Even though we are reading files, we need to make sure we can write to this file later
fPath := path.Join(GuildsDir, fName)
fd, err := windows.Open(fPath, windows.O_RDWR, 0)
if err != nil {
log.Errorf("File \"%s\" is not writable; guild %s WILL NOT be loaded! (%s)", fPath, guildId, err)
windows.Close(fd)
continue
}
// Close file handle since we are not writing to it.
windows.Close(fd)
// Try reading the file
jsonBytes, err := ioutil.ReadFile(fPath)
if err != nil {
log.Errorf("Failed to read \"%s\"; guild %s WILL NOT be loaded! (%s)", fPath, guildId, err)
continue
}
// Unmarshal the json
var gInfo GuildInfo
err = json.Unmarshal(jsonBytes, &gInfo)
if err != nil {
log.Errorf("Failed to unmarshal \"%s\"; guild %s WILL NOT be loaded! (%s)", fPath, guildId, err)
continue
}
// Add the loaded guild to the map
Guilds[guildId] = &Guild{
ID: guildId,
Info: gInfo,
}
}
if len(Guilds) == 0 {
log.Warningf("There are no guilds to load; data for new guilds will be saved to \"%s\"", GuildsDir)
return
}
// :)
plural := ""
if len(Guilds) != 1 {
plural = "s"
}
log.Infof("Loaded %d guild%s", len(Guilds), plural)
}
// save
// Save a given guild object to .json
func (g *Guild) save() {
// See if a mutex exists for this guild, and create if not
if _, ok := saveLock[g.ID]; !ok {
saveLock[g.ID] = &sync.Mutex{}
}
// Unlock writing when done
defer saveLock[g.ID].Unlock()
// Mark this guild as locked before saving
saveLock[g.ID].Lock()
// Create the output directory if it doesn't exist
// This is a fatal error, since no other guilds would be savable if this fails
if _, err := os.Stat(GuildsDir); os.IsNotExist(err) {
mkErr := os.Mkdir(GuildsDir, 0755)
if mkErr != nil {
log.Fatalf("Failed to create guild output directory: %s", mkErr)
}
}
// Convert the guild object to text
jsonBytes, err := json.MarshalIndent(g.Info, "", " ")
if err != nil {
log.Fatalf("Failed marshalling JSON data for guild %s: %s", g.ID, err)
}
// Write the contents to a file
outPath := path.Join(GuildsDir, g.ID+".json")
err = ioutil.WriteFile(outPath, jsonBytes, 0644)
if err != nil {
log.Fatalf("Write failed to %s: %s", outPath, err)
}
}
// ReadDefaults
// TODO: WRITE DOCUMENTATION FOR THIS LMAO
func ReadDefaults(filePath string) (result []string) {
fPath := path.Clean(filePath)
if _, existErr := os.Stat(fPath); os.IsNotExist(existErr) {
log.Errorf("Failed to find \"%s\"; File WILL NOT be loaded! (%s)", fPath, existErr)
return
}
jsonBytes, err := ioutil.ReadFile(fPath)
if err != nil {
log.Errorf("Failed to read \"%s\"; File WILL NOT be loaded! (%s)", fPath, err)
return
}
err = json.Unmarshal(jsonBytes, &result)
if err != nil {
log.Errorf("Failed to unmarshal \"%s\"; File WILL NOT be loaded! (%s)", fPath, err)
}
return
}

7
fs.go
View File

@ -1,13 +1,16 @@
//go:build darwin || linux
// +build darwin linux
package framework
import (
"encoding/json"
"golang.org/x/sys/unix"
"io/ioutil"
"os"
"path"
"strings"
"sync"
"syscall"
)
// fs.go
@ -69,7 +72,7 @@ func loadGuilds() {
// Even though we are reading files, we need to make sure we can write to this file later
fPath := path.Join(GuildsDir, fName)
err := syscall.Access(fPath, syscall.O_RDWR)
err := unix.Access(fPath, unix.O_RDWR)
if err != nil {
log.Errorf("File \"%s\" is not writable; guild %s WILL NOT be loaded! (%s)", fPath, guildId, err)
continue

407
guilds.go
View File

@ -3,38 +3,29 @@ package framework
import (
"errors"
"strings"
"sync"
"time"
"github.com/bwmarrin/discordgo"
)
// guilds.go
// This file contains the structure of a guild, and all of the functions used to store and retrieve guild information
// This file contains the structure of a guild, and all the functions used to store and retrieve guild information
// GuildInfo
// This is all of the settings and data that needs to be stored about a single guild
// This is all the settings and data that needs to be stored about a single guild
type GuildInfo struct {
AddedDate int64 `json:"addedDate"` // The date the bot was added to the server
Prefix string `json:"prefix"` // The bot prefix
GuildLanguage string `json:"guildLanguage"` // Guilds default language todo make language per user
ModeratorIds []string `json:"moderatorIds"` // The list of user/role IDs allowed to run mod-only commands
WhitelistIds []string `json:"whitelistIds"` // List of user/role Ids that a user MUST have one of in order to run any commands, including public ones
IgnoredIds []string `json:"ignoredIds"` // List of user/role IDs that can never run commands, even public ones
WhitelistedChannels []string `json:"whitelistedChannels"` // List of channel IDs of whitelisted channels. If this list is non-empty, then only channels in this list can be used to invoke commands (unless the invoker is a bot moderator)
IgnoredChannels []string `json:"ignoredChannels"` // A list of channel IDs where commands will always be ignored, unless the user is a bot admin
BannedWordDetector bool `json:"banned_word_detector"` // Whether or not to detect banned words
GuildBannedWords []string `json:"guild_banned_words"` // List of banned words and phrases in this guild. Can use a command to update list.
BannedWordDetectorRoles []string `json:"banned_word_detector_roles"` // List of roles that the bot will not ignore
BannedWordDetectorChannels []string `json:"banned_word_detector_channels"` // List of channels that the bot will detect
GlobalDisabledTriggers []string `json:"globalDisabledTriggers"` // List of BotCommand triggers that can't be used anywhere in this guild
ChannelDisabledTriggers map[string][]string `json:"channelDisabledTriggers"` // List of channel IDs and the list of triggers that can't be used in it
CustomCommands map[string]CustomCommand `json:"customCommands"` // The list of triggers and their corresponding outputs for custom commands
DeletePolicy bool `json:"deletePolicy"` // Whether or not to delete BotCommand messages after a user sends them
ResponseChannelId string `json:"responseChannelId"` // The channelID of the channel to use for responses by default
MuteRoleId string `json:"muteRoleId"` // The role ID of the Mute role
MutedUsers map[string]int64 `json:"mutedUsers"` // The list of muted users, and the Unix timestamp of when their mute expired
Storage map[string]interface{} `json:"storage"` // Generic storage available to store anything not specific to the core bot
AddedDate int64 `json:"added_date"`
ChannelDisabledCommands map[string][]string `json:"channel_disabled_commands"`
DeletePolicy bool `json:"delete_policy"`
GlobalDisabledCommands []string `json:"global_disabled_commands"`
IgnoredChannels []string `json:"ignored_channels"`
IgnoredIds []string `json:"ignored_ids"`
ModeratorIds []string `json:"moderator_ids"`
Prefix string `json:"prefix,"`
ResponseChannelId string `json:"response_channel_id"`
Storage map[string]interface{} `json:"storage"`
WhitelistedChannels []string `json:"whitelisted_channels"`
WhitelistIds []string `json:"whitelist_ids"`
}
// Guild
@ -50,10 +41,6 @@ type Guild struct {
// Otherwise, there will be information desync
var Guilds = make(map[string]*Guild)
// muteLock
// A map to store mutexes for handling mutes for a server synchronously
var muteLock = make(map[string]*sync.Mutex)
// getGuild
// Return a Guild object corresponding to the given guildId
// If the guild doesn't exist, initialize a new guild and save it before returning
@ -65,22 +52,17 @@ func getGuild(guildId string) *Guild {
ID: "",
Info: GuildInfo{
AddedDate: time.Now().Unix(),
Prefix: "!",
ChannelDisabledCommands: nil,
DeletePolicy: false,
GuildLanguage: "en",
ResponseChannelId: "",
MuteRoleId: "",
GlobalDisabledTriggers: nil,
ChannelDisabledTriggers: make(map[string][]string),
CustomCommands: make(map[string]CustomCommand),
ModeratorIds: nil,
GlobalDisabledCommands: nil,
IgnoredChannels: nil,
IgnoredIds: nil,
BannedWordDetector: false,
GuildBannedWords: nil,
BannedWordDetectorRoles: nil,
BannedWordDetectorChannels: nil,
MutedUsers: make(map[string]int64),
ModeratorIds: nil,
Prefix: "!",
ResponseChannelId: "",
Storage: make(map[string]interface{}),
WhitelistedChannels: nil,
WhitelistIds: nil,
},
}
}
@ -92,22 +74,17 @@ func getGuild(guildId string) *Guild {
ID: guildId,
Info: GuildInfo{
AddedDate: time.Now().Unix(),
Prefix: "!",
ChannelDisabledCommands: nil,
DeletePolicy: false,
GuildLanguage: "en",
ResponseChannelId: "",
MuteRoleId: "",
GlobalDisabledTriggers: nil,
ChannelDisabledTriggers: make(map[string][]string),
CustomCommands: make(map[string]CustomCommand),
ModeratorIds: nil,
GlobalDisabledCommands: nil,
IgnoredChannels: nil,
IgnoredIds: nil,
BannedWordDetector: false,
GuildBannedWords: nil,
BannedWordDetectorRoles: nil,
BannedWordDetectorChannels: nil,
MutedUsers: make(map[string]int64),
ModeratorIds: nil,
Prefix: "!",
ResponseChannelId: "",
Storage: make(map[string]interface{}),
WhitelistedChannels: nil,
WhitelistIds: nil,
},
}
// Add the new guild to the map of guilds
@ -280,13 +257,6 @@ func (g *Guild) SetPrefix(newPrefix string) {
g.save()
}
// SetLang
// Set the prefix, then save the guild data
func (g *Guild) SetLang(lang string) {
g.Info.GuildLanguage = lang
g.save()
}
// IsMod
// Check if a given ID is a moderator or not
func (g *Guild) IsMod(checkId string) bool {
@ -611,9 +581,9 @@ func (g *Guild) RemoveChannelFromIgnored(channelId string) error {
}
// IsGloballyDisabled
// Check if a given trigger is globally disabled
// Check if a given command is globally disabled
func (g *Guild) IsGloballyDisabled(trigger string) bool {
for _, disabled := range g.Info.GlobalDisabledTriggers {
for _, disabled := range g.Info.GlobalDisabledCommands {
if strings.ToLower(disabled) == strings.ToLower(trigger) {
return true
}
@ -622,33 +592,33 @@ func (g *Guild) IsGloballyDisabled(trigger string) bool {
return false
}
// EnableTriggerGlobally
// Remove a trigger from the list of *globally disabled* triggers
func (g *Guild) EnableTriggerGlobally(trigger string) error {
// EnableCommandGlobally
// Remove a command from the list of *globally disabled* triggers
func (g *Guild) EnableCommandGlobally(trigger string) error {
if !g.IsGloballyDisabled(trigger) {
return errors.New("trigger is not disabled; nothing to enable")
}
g.Info.GlobalDisabledTriggers = RemoveItem(g.Info.GlobalDisabledTriggers, trigger)
g.Info.GlobalDisabledCommands = RemoveItem(g.Info.GlobalDisabledCommands, trigger)
g.save()
return nil
}
// DisableTriggerGlobally
// Add a trigger to the list of *globally disabled* triggers
func (g *Guild) DisableTriggerGlobally(trigger string) error {
if g.IsGloballyDisabled(trigger) {
return errors.New("trigger is not enabled; nothing to disable")
// DisableCommandGlobally
// Add a command to the list of *globally disabled* commands
func (g *Guild) DisableCommandGlobally(command string) error {
if g.IsGloballyDisabled(command) {
return errors.New("command is not enabled; nothing to disable")
}
g.Info.GlobalDisabledTriggers = append(g.Info.GlobalDisabledTriggers, trigger)
g.Info.GlobalDisabledCommands = append(g.Info.GlobalDisabledCommands, command)
g.save()
return nil
}
// TriggerIsDisabledInChannel
// Check if a given trigger is disabled in the given channel
func (g *Guild) TriggerIsDisabledInChannel(trigger string, channelId string) bool {
// CommandIsDisabledInChannel
// Check if a given command is disabled in the given channel
func (g *Guild) CommandIsDisabledInChannel(command string, channelId string) bool {
cleanedId := CleanId(channelId)
if cleanedId == "" {
return true
@ -659,16 +629,16 @@ func (g *Guild) TriggerIsDisabledInChannel(trigger string, channelId string) boo
}
// Iterate over every channel ID (the map key) and their internal list of disabled triggers
for channel, triggers := range g.Info.ChannelDisabledTriggers {
for channel, commands := range g.Info.ChannelDisabledCommands {
// If the channel matches our current channel, continue
if channel == cleanedId {
// For every disabled trigger in the list...
for _, disabled := range triggers {
for _, disabled := range commands {
// If the current trigger matches a disabled one, return true
if disabled == trigger {
if disabled == command {
return true
}
}
@ -678,83 +648,43 @@ func (g *Guild) TriggerIsDisabledInChannel(trigger string, channelId string) boo
return false
}
// EnableTriggerInChannel
// Given a trigger and channel ID, remove that trigger from that channel's list of blocked triggers
func (g *Guild) EnableTriggerInChannel(trigger string, channelId string) error {
// EnableCommandInChannel
// Given a command and channel ID, remove that command from that channel's list of blocked comamnds
func (g *Guild) EnableCommandInChannel(command string, channelId string) error {
cleanedId := CleanId(channelId)
if cleanedId == "" {
return errors.New("provided channel ID is invalid")
}
if !g.TriggerIsDisabledInChannel(trigger, cleanedId) {
return errors.New("that trigger is not disabled in this channel; nothing to enable")
if !g.CommandIsDisabledInChannel(command, cleanedId) {
return errors.New("that command is not disabled in this channel; nothing to enable")
}
// Remove the trigger from THIS channel's list
g.Info.ChannelDisabledTriggers[cleanedId] = RemoveItem(g.Info.ChannelDisabledTriggers[cleanedId], trigger)
g.Info.ChannelDisabledCommands[cleanedId] = RemoveItem(g.Info.ChannelDisabledCommands[cleanedId], command)
// If there are no more items, delete the entire channel list, otherwise it will appear as null in the json
if len(g.Info.ChannelDisabledTriggers[cleanedId]) == 0 {
delete(g.Info.ChannelDisabledTriggers, cleanedId)
if len(g.Info.ChannelDisabledCommands[cleanedId]) == 0 {
delete(g.Info.ChannelDisabledCommands, cleanedId)
}
g.save()
return nil
}
// DisableTriggerInChannel
// Given a trigger and channel ID, add that trigger to that channel's list of blocked triggers
func (g *Guild) DisableTriggerInChannel(trigger string, channelId string) error {
// DisableCommandInChannel
// Given a command and channel ID, add that command to that channel's list of blocked commands
func (g *Guild) DisableTriggerInChannel(command string, channelId string) error {
cleanedId := CleanId(channelId)
if cleanedId == "" {
return errors.New("provided channel ID is invalid")
}
if g.TriggerIsDisabledInChannel(trigger, cleanedId) {
if g.CommandIsDisabledInChannel(command, cleanedId) {
return errors.New("that trigger is already disabled in this channel; nothing to disable")
}
g.Info.ChannelDisabledTriggers[cleanedId] = append(g.Info.ChannelDisabledTriggers[cleanedId], trigger)
g.save()
return nil
}
// IsCustomCommand
// Check if a given trigger is a custom command in this guild
func (g *Guild) IsCustomCommand(trigger string) bool {
if _, ok := g.Info.CustomCommands[strings.ToLower(trigger)]; ok {
return true
}
return false
}
// AddCustomCommand
// Add a custom command to this guild
func (g *Guild) AddCustomCommand(trigger string, content string, public bool) error {
if g.IsCustomCommand(trigger) {
return errors.New("the provided trigger is already a custom command")
}
if _, ok := commands[trigger]; ok {
return errors.New("custom command would have overridden a core command")
}
g.Info.CustomCommands[trigger] = CustomCommand{
Content: content,
InvokeCount: 0,
Public: public,
}
g.save()
return nil
}
// RemoveCustomCommand
// Remove a custom command from this guild
func (g *Guild) RemoveCustomCommand(trigger string) error {
if !g.IsCustomCommand(trigger) {
return errors.New("the provided trigger is not a custom command")
}
delete(g.Info.CustomCommands, trigger)
g.Info.ChannelDisabledCommands[cleanedId] = append(g.Info.ChannelDisabledCommands[cleanedId], command)
g.save()
return nil
}
@ -785,116 +715,6 @@ func (g *Guild) SetResponseChannel(channelId string) error {
return nil
}
// SetMuteRole
// Set the role ID to use for issuing mutes, then save the guild data
func (g *Guild) SetMuteRole(roleId string) error {
// Try grabbing the role first (we don't use IsRole since we need the real ID)
role, err := g.GetRole(roleId)
if err != nil {
return err
}
g.Info.MuteRoleId = role.ID
g.save()
return nil
}
// HasMuteRecord
// Check if a member with a given ID has a mute record
// To check if they are actually muted, use g.HasRole
func (g *Guild) HasMuteRecord(userId string) bool {
// Check if the member exists
member, err := g.GetMember(userId)
if err != nil {
return false
}
// Check if the member is in the list of mutes
if _, ok := g.Info.MutedUsers[member.User.ID]; ok {
return true
}
return false
}
// Mute
// Mute a user for the specified duration, apply the mute role, and write a mute record to the guild info
func (g *Guild) Mute(userId string, duration int64) error {
// Make sure the mute role exists
muteRole, err := g.GetRole(g.Info.MuteRoleId)
if err != nil {
return err
}
// Make sure the member exists
member, err := g.GetMember(userId)
if err != nil {
return err
}
// Create a mute mutex for this guild if it does not exist
if _, ok := muteLock[g.ID]; !ok {
muteLock[g.ID] = &sync.Mutex{}
}
// Lock this guild's mute activity so there is no desync
defer muteLock[g.ID].Unlock()
muteLock[g.ID].Lock()
// Try muting the member
err = Session.GuildMemberRoleAdd(g.ID, member.User.ID, muteRole.ID)
if err != nil {
return err
}
// If the duration is not 0 (indefinite mute), add the current time to the duration
if duration != 0 {
duration += time.Now().Unix()
}
// Record this mute record
g.Info.MutedUsers[member.User.ID] = duration
g.save()
return nil
}
// UnMute
// Unmute a user; expiry checks will not be done here, this is a direct unmute
func (g *Guild) UnMute(userId string) error {
// Make sure the mute role exists
muteRole, err := g.GetRole(g.Info.MuteRoleId)
if err != nil {
return err
}
// Make sure the member exists
member, err := g.GetMember(userId)
if err != nil {
return err
}
// Create a mute mutex for this guild if it does not exist
if _, ok := muteLock[g.ID]; !ok {
muteLock[g.ID] = &sync.Mutex{}
}
// Lock this guild's mute activity so there is no desync
defer muteLock[g.ID].Unlock()
muteLock[g.ID].Lock()
// Delete the mute record if it exists
delete(g.Info.MutedUsers, member.User.ID)
g.save()
// Try unmuting the user
err = Session.GuildMemberRoleRemove(g.ID, member.User.ID, muteRole.ID)
if err != nil {
return err
}
return nil
}
// Kick
// Kick a member
func (g *Guild) Kick(userId string, reason string) error {
@ -1133,108 +953,3 @@ func (g *Guild) GetCommandUsage(cmd CommandInfo) string {
}
return "```\n" + output + "\n```"
}
// IsSniperEnabled
// Checks to see if the sniper module is enabled
func (g *Guild) IsSniperEnabled() bool {
return g.Info.BannedWordDetector
}
// IsSnipeable
// Checks to see if the sniper module can snipe this role
func (g *Guild) IsSnipeable(authorID string) bool {
if Session.State.Ready.User != nil && authorID == Session.State.Ready.User.ID {
return false
}
if g.MemberOrRoleInList(authorID, g.Info.BannedWordDetectorRoles) {
return false
}
return true
}
// IsSniperChannel
// Checks to see if the channel is in the channel list
func (g *Guild) IsSniperChannel(channelID string) bool {
for _, id := range g.Info.BannedWordDetectorChannels {
if id == channelID {
return true
}
}
return false
}
// SetSniper
// Sets the state of the sniper
func (g *Guild) SetSniper(value bool) bool {
g.Info.BannedWordDetector = value
g.save()
return value
}
// BulkAddWords
// Allows you to bulk add words to the banned word detector
func (g *Guild) BulkAddWords(words []string) []string {
g.Info.GuildBannedWords = append(g.Info.GuildBannedWords, words...)
g.save()
return g.Info.GuildBannedWords
}
// AddWord
// Allows you to add a word to the banned word detector
func (g *Guild) AddWord(word string) []string {
g.Info.GuildBannedWords = append(g.Info.GuildBannedWords, word)
g.save()
return g.Info.GuildBannedWords
}
// RemoveWord
// Allows you to remove a word from the banned word detector
func (g *Guild) RemoveWord(word string) []string {
g.Info.GuildBannedWords = RemoveItem(g.Info.GuildBannedWords, word)
g.save()
return g.Info.GuildBannedWords
}
// SetSniperRole
// Allows you to add a role to the sniper
func (g *Guild) SetSniperRole(roleID string) []string {
if g.IsRole(roleID) {
g.Info.BannedWordDetectorRoles = append(g.Info.BannedWordDetectorRoles, roleID)
g.save()
return g.Info.BannedWordDetectorRoles
}
return g.Info.BannedWordDetectorRoles
}
// SetSniperChannel
// Allows you to add a channel to the sniper
func (g *Guild) SetSniperChannel(channelID string) []string {
if g.IsChannel(channelID) {
g.Info.BannedWordDetectorChannels = append(g.Info.BannedWordDetectorChannels, channelID)
g.save()
return g.Info.BannedWordDetectorChannels
}
return g.Info.BannedWordDetectorChannels
}
// UnsetSniperRole
// Allows you to remove a role from the sniper
func (g *Guild) UnsetSniperRole(roleID string) []string {
if g.IsRole(roleID) {
g.Info.BannedWordDetectorRoles = RemoveItem(g.Info.BannedWordDetectorRoles, roleID)
g.save()
return g.Info.BannedWordDetectorRoles
}
return g.Info.BannedWordDetectorRoles
}
// UnsetSniperChannel
// Allows you to remove a channel from the sniper
func (g *Guild) UnsetSniperChannel(channelID string) []string {
if g.IsChannel(channelID) {
g.Info.BannedWordDetectorChannels = RemoveItem(g.Info.BannedWordDetectorChannels, channelID)
g.save()
return g.Info.BannedWordDetectorChannels
}
return g.Info.BannedWordDetectorChannels
}

View File

@ -117,8 +117,8 @@ func handleInteractionCommand(s *discordgo.Session, i *discordgo.InteractionCrea
return
}
// Ignore the command if this channel has blocked the trigger
if g.TriggerIsDisabledInChannel(trigger, i.ChannelID) {
// Ignore the command if this channel has blocked the command
if g.CommandIsDisabledInChannel(trigger, i.ChannelID) {
ErrorResponse(i.Interaction, "Command is disabled in this channel!", trigger)
return
}

View File

@ -1,7 +1,6 @@
package framework
import (
"fmt"
"time"
"github.com/bwmarrin/discordgo"
@ -94,72 +93,6 @@ func NewResponse(ctx *Context, messageComponents bool, ephemeral bool) *Response
})
}
}
// If the command context is not empty, append the command
if ctx.Cmd.Trigger != "" {
// Get the command used as a string, and all interpreted arguments, so it can be a part of the output
commandUsed := ""
if r.Ctx.Cmd.IsChild {
commandUsed = fmt.Sprintf("%s%s %s", r.Ctx.Guild.Info.Prefix, r.Ctx.Cmd.ParentID, r.Ctx.Cmd.Trigger)
} else {
commandUsed = r.Ctx.Guild.Info.Prefix + r.Ctx.Cmd.Trigger
}
// Just makes the thing prettier
if ctx.Interaction != nil {
commandUsed = "/" + r.Ctx.Cmd.Trigger
}
for _, k := range r.Ctx.Cmd.Arguments.Keys() {
arg := ctx.Args[k]
if arg.StringValue() == "" {
continue
}
vv, ok := r.Ctx.Cmd.Arguments.Get(k)
if ok {
argInfo := vv.(*ArgInfo)
switch argInfo.TypeGuard {
case Int:
fallthrough
case Boolean:
fallthrough
case String:
commandUsed += " " + arg.StringValue()
break
case User:
user, err := arg.UserValue(Session)
if err != nil {
commandUsed += " " + arg.StringValue()
} else {
commandUsed += " " + user.Mention()
}
case Role:
role, err := arg.RoleValue(Session, r.Ctx.Guild.ID)
if err != nil {
commandUsed += " " + arg.StringValue()
} else {
commandUsed += " " + role.Mention()
}
case Channel:
channel, err := arg.ChannelValue(Session)
if err != nil {
commandUsed += " " + arg.StringValue()
} else {
commandUsed += " " + channel.Mention()
}
}
} else {
commandUsed += " " + arg.StringValue()
}
}
commandUsed = "```\n" + commandUsed + "\n```"
r.AppendField("Command used:", commandUsed, false)
}
// If the message is not nil, append an invoker
if ctx.Message != nil {
r.AppendField("Invoked by:", r.Ctx.Message.Author.Mention(), false)
}
return r
}
@ -441,9 +374,6 @@ func ErrorResponse(i *discordgo.Interaction, errorMsg string, trigger string) {
func (r *Response) AcknowledgeInteraction() {
Session.InteractionRespond(r.Ctx.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "<:loadingdots:759625992166965288>",
},
})
r.Loading = true
}

View File

@ -89,10 +89,10 @@ func CleanId(in string) string {
}
// ExtractCommand
// Given a message, attempt to extract a command trigger and command arguments out of it
// Given a message, attempt to extract a commands trigger and command arguments out of it
// If there is no prefix, try using a bot mention as the prefix
func ExtractCommand(guild *GuildInfo, message string) (*string, *string) {
// Check if the message starts with the bot trigger
// Check if the message starts with the bot prefix
if strings.HasPrefix(message, guild.Prefix) {
// Split the message on the prefix, but ensure only 2 fields are returned
// This ensures messages containing multiple instances of the prefix don't split multiple times