From 9fc6b4e99c476ed5424da72b7abb8cb8e80291bb Mon Sep 17 00:00:00 2001 From: Etzelia Date: Tue, 9 Jun 2020 08:04:44 -0500 Subject: [PATCH] Initial Commit Signed-off-by: Etzelia --- .gitignore | 8 +++ Makefile | 24 ++++++++ README.md | 23 ++++++++ config/config.go | 64 +++++++++++++++++++++ database/database.go | 60 +++++++++++++++++++ discord/clear.go | 69 ++++++++++++++++++++++ discord/discord.go | 134 +++++++++++++++++++++++++++++++++++++++++++ discord/fired.go | 19 ++++++ discord/help.go | 42 ++++++++++++++ discord/inspire.go | 23 ++++++++ discord/links.go | 49 ++++++++++++++++ discord/register.go | 53 +++++++++++++++++ go.mod | 13 +++++ go.sum | 32 +++++++++++ main.go | 61 ++++++++++++++++++++ sedbot.example.go | 35 +++++++++++ sedbot.example.toml | 38 ++++++++++++ 17 files changed, 747 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 config/config.go create mode 100644 database/database.go create mode 100644 discord/clear.go create mode 100644 discord/discord.go create mode 100644 discord/fired.go create mode 100644 discord/help.go create mode 100644 discord/inspire.go create mode 100644 discord/links.go create mode 100644 discord/register.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 sedbot.example.go create mode 100644 sedbot.example.toml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e03ca1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# GoLand +.idea/ + +# Generated +config/config_default.go + +# sedbot +sedbot* \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..154ff14 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +GO ?= go + +.PHONY: fmt +fmt: + $(GO) fmt ./... + +.PHONY: generate +generate: + $(GO) generate ./... + +.PHONY: test +test: + $(GO) test -race ./... + +.PHONY: vet +vet: + $(GO) vet ./... + +.PHONY: build +build: + $(GO) build + +.PHONY: build-all +build-all: generate build \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f28203f --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# SedBot + +BirbMC Discord generi-bot. + +## Commands + +### Public + +* `register ` - Register to the Discord +* `links` - Get a list of dynamic links + * `` - Get a specific link +* `fired` - Check how many times Carolyn has been fired +* `inspire` - Get a random "inspirational" message from [InspiroBot](https://inspirobot.me) + +### Moderation + +* `clear [<@user>] ` - Clear messages (optionally only by @user) + +## Building + +```text +make build-all +``` \ No newline at end of file diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..20d2246 --- /dev/null +++ b/config/config.go @@ -0,0 +1,64 @@ +package config + +import ( + "io/ioutil" + "os" + + "github.com/BurntSushi/toml" +) + +var defaultConfig = []byte("") + +type Config struct { + Token string `toml:"token"` + Prefix string `toml:"prefix"` + MCMToken string `toml:"mcm_token"` + MCMURL string `toml:"mcm_url"` + DBPath string `toml:"db_path"` + + StaffRoles []string `toml:"staff_roles"` + Links []Link `toml:"links"` + MessageRoles []MessageRole `toml:"message_roles"` + RegisterRole string `toml:"register_role"` + RegisteredChannel string `toml:"registered_channel"` + FiredRole string `toml:"fired_role"` +} + +type MessageRole struct { + MessageID string `toml:"message_id"` + RoleID string `toml:"role_id"` + Emoji string `toml:"emoji"` +} + +type Link struct { + Name string `toml:"name"` + Aliases []string `toml:"aliases"` + URL string `toml:"url"` +} + +func Load(configPath string) (*Config, error) { + var err error + var configContent []byte + if len(configPath) == 0 { + configPath = "sedbot.toml" + } + + configContent, err = ioutil.ReadFile(configPath) + if err != nil { + if os.IsNotExist(err) { + if err = ioutil.WriteFile(configPath, defaultConfig, os.ModePerm); err != nil { + return nil, err + } + configContent = defaultConfig + } else { + return nil, err + } + } + + var cfg *Config + if err = toml.Unmarshal(configContent, &cfg); err != nil { + return nil, err + } + + return cfg, nil +} diff --git a/database/database.go b/database/database.go new file mode 100644 index 0000000..8f3c9ac --- /dev/null +++ b/database/database.go @@ -0,0 +1,60 @@ +package database + +import ( + "strconv" + + "go.etcd.io/bbolt" +) + +var ( + firedBucket = []byte("fired") + + buckets = [][]byte{ + firedBucket, + } +) + +type Database struct { + db *bbolt.DB +} + +func Load(dbPath string) (*Database, error) { + db, err := bbolt.Open(dbPath, 0600, bbolt.DefaultOptions) + if err != nil { + return nil, err + } + for _, b := range buckets { + if err := db.Update(func(tx *bbolt.Tx) error { + _, err := tx.CreateBucketIfNotExists(b) + return err + }); err != nil { + return nil, err + } + } + return &Database{ + db: db, + }, nil +} + +func (db *Database) CheckPing(roleID string) int { + roleIDByte := []byte(roleID) + var idx int + _ = db.db.View(func(tx *bbolt.Tx) error { + num := tx.Bucket(firedBucket).Get(roleIDByte) + if num != nil { + if i, err := strconv.Atoi(string(num)); err == nil { + idx = i + } + } + return nil + }) + return idx +} + +func (db *Database) IncrementPing(roleID string) error { + roleIDByte := []byte(roleID) + return db.db.Update(func(tx *bbolt.Tx) error { + idx := db.CheckPing(roleID) + return tx.Bucket(firedBucket).Put(roleIDByte, []byte(strconv.Itoa(idx+1))) + }) +} diff --git a/discord/clear.go b/discord/clear.go new file mode 100644 index 0000000..fa7592a --- /dev/null +++ b/discord/clear.go @@ -0,0 +1,69 @@ +package discord + +import ( + "errors" + "strconv" + "strings" +) + +const clearMax = 20 + +func init() { + commands["clear"] = command{ + validate: func(cmd commandInit) bool { + return isStaff(cmd.message.Member.Roles, cmd.config.StaffRoles) + }, + run: func(cmd commandInit) error { + args := strings.Fields(cmd.message.Content) + + var userID string + if len(cmd.message.Mentions) > 0 { + userID = cmd.message.Mentions[0].ID + } + + limitArg := 1 + if userID != "" { + limitArg = 2 + if len(args) < 2 { + return errors.New("this command takes needs two arguments with a mention") + } + } else if len(args) < 1 { + return errors.New("this command takes one argument without a mention") + } + + limit, err := strconv.Atoi(args[limitArg]) + if err != nil { + return err + } + + if limit < 0 { + limit = 0 + } else if limit > clearMax { + limit = 20 + } + + batch := []string{cmd.message.ID} + + var deleted int + messages, err := cmd.session.ChannelMessages(cmd.message.ChannelID, 100, cmd.message.ID, "", "") + for _, msg := range messages { + if deleted == limit { + break + } + + deleteMessage := true + if userID != "" { + deleteMessage = msg.Author.ID == userID + } + + if deleteMessage { + batch = append(batch, msg.ID) + deleted++ + } + } + + return cmd.session.ChannelMessagesBulkDelete(cmd.message.ChannelID, batch) + }, + help: "Clear messages", + } +} diff --git a/discord/discord.go b/discord/discord.go new file mode 100644 index 0000000..a6fd265 --- /dev/null +++ b/discord/discord.go @@ -0,0 +1,134 @@ +package discord + +import ( + "strings" + + "go.etztech.xyz/sedbot/config" + "go.etztech.xyz/sedbot/database" + + "github.com/bwmarrin/discordgo" + "go.jolheiser.com/beaver" +) + +// Register commands to this map +var commands = make(map[string]command) + +type commandInit struct { + session *discordgo.Session + message *discordgo.Message + config *config.Config + database *database.Database +} + +type command struct { + validate func(cmd commandInit) bool + run func(cmd commandInit) error + help string +} + +func Bot(cfg *config.Config, db *database.Database) (*discordgo.Session, error) { + bot, err := discordgo.New("Bot " + cfg.Token) + if err != nil { + return nil, err + } + + Links(cfg) + + bot.AddHandler(commandHandler(cfg, db)) + bot.AddHandler(messageHandler(cfg, db)) + + beaver.Info("https://discord.com/api/oauth2/authorize?client_id=718905104643784825&permissions=0&redirect_uri=https%3A%2F%2Fbirbmc.com&scope=bot") + + return bot, nil +} + +func sendTyping(s *discordgo.Session, channelID string) { + if err := s.ChannelTyping(channelID); err != nil { + beaver.Errorf("could not send typing status: %v", err) + } +} + +func sendMessage(s *discordgo.Session, channelID, content string) *discordgo.Message { + msg, err := s.ChannelMessageSend(channelID, content) + if err != nil { + beaver.Errorf("could not send message: %v", err) + return nil + } + return msg +} + +func isStaff(authorRoleIDs, staffRoleIDs []string) bool { + for _, aRole := range authorRoleIDs { + for _, sRole := range staffRoleIDs { + if aRole == sRole { + return true + } + } + } + return false +} + +func commandHandler(cfg *config.Config, db *database.Database) func(s *discordgo.Session, m *discordgo.MessageCreate) { + return func(s *discordgo.Session, m *discordgo.MessageCreate) { + // Ignore bots + if m.Author.Bot { + return + } + + // Check prefix + if !strings.HasPrefix(m.Content, cfg.Prefix) { + return + } + + content := m.Content[1:] + args := strings.Fields(content) + if len(args) == 0 { + return + } + + cmdArg := strings.ToLower(args[0]) + isHelp := strings.EqualFold(cmdArg, "help") + + cmd, ok := commands[cmdArg] + if !ok && !isHelp { + return + } + + if isHelp { + sendMessage(s, m.ChannelID, cmd.help) + return + } + + cmdInit := commandInit{ + session: s, + message: m.Message, + config: cfg, + database: db, + } + if !cmd.validate(cmdInit) { + sendMessage(s, m.ChannelID, "You cannot run this command.") + return + } + if err := cmd.run(cmdInit); err != nil { + sendMessage(s, m.ChannelID, err.Error()) + } + } +} + +func messageHandler(cfg *config.Config, db *database.Database) func(s *discordgo.Session, m *discordgo.MessageCreate) { + return func(s *discordgo.Session, m *discordgo.MessageCreate) { + // Ignore bots + if m.Author.Bot { + return + } + + // [FIRED] increment + for _, role := range m.MentionRoles { + if cfg.FiredRole == role { + if err := db.IncrementPing(cfg.FiredRole); err != nil { + beaver.Errorf("could not increment ping for %s: %v", cfg.FiredRole, err) + } + } + } + } +} diff --git a/discord/fired.go b/discord/fired.go new file mode 100644 index 0000000..e85b11b --- /dev/null +++ b/discord/fired.go @@ -0,0 +1,19 @@ +package discord + +import ( + "fmt" +) + +func init() { + commands["fired"] = command{ + validate: func(cmd commandInit) bool { + return true + }, + run: func(cmd commandInit) error { + sendMessage(cmd.session, cmd.message.ChannelID, fmt.Sprintf("Carolyn has been fired **%d** times!", + cmd.database.CheckPing(cmd.config.FiredRole))) + return nil + }, + help: "Check how many times Carolyn has been fired.", + } +} diff --git a/discord/help.go b/discord/help.go new file mode 100644 index 0000000..5d50e1b --- /dev/null +++ b/discord/help.go @@ -0,0 +1,42 @@ +package discord + +import ( + "fmt" + "strings" +) + +func init() { + commands["help"] = command{ + validate: func(cmd commandInit) bool { + return true + }, + run: func(cmd commandInit) error { + args := strings.Fields(cmd.message.Content)[1:] + + var resp string + if len(args) == 1 { + resp = singleHelp(args[0]) + } else { + resp = allHelp() + } + sendMessage(cmd.session, cmd.message.ChannelID, resp) + return nil + }, + help: "HELP! HEEEEEEEEEELP!", + } +} + +func singleHelp(cmd string) string { + if c, ok := commands[cmd]; ok { + return fmt.Sprintf("%s: %s", cmd, c.help) + } + return "Unknown command" +} + +func allHelp() string { + helps := make([]string, 0) + for n, c := range commands { + helps = append(helps, fmt.Sprintf("%s: %s", n, c.help)) + } + return strings.Join(helps, "\n") +} diff --git a/discord/inspire.go b/discord/inspire.go new file mode 100644 index 0000000..9f2c06f --- /dev/null +++ b/discord/inspire.go @@ -0,0 +1,23 @@ +package discord + +import "go.etztech.xyz/inspiro" + +func init() { + commands["inspire"] = command{ + validate: func(cmd commandInit) bool { + return true + }, + run: func(cmd commandInit) error { + sendTyping(cmd.session, cmd.message.ChannelID) + + img, err := inspiro.Generate() + if err != nil { + return err + } + + sendMessage(cmd.session, cmd.message.ChannelID, img) + return nil + }, + help: "Get inspired!", + } +} diff --git a/discord/links.go b/discord/links.go new file mode 100644 index 0000000..d8241ff --- /dev/null +++ b/discord/links.go @@ -0,0 +1,49 @@ +package discord + +import ( + "fmt" + "strings" + + "go.etztech.xyz/sedbot/config" +) + +func Links(cfg *config.Config) { + links := make([]string, 0) + for _, link := range cfg.Links { + commands[link.Name] = command{ + validate: func(cmd commandInit) bool { + return true + }, + run: func(cmd commandInit) error { + sendMessage(cmd.session, cmd.message.ChannelID, fmt.Sprintf("<%s>", link.URL)) + return nil + }, + help: fmt.Sprintf("Returns the link for %s", link.Name), + } + links = append(links, fmt.Sprintf("%s -> %s", link.Name, link.URL)) + for _, alias := range link.Aliases { + commands[alias] = command{ + validate: func(cmd commandInit) bool { + return true + }, + run: func(cmd commandInit) error { + sendMessage(cmd.session, cmd.message.ChannelID, fmt.Sprintf("<%s>", link.URL)) + return nil + }, + help: fmt.Sprintf("Returns the link for %s", alias), + } + links = append(links, fmt.Sprintf("%s -> %s", alias, link.URL)) + } + } + + commands["links"] = command{ + validate: func(cmd commandInit) bool { + return true + }, + run: func(cmd commandInit) error { + sendMessage(cmd.session, cmd.message.ChannelID, strings.Join(links, "\n")) + return nil + }, + help: "Get all dynamic links", + } +} diff --git a/discord/register.go b/discord/register.go new file mode 100644 index 0000000..7c086fb --- /dev/null +++ b/discord/register.go @@ -0,0 +1,53 @@ +package discord + +import ( + "errors" + "fmt" + "strings" + + "go.etztech.xyz/go-mcm" + "go.etztech.xyz/go-mcm/model/django" +) + +func init() { + commands["register"] = command{ + validate: func(cmd commandInit) bool { + return len(cmd.message.Member.Roles) == 0 + }, + run: func(cmd commandInit) error { + args := strings.Fields(cmd.message.Content) + if len(args) < 2 { + return errors.New("you must give this command your application username") + } + + sendTyping(cmd.session, cmd.message.ChannelID) + + manager := mcm.NewMCM(cmd.config.MCMToken, cmd.config.MCMURL) + models := manager.NewModel() + + apps, err := models.Application(models.NewDjangoBuilder().IExact(django.ApplicationUsername, args[1])) + if err != nil { + return err + } + + if len(apps) == 0 { + return errors.New("no application found with that username") + } + + if !apps[0].Accepted { + return errors.New("sorry, your application was denied") + } + + // Accepted + if err := cmd.session.GuildMemberNickname(cmd.message.GuildID, cmd.message.Author.ID, apps[0].Username); err != nil { + return err + } + if err := cmd.session.GuildMemberRoleAdd(cmd.message.GuildID, cmd.message.Author.ID, cmd.config.RegisterRole); err != nil { + return err + } + sendMessage(cmd.session, cmd.config.RegisteredChannel, fmt.Sprintf("Welcome, **%s**!", cmd.message.Author.Mention())) + return nil + }, + help: "Register yourself with the Discord", + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..594882e --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module go.etztech.xyz/sedbot + +go 1.14 + +require ( + github.com/BurntSushi/toml v0.3.1 + github.com/bwmarrin/discordgo v0.20.3 + github.com/urfave/cli/v2 v2.2.0 // indirect + go.etcd.io/bbolt v1.3.4 + go.etztech.xyz/go-mcm v1.2.0 + go.etztech.xyz/inspiro v0.0.0-20200606185551-edfdf9da2359 + go.jolheiser.com/beaver v1.0.2 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..74b9d5f --- /dev/null +++ b/go.sum @@ -0,0 +1,32 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/bwmarrin/discordgo v0.20.3 h1:AxjcHGbyBFSC0a3Zx5nDQwbOjU7xai5dXjRnZ0YB7nU= +github.com/bwmarrin/discordgo v0.20.3/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= +github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4= +github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= +go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etztech.xyz/go-mcm v1.2.0 h1:QEOv6oAjy9ICP3AOcwItNT88wBjOZHK7UKseZEcZh0k= +go.etztech.xyz/go-mcm v1.2.0/go.mod h1:Hz2YULB3sN/aQA8cPSm2d6LM3E3qTMspzfRCIAD/1dc= +go.etztech.xyz/inspiro v0.0.0-20200606185551-edfdf9da2359 h1:j/ZeoAj185wHfCSYD52Kt/69i3Bzk1MXN4Qh1yP6+P4= +go.etztech.xyz/inspiro v0.0.0-20200606185551-edfdf9da2359/go.mod h1:+fC1WzJm/oS4UEgqr1jPouWerxBys52lTTDA94/5bf8= +go.jolheiser.com/beaver v1.0.2 h1:KA2D6iO8MQhZi1nZYi/Chak/f1Cxfrs6b1XO623+Khk= +go.jolheiser.com/beaver v1.0.2/go.mod h1:7X4F5+XOGSC3LejTShoBdqtRCnPWcnRgmYGmG3EKW8g= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfruoXZIrh4YBgqVHtDvw0= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..442ec31 --- /dev/null +++ b/main.go @@ -0,0 +1,61 @@ +//go:generate go run sedbot.example.go + +package main + +import ( + "flag" + "os" + "os/signal" + "syscall" + + "go.etztech.xyz/sedbot/config" + "go.etztech.xyz/sedbot/database" + "go.etztech.xyz/sedbot/discord" + + "go.jolheiser.com/beaver" +) + +var configFlag string + +func main() { + flag.StringVar(&configFlag, "config", "sedbot.toml", "Set config path") + flag.Parse() + + beaver.Console.Format = beaver.FormatOptions{ + TimePrefix: true, + StackPrefix: true, + StackLimit: 15, + LevelPrefix: true, + LevelColor: true, + } + + cfg, err := config.Load(configFlag) + if err != nil { + beaver.Fatalf("could not load config: %v", err) + } + + db, err := database.Load(cfg.DBPath) + if err != nil { + beaver.Fatalf("could not load database: %v", err) + } + + bot, err := discord.Bot(cfg, db) + if err != nil { + beaver.Fatalf("could not start Discord bot: %v", err) + } + + go func() { + if err := bot.Open(); err != nil { + beaver.Errorf("error running Discord bot: %v", err) + } + }() + + beaver.Info("Bot is now running. Press CTRL-C to exit.") + sc := make(chan os.Signal, 1) + signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) + <-sc + + if err := bot.Close(); err != nil { + beaver.Errorf("error closing Discord bot: %v", err) + } +} diff --git a/sedbot.example.go b/sedbot.example.go new file mode 100644 index 0000000..10abce6 --- /dev/null +++ b/sedbot.example.go @@ -0,0 +1,35 @@ +// +build ignore + +package main + +import ( + "fmt" + "io/ioutil" + "os" +) + +const ( + exampleFile = "sedbot.example.toml" + writeFile = "config/config_default.go" + tmpl = `package config + +func init() { + defaultConfig = []byte(` + "`" + `%s` + "`" + `) +} +` +) + +func main() { + bytes, err := ioutil.ReadFile(exampleFile) + if err != nil { + fmt.Printf("Could not read from %s. Are you in the root directory of the project?", exampleFile) + os.Exit(1) + } + + data := fmt.Sprintf(tmpl, string(bytes)) + + if err := ioutil.WriteFile(writeFile, []byte(data), os.ModePerm); err != nil { + fmt.Printf("Could not write to %s.", writeFile) + os.Exit(1) + } +} diff --git a/sedbot.example.toml b/sedbot.example.toml new file mode 100644 index 0000000..0a05dfe --- /dev/null +++ b/sedbot.example.toml @@ -0,0 +1,38 @@ +# token is the Discord token for the bot +token = "" + +# prefix is the bot command prefix +prefix = "!" + +# mcm_token is the token for the MCM API +mcm_token = "" + +# mcm_url is the base URL to MCM +mcm_url = "" + +# db_path is the path to the database (default is next to binary) +db_path = "sedbot.db" + +# fired_role is to check how many time Carolyn has been fired +fired_role = "0" + +# register_role is the role to assign to a user after registering +register_role = "0" + +# registered_channel is the channel to message to welcome the newly registered user +registered_channel = "0" + +# staff_roles are for staff commands +staff_roles = [] + +# links are any basic link -> URL commands +[[links]] +name = "discord" +aliases = ["invite", "gib"] +url = "https://birbmc.com/discord" + +# message_roles are for messages that should toggle a role when a user selects it +[[message_roles]] +message_id = "0" +role_id = "0" +emoji = "thumbsup" \ No newline at end of file