Create Scuzzy

Features: Hastily add usercolor feature
Main: Show prefix in bot status
Features: add cat
Main/Features/Auth: Add basic Role Name/ID based command authentication and bot configuration.
Main: Sanity check for missing flags.
Features: Implement command deletion and tag-responses
Misc: Add cmd/main to .gitignore
Misc: Delete built binary
Main: Refactor main.go
- Use log.Fatal instead of fmt.Printf and os.Exit
- Move Config reading into seperate function
- Parse command line flags in main()
- Instantiate Features.go struct inside main()
- Use simple ticker to set bot status every 15 minutes
Auth: Refactor auth
- Return early when building Admin role list
- Move CheckAdminrole() into auth.go, remove roles.go
Features: Refactor features
- Remove New() function
- Move help.go, ping.go functionality into misc.go
Features: Add bot control feature to set status.
Features: Implement helper function for embeds, return errors.
Main: Rename config file to bot_config.json
Features: Use success embed for user color.
Features: Add purge messages feature.
Main: Add status_text property to config, use it for Bot Status.
Features: Send welcome message to new users, implement auto-join roles.
Main: Use complex user status
Main: Reduce ticker interval to 10 minutes for bot status update.
Main: Create helper function for complex custom embeds.
Features: Implement info command.
Features: Convert requested user color to lowercase.
Features: Add markdown helper
Features: Fix markdown helper typo
Features: Use error embed for handleSetStatus incorrect permissions.
Features: Add strikethrough and spoilers information to markdown info.
Features: Add info and md to help text.
Features: Use backtick instead of single quote for command prefix in help text.
Features: Remove markdown info message after 15 seconds.
Features: Fix typo in status setting permission error.
Features: Add commands to convert between Celsius and Farenheit
Features: Update help to include temperature conversion commands.
Features/Models/Main: Load color roles from JSON config.
Auth/Main/Features/Models: Implement config-based channel white/blacklisting.
Main/Models: Remove unused admin_only config field.
Features: Simplify error handling.
Auth: Remove leftover AdminOnly field.
Features: Use command restriction for usercolor commands.
Main: Update default config to restrict color and colors commands.
Auth/Features: Return true for undefined commands in restrictions list by default.
Features: Use better error messages for channel white/blacklist
Auth: Improve channel white/blacklist behavior.
Main: Replace broken ticker for status updates
Features: Get bot avatar via Discord for embed.
Features: Delete requesting message for markdown info.
Features: Handle potential error in deleting help requester message.
master
Marc Egerton 2020-04-11 15:16:09 +01:00
commit d54d2bb812
13 changed files with 973 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.idea/
main
cmd/main

92
auth/auth.go Normal file
View File

@ -0,0 +1,92 @@
package auth
import (
"github.com/bwmarrin/discord.go"
"github.com/foxtrot/scuzzy/models"
"strings"
)
type AdminRole struct {
Name string
ID string
}
type Auth struct {
AdminRoles []AdminRole
CommandRestrictions []models.CommandRestriction
Guild *discordgo.Guild
Config *models.Configuration
}
func New(config *models.Configuration, guild *discordgo.Guild) *Auth {
var ars []AdminRole
for _, gRole := range guild.Roles {
for _, aRole := range config.AdminRoles {
if aRole != gRole.Name {
continue
}
ar := AdminRole{
Name: gRole.Name,
ID: gRole.ID,
}
ars = append(ars, ar)
}
}
var crs []models.CommandRestriction
for _, cRes := range config.CommandRestrictions {
cr := models.CommandRestriction{
Command: cRes.Command,
Mode: cRes.Mode,
Channels: cRes.Channels,
}
crs = append(crs, cr)
}
return &Auth{
AdminRoles: ars,
CommandRestrictions: crs,
Config: config,
Guild: guild,
}
}
func (a *Auth) CheckAdminRole(m *discordgo.Member) bool {
for _, aR := range a.AdminRoles {
for _, mID := range m.Roles {
if aR.ID == mID {
return true
}
}
}
return false
}
func (a *Auth) CheckCommandRestrictions(m *discordgo.MessageCreate) bool {
cName := strings.Split(m.Content, " ")[0]
cName = strings.Replace(cName, a.Config.CommandKey, "", 1)
cChanID := m.ChannelID
for _, cR := range a.CommandRestrictions {
if cName == cR.Command {
for _, cID := range cR.Channels {
if cID == cChanID && cR.Mode == "white" {
return true
} else if cID == cChanID && cR.Mode == "black" {
return false
}
}
if cR.Mode == "white" {
return false
} else {
return true
}
}
}
return true
}

24
cmd/bot_config.json Normal file
View File

@ -0,0 +1,24 @@
{
"guild_id": "506629366659153951",
"status_text": ".help",
"welcome_text": "Hi! Welcome to the Hak5 Discord Server. Please be sure to check out the #rules channel and say hello in #general!",
"command_key": ".",
"admin_roles": ["Admin", "Moderator"],
"join_role_ids": ["697929841638637778"],
"command_restrictions": [
{ "command": "color", "mode": "white", "channels": ["698567678025138277", "698519835532984470"] },
{ "command": "colors", "mode": "white", "channels": ["698567678025138277", "698519835532984470"] }
],
"color_roles": [
{ "color": "red", "id": "697930042491142174" },
{ "color": "blue", "id": "697930093766639699" },
{ "color": "green", "id": "697930441939877970" },
{ "color": "purple", "id": "697930578485444610" },
{ "color": "yellow", "id": "697930630247350402" },
{ "color": "pink", "id": "697965484313935966" }
]
}

134
cmd/main.go Normal file
View File

@ -0,0 +1,134 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"github.com/foxtrot/scuzzy/auth"
"github.com/foxtrot/scuzzy/features"
"github.com/foxtrot/scuzzy/models"
"io/ioutil"
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/bwmarrin/discord.go"
)
// Core Bot Properties
var (
Token string
ConfigPath string
Config models.Configuration
)
func getConfig() error {
cf, err := ioutil.ReadFile(ConfigPath)
if err != nil {
return err
}
err = json.Unmarshal(cf, &Config)
if err != nil {
return err
}
return nil
}
func main() {
// Parse and Check Flags
flag.StringVar(&Token, "t", "", "Bot Token")
flag.StringVar(&ConfigPath, "c", "", "Config Path")
flag.Parse()
if len(Token) == 0 {
log.Fatal("Error: No Auth Token supplied.")
}
if len(ConfigPath) == 0 {
log.Fatal("Error: No Config Path supplied.")
}
// Get Config
err := getConfig()
if err != nil {
log.Fatal("Error: " + err.Error())
}
// Instantiate Bot
bot, err := discordgo.New("Bot " + Token)
if err != nil {
log.Fatal("Error: " + err.Error())
}
// Open Connection
err = bot.Open()
if err != nil {
log.Fatal("Error: " + err.Error())
}
// Setup Auth
Config.Guild, err = bot.Guild(Config.GuildID)
if err != nil {
log.Fatal("Error: " + err.Error())
}
var a *auth.Auth
a = auth.New(&Config, Config.Guild)
// Setup Handlers
f := features.Features{
Token: Token,
Auth: a,
Config: Config,
}
// Register Handlers
bot.AddHandler(f.OnMessageCreate)
bot.AddHandler(f.OnUserJoin)
fmt.Println("Bot Running.")
// Set Bot Status
go func() {
usd := discordgo.UpdateStatusData{
IdleSince: nil,
Game: &discordgo.Game{
Name: Config.StatusText,
Type: 0,
URL: "",
Details: "",
State: "",
TimeStamps: discordgo.TimeStamps{},
Assets: discordgo.Assets{},
ApplicationID: "",
Instance: -1,
},
AFK: false,
Status: "online",
}
err = bot.UpdateStatusComplex(usd)
if err != nil {
log.Fatal("Error: " + err.Error())
}
// For some reason the bot's status will regularly disappear...
for _ = range time.Tick(10 * time.Minute) {
err := bot.UpdateStatusComplex(usd)
if err != nil {
log.Fatal("Error: " + err.Error())
}
}
}()
// Catch SIGINT
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGKILL)
<-sc
err = bot.Close()
if err != nil {
log.Fatal("Error: " + err.Error())
}
}

33
features/bot.go Normal file
View File

@ -0,0 +1,33 @@
package features
import (
"errors"
discordgo "github.com/bwmarrin/discord.go"
"strings"
)
func (f *Features) handleSetStatus(s *discordgo.Session, m *discordgo.MessageCreate) error {
if !f.Auth.CheckAdminRole(m.Member) {
return errors.New("You do not have permissions to use that command.")
}
stSplit := strings.SplitN(m.Content, " ", 2)
if len(stSplit) < 2 {
return errors.New("You did not specify a status.")
}
st := stSplit[1]
err := s.UpdateStatus(0, st)
if err != nil {
return err
}
msg := f.CreateDefinedEmbed("Set Status", "Operation completed successfully.", "success")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, msg)
if err != nil {
return err
}
return nil
}

12
features/features.go Normal file
View File

@ -0,0 +1,12 @@
package features
import (
"github.com/foxtrot/scuzzy/auth"
"github.com/foxtrot/scuzzy/models"
)
type Features struct {
Token string
Auth *auth.Auth
Config models.Configuration
}

171
features/handlers.go Normal file
View File

@ -0,0 +1,171 @@
package features
import (
"github.com/bwmarrin/discord.go"
"log"
"strings"
)
func (f *Features) OnMessageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
var err error
// Ignore the bot itself
if m.Author.ID == s.State.User.ID {
return
}
cKey := f.Config.CommandKey
cName := strings.Split(m.Content, " ")[0]
if !strings.HasPrefix(cName, cKey) {
return
}
switch cName {
/* Misc Commands */
case cKey + "help":
err = f.handleHelp(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (Help)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
break
case cKey + "info":
err = f.handleInfo(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (Info)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
break
case cKey + "ping":
err = f.handlePing(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (Ping)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
break
case cKey + "no":
err = f.handleCat(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (No)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
break
case cKey + "md":
err = f.handleMarkdownInfo(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (Markdown)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
break
case cKey + "ctof":
err = f.handleCtoF(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (CtoF)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
break
case cKey + "ftoc":
err = f.handleFtoC(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (FtoC)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
break
/* Moderation */
case cKey + "purge":
err = f.handlePurgeChannel(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (Purge)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
/* Bot Control */
case cKey + "status":
err = f.handleSetStatus(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (Status)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
/* Role Colors */
case cKey + "colors":
err = f.listUserColors(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (Colors)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
break
case cKey + "color":
err = f.setUserColor(s, m)
if err != nil {
eMsg := f.CreateDefinedEmbed("Error (Color)", err.Error(), "error")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, eMsg)
if err != nil {
log.Fatal(err.Error())
}
return
}
break
}
}
func (f *Features) OnUserJoin(s *discordgo.Session, m *discordgo.GuildMemberAdd) {
userChannel, err := s.UserChannelCreate(m.User.ID)
if err != nil {
log.Print("Error (User Join): " + err.Error())
return
}
_, err = s.ChannelMessageSend(userChannel.ID, f.Config.WelcomeText)
if err != nil {
log.Print("Error (User Join): " + err.Error())
return
}
for _, roleID := range f.Config.JoinRoleIDs {
err = s.GuildMemberRoleAdd(f.Auth.Guild.ID, m.User.ID, roleID)
if err != nil {
log.Print("Error (User Join)" + err.Error())
return
}
}
}

94
features/helpers.go Normal file
View File

@ -0,0 +1,94 @@
package features
import (
"fmt"
discordgo "github.com/bwmarrin/discord.go"
"github.com/foxtrot/scuzzy/models"
)
func (f *Features) PrintError(component string, error string) {
fmt.Printf("Error: %s: %s\n", component, error)
}
func (f *Features) CreateDefinedEmbed(title string, desc string, status string) *discordgo.MessageEmbed {
msgColor := 0x000000
switch status {
case "error":
msgColor = 0xCC0000
break
case "success":
msgColor = 0x00CC00
break
default:
msgColor = 0xFFA500
}
ftr := discordgo.MessageEmbedFooter{
Text: "Something broken? Tell foxtrot#1337",
IconURL: "https://cdn.discordapp.com/avatars/514163441548656641/a4ede220fea0ad8872b86f3eebc45524.png?size=128",
ProxyIconURL: "",
}
msg := discordgo.MessageEmbed{
URL: "",
Type: "",
Title: title,
Description: desc,
Timestamp: "",
Color: msgColor,
Footer: &ftr,
Image: nil,
Thumbnail: nil,
Video: nil,
Provider: nil,
Author: nil,
Fields: nil,
}
return &msg
}
func (f *Features) CreateCustomEmbed(embedData *models.CustomEmbed) *discordgo.MessageEmbed {
var ftr discordgo.MessageEmbedFooter
var img discordgo.MessageEmbedImage
var thm discordgo.MessageEmbedThumbnail
var prv discordgo.MessageEmbedProvider
var atr discordgo.MessageEmbedAuthor
ftr.Text = embedData.FooterText
ftr.IconURL = embedData.FooterImageURL
img.URL = embedData.ImageURL
img.Height = embedData.ImageH
img.Width = embedData.ImageW
thm.URL = embedData.ThumbnailURL
thm.Height = embedData.ThumbnailH
thm.Width = embedData.ThumbnailW
prv.Name = embedData.ProviderText
prv.URL = embedData.ProviderURL
atr.Name = embedData.AuthorText
atr.URL = embedData.AuthorURL
atr.IconURL = embedData.AuthorImageURL
msg := discordgo.MessageEmbed{
URL: embedData.URL,
Type: embedData.Type,
Title: embedData.Title,
Description: embedData.Desc,
Timestamp: "",
Color: embedData.Color,
Footer: &ftr,
Image: &img,
Thumbnail: &thm,
Video: nil,
Provider: &prv,
Author: &atr,
Fields: nil,
}
return &msg
}

212
features/misc.go Normal file
View File

@ -0,0 +1,212 @@
package features
import (
"errors"
"fmt"
"github.com/bwmarrin/discord.go"
"github.com/foxtrot/scuzzy/models"
"strconv"
"strings"
"time"
)
func (f *Features) handleCat(s *discordgo.Session, m *discordgo.MessageCreate) error {
if f.Auth.CheckAdminRole(m.Member) {
_, _ = s.ChannelMessageSend(m.ChannelID, "https://giphy.com/gifs/cat-cute-no-rCxogJBzaeZuU")
_ = s.ChannelMessageDelete(m.ChannelID, m.ID)
}
return nil
}
func (f *Features) handlePing(s *discordgo.Session, m *discordgo.MessageCreate) error {
var r *discordgo.Message
var err error
if !f.Auth.CheckAdminRole(m.Member) {
return errors.New("You do not have permissions to use that command.")
} else {
msg := f.CreateDefinedEmbed("Ping", "Pong", "success")
r, err = s.ChannelMessageSendEmbed(m.ChannelID, msg)
if err != nil {
return err
}
}
time.Sleep(5 * time.Second)
err = s.ChannelMessageDelete(m.ChannelID, r.ID)
if err != nil {
return err
}
err = s.ChannelMessageDelete(m.ChannelID, m.ID)
if err != nil {
return err
}
return nil
}
func (f *Features) handleInfo(s *discordgo.Session, m *discordgo.MessageCreate) error {
desc := "**Source**: https://github.com/foxtrot/scuzzy\n"
desc += "**Language**: Go\n"
desc += "**Commands**: See `" + f.Config.CommandKey + "help`\n\n\n"
gm, err := s.GuildMember(f.Config.GuildID, s.State.User.ID)
if err != nil {
return err
}
d := models.CustomEmbed{
Title: "Scuzzy Information",
Desc: desc,
ImageURL: "",
ImageH: 100,
ImageW: 100,
Color: 0xFFA500,
URL: "",
Type: "",
Timestamp: "",
FooterText: "Made with ❤ by Foxtrot",
FooterImageURL: "https://cdn.discordapp.com/avatars/514163441548656641/a4ede220fea0ad8872b86f3eebc45524.png",
ThumbnailURL: gm.User.AvatarURL(""),
ThumbnailH: 150,
ThumbnailW: 150,
ProviderURL: "",
ProviderText: "",
AuthorText: "",
AuthorURL: "",
AuthorImageURL: "",
}
msg := f.CreateCustomEmbed(&d)
_, err = s.ChannelMessageSendEmbed(m.ChannelID, msg)
if err != nil {
return err
}
return nil
}
func (f *Features) handleHelp(s *discordgo.Session, m *discordgo.MessageCreate) error {
desc := "**Available Commands**\n"
desc += "`help` - This help dialog\n"
desc += "`info` - Display Scuzzy info\n"
desc += "`md` - Display Discord markdown information\n"
desc += "`colors` - Available color roles\n"
desc += "`color` - Set an available color role\n"
desc += "`ctof` - Convert Celsius to Farenheit\n"
desc += "`ftoc` - Convert Farenheit to Celsius\n"
if f.Auth.CheckAdminRole(m.Member) {
desc += "\n"
desc += "**Admin Commands**\n"
desc += "`ping` - Ping the bot\n"
desc += "`status` - Set the bot status\n"
desc += "`purge` - Purge channel messages\n"
}
desc += "\n\nAll commands are prefixed with `" + f.Config.CommandKey + "`\n"
msg := f.CreateDefinedEmbed("Help", desc, "")
_, err := s.ChannelMessageSendEmbed(m.ChannelID, msg)
if err != nil {
return err
}
err = s.ChannelMessageDelete(m.ChannelID, m.ID)
if err != nil {
return err
}
return nil
}
func (f *Features) handleMarkdownInfo(s *discordgo.Session, m *discordgo.MessageCreate) error {
desc := "*Italic* text goes between `*single asterisks*`\n"
desc += "**Bold** text goes between `**double asterisks**`\n"
desc += "***Bold and Italic*** text goes between `***triple asterisks***`\n"
desc += "__Underlined__ text goes between `__double underscore__`\n"
desc += "~~Strikethrough~~ text goes between `~~double tilde~~`\n"
desc += "||Spoilers|| go between `|| double pipe ||`\n\n"
desc += "You can combine the above styles.\n\n"
desc += "Inline Code Blocks start and end with a single `````\n"
desc += "Multi line Code Blocks start and end with ```````\n"
desc += "Multi line Code Blocks can also specify a language with `````language`` at the start\n\n"
desc += "Single line quotes start with `>`\n"
desc += "Multi line quotes start with `>>>`\n"
msg := f.CreateDefinedEmbed("Discord Markdown", desc, "")
r, err := s.ChannelMessageSendEmbed(m.ChannelID, msg)
if err != nil {
return err
}
time.Sleep(15 * time.Second)
err = s.ChannelMessageDelete(m.ChannelID, r.ID)
if err != nil {
return err
}
err = s.ChannelMessageDelete(m.ChannelID, m.ID)
if err != nil {
return err
}
return nil
}
func (f *Features) handleCtoF(s *discordgo.Session, m *discordgo.MessageCreate) error {
inS := strings.Split(m.Content, " ")
if len(inS) < 2 {
return errors.New("You did not specify a temperature")
}
in := inS[1]
inF, err := strconv.ParseFloat(in, 2)
if err != nil {
return errors.New("You did not specify a valid number")
}
cels := (inF * 9.0 / 5.0) + 32.0
celsF := float64(cels)
msg := fmt.Sprintf("`%.1f°c` is `%.1f°f`", inF, celsF)
e := f.CreateDefinedEmbed("Celsius to Farenheit", msg, "")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, e)
if err != nil {
return err
}
return nil
}
func (f *Features) handleFtoC(s *discordgo.Session, m *discordgo.MessageCreate) error {
inS := strings.Split(m.Content, " ")
if len(inS) < 2 {
return errors.New("You did not specify a temperature")
}
in := inS[1]
inF, err := strconv.ParseFloat(in, 2)
if err != nil {
return errors.New("You did not specify a valid number")
}
faren := (inF - 32) * 5 / 9
farenF := float64(faren)
msg := fmt.Sprintf("`%.1f°f` is `%.1f°c`", inF, farenF)
e := f.CreateDefinedEmbed("Farenheit to Celsius", msg, "")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, e)
if err != nil {
return err
}
return nil
}

58
features/moderation.go Normal file
View File

@ -0,0 +1,58 @@
package features
import (
"errors"
"github.com/bwmarrin/discord.go"
"strconv"
"strings"
)
func (f *Features) handlePurgeChannel(s *discordgo.Session, m *discordgo.MessageCreate) error {
if !f.Auth.CheckAdminRole(m.Member) {
return errors.New("You do not have permissions to use that command.")
}
purgeSplit := strings.SplitN(m.Content, " ", 2)
if len(purgeSplit) < 2 {
return errors.New("No message count supplied")
}
msgCount, err := strconv.Atoi(purgeSplit[1])
if err != nil {
return nil
}
if msgCount > 100 {
return errors.New("You may only purge upto 100 messages at a time.")
}
chanMsgs, err := s.ChannelMessages(m.ChannelID, msgCount, "", "", "")
if err != nil {
return err
}
msg := f.CreateDefinedEmbed("Purge Channel", "Purging `"+purgeSplit[1]+"` messages.", "normal")
r, err := s.ChannelMessageSendEmbed(m.ChannelID, msg)
if err != nil {
return err
}
var delMsgs []string
for _, v := range chanMsgs {
delMsgs = append(delMsgs, v.ID)
}
err = s.ChannelMessagesBulkDelete(m.ChannelID, delMsgs)
if err != nil {
return err
}
err = s.ChannelMessageDelete(m.ChannelID, r.ID)
msg = f.CreateDefinedEmbed("Purge Channel", "Purged `"+purgeSplit[1]+"` messages!", "success")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, msg)
if err != nil {
return err
}
return nil
}

81
features/usercolor.go Normal file
View File

@ -0,0 +1,81 @@
package features
import (
"errors"
"github.com/bwmarrin/discord.go"
"strings"
)
func (f *Features) listUserColors(s *discordgo.Session, m *discordgo.MessageCreate) error {
if !f.Auth.CheckCommandRestrictions(m) {
return errors.New("This command is not allowed in this channel.")
}
msgC := "You can choose from the following colors:\n\n"
for _, v := range f.Config.ColorRoles {
msgC += "<@&" + v.ID + ">\n"
}
msgC += "\n\nUse `" + f.Config.CommandKey + "color <color_name>` to set.\n"
msg := f.CreateDefinedEmbed("User Colors", msgC, "")
_, err := s.ChannelMessageSendEmbed(m.ChannelID, msg)
if err != nil {
return err
}
return nil
}
func (f *Features) setUserColor(s *discordgo.Session, m *discordgo.MessageCreate) error {
var err error
if !f.Auth.CheckCommandRestrictions(m) {
return errors.New("This command is not allowed in this channel.")
}
rUserID := m.Author.ID
userInput := strings.Split(m.Content, " ")
if len(userInput) < 2 {
err = f.listUserColors(s, m)
return err
}
roleColorName := userInput[1]
roleColorName = strings.ToLower(roleColorName)
roleColorID := ""
for _, role := range f.Config.ColorRoles {
if role.Name == roleColorName {
roleColorID = role.ID
}
}
if len(roleColorID) == 0 {
err = f.listUserColors(s, m)
return err
}
for _, role := range f.Config.ColorRoles {
// Attempt to remove all color roles regardless of if they have them or not.
// Slow because of the REST requests...
_ = s.GuildMemberRoleRemove(m.GuildID, rUserID, role.ID)
}
err = s.GuildMemberRoleAdd(m.GuildID, rUserID, roleColorID)
if err != nil {
return err
} else {
msg := f.CreateDefinedEmbed("User Color", "<@"+m.Author.ID+">: Your color has been set to <@&"+roleColorID+">!", "success")
_, err = s.ChannelMessageSendEmbed(m.ChannelID, msg)
if err != nil {
return err
}
}
err = s.ChannelMessageDelete(m.ChannelID, m.ID)
if err != nil {
return err
}
return nil
}

31
models/config.go Normal file
View File

@ -0,0 +1,31 @@
package models
import "github.com/bwmarrin/discord.go"
type ColorRole struct {
Name string `json:"color"`
ID string `json:"id"`
}
type CommandRestriction struct {
Command string `json:"command"`
Mode string `json:"mode"`
Channels []string `json:"channels"`
}
type Configuration struct {
GuildID string `json:"guild_id"`
StatusText string `json:"status_text"`
WelcomeText string `json:"welcome_text"`
CommandKey string `json:"command_key"`
AdminRoles []string `json:"admin_roles"`
JoinRoleIDs []string `json:"join_role_ids"`
CommandRestrictions []CommandRestriction `json:"command_restrictions"`
ColorRoles []ColorRole `json:"color_roles"`
Guild *discordgo.Guild `json:"reserved_guild"`
}

28
models/embeds.go Normal file
View File

@ -0,0 +1,28 @@
package models
type CustomEmbed struct {
URL string
Title string
Desc string
Type string
Timestamp string
Color int
FooterText string
FooterImageURL string
ImageURL string
ImageH int
ImageW int
ThumbnailURL string
ThumbnailH int
ThumbnailW int
ProviderURL string
ProviderText string
AuthorText string
AuthorURL string
AuthorImageURL string
}