diff --git a/command.go b/command.go new file mode 100644 index 0000000..47d03fd --- /dev/null +++ b/command.go @@ -0,0 +1,96 @@ +package main + +import ( + "fmt" + "github.com/bwmarrin/discordgo" + "strings" + "log" + "regexp" +) + +type CommandType int + +const ( + CommandTypePrefix CommandType = 0 + CommandTypeFullMatch CommandType = 1 + CommandTypeRegex CommandType = 2 +) + +type Command struct { + Trigger string // must be specified + Output string // no output if unspecified + OutputEmbed *discordgo.MessageEmbed // no embed output if unspecified + Type CommandType // defaults to Prefix + OutputIsReply bool // defaults to false + DeleteInput bool // defaults to false + DMOnly bool // defaults to false + AdminOnly bool // defaults to false + IsEmbed bool // defaults to false + // for custom commands that go beyond prints and deletions + Function func(*discordgo.Session, *discordgo.MessageCreate) +} + + +func registerCommand(command Command) { + if command.Trigger == "" { + fmt.Println("Cannot register a command with no trigger. Skipping.") + return + } + commands = append(commands, command) +} + +func evaluateMessage(s *discordgo.Session, m *discordgo.MessageCreate) { + if m.Author.ID == s.State.User.ID { + log.Printf(" %s", m.Content) + return + } + for _, command := range commands { + switch command.Type { + case CommandTypePrefix: + if strings.HasPrefix(m.Content, command.Trigger) { + executeCommand(s, m, command) + return + } + case CommandTypeFullMatch: + if m.Content == command.Trigger { + executeCommand(s, m, command) + return + } + case CommandTypeRegex: + match, _ := regexp.MatchString(command.Trigger, m.Content) + if match { + executeCommand(s, m, command) + return + } + } + } +} + +func executeCommand(session *discordgo.Session, message *discordgo.MessageCreate, command Command) { + if (!command.DMOnly || (getChannel(session.State, message.ChannelID).Type == discordgo.ChannelTypeDM)) && + (!command.AdminOnly || (message.Author.ID == config.AdminID)) { + if command.Function == nil { + // simple reply + if command.OutputEmbed == nil { + messageContent := generateReply(message, command) + session.ChannelMessageSend(message.ChannelID, messageContent) + } else { + session.ChannelMessageSendEmbed(message.ChannelID, command.OutputEmbed) + } + if command.DeleteInput { + session.ChannelMessageDelete(message.ChannelID, message.ID) + } + } + } else { + log.Printf("Denied command %s to user %s.", command.Trigger, userToString(message.Author)) + } +} + +func generateReply(message *discordgo.MessageCreate, command Command) string { + output := command.Output + if command.OutputIsReply { + output = fmt.Sprintf(output, message.Author.ID) + } + return output +} + diff --git a/config.go b/config.go index 087b638..40cee7c 100644 --- a/config.go +++ b/config.go @@ -31,7 +31,7 @@ type Config struct { func readConfig() Config { - file, _ := os.Open("config.json") + file, _ := os.Open("config2.json") conf := Config{} json.NewDecoder(file).Decode(&conf) file.Close() diff --git a/events.go b/events.go new file mode 100644 index 0000000..801c029 --- /dev/null +++ b/events.go @@ -0,0 +1,180 @@ +package main + +import ( + "fmt" + "github.com/bwmarrin/discordgo" + "strings" + "log" + "regexp" +) + +func onJoin(s *discordgo.Session, member *discordgo.GuildMemberAdd) { + if !member.User.Bot && config.RequireAccept { + s.GuildMemberRoleAdd(config.ServerID, member.User.ID, config.LockedRoleID) + } + if !member.User.Bot && config.SendWelcomeDM { + dm, err := s.UserChannelCreate(member.User.ID) + if err != nil { + log.Println(fmt.Sprintf("Error creating DM with %s", userToString(member.User), err)) + } else { + embed := getWelcomeEmbed() + _, err = s.ChannelMessageSendEmbed(dm.ID, embed) + if err != nil { + log.Println(fmt.Sprintf("Error sending DM to %s", userToString(member.User), err)) + } + } + if err != nil { + // if any of the preceding operations produced an error + log.Printf("Sending welcome @mention at %s", userToString(member.User)) + s.ChannelMessageSend(config.GeneralChannel, fmt.Sprintf("Wilkommen <@%s>. Bitte aktiviere vorübergehend DMs für diesen Server und sende eine Nachricht mit !welcome an mich.", member.User.ID)) + } + } + log.Printf("User joined: %s", userToString(member.User)) +} + +func onDM(s *discordgo.Session, m *discordgo.MessageCreate) { + log.Printf("Received DM from %s with content: “%s”", userToString(m.Author), m.Content) + fmt.Sprintf("Received DM from %s with content: “%s”", userToString(m.Author), m.Content) + Member, _ := s.GuildMember(config.ServerID, m.Author.ID) + dm, _ := s.UserChannelCreate(Member.User.ID) + if m.Content == "!welcome" { + s.ChannelMessageSendEmbed(dm.ID, getWelcomeEmbed()) + return + } + if strings.HasPrefix(m.Content, "!complain") { + redirectComplaint(s, m) + s.ChannelMessageSend(dm.ID, config.ComplaintReceivedMessage) + return + } + for comm, role := range config.RoleCommands { + if m.Content == comm { + for _, irole := range config.RoleCommands { + for _, mrole := range Member.Roles { + if irole == mrole { + s.ChannelMessageSend(dm.ID, "Baka, du kannst nur eine der Rollen haben.") + log.Printf("Denied Role %s to %s. User already has %s", roleName(s.State, irole), userToString(m.Author), roleName(s.State, irole)) + return + } + } + } + log.Printf("Giving Role %s to %s", roleName(s.State, role), userToString(m.Author)) + s.ChannelMessageSend(dm.ID, "Haaai, Ryoukai desu~") + s.GuildMemberRoleAdd(config.ServerID, m.Author.ID, role) + } + } +} + +func onMessage(s *discordgo.Session, m *discordgo.MessageCreate) { + if m.Author.ID == s.State.User.ID { + log.Printf(" %s", m.Content) + return + } + + if getChannel(s.State, m.ChannelID).Type == discordgo.ChannelTypeDM { + onDM(s, m) + } + + if m.Author.ID == config.AdminID { + //replyGodmode(s, m) + } else if m.ChannelID == config.WelcomeChannel { + s.ChannelMessageDelete(m.ChannelID, m.ID) + if m.Content == "!accept" { + unlockUser(s, m.Author.ID) + } + return + } + + // In case this doesn’t work with your font: the last character is a winking emoji. + winks, _ := regexp.MatchString("([()|DoO];|;[()|DoOpP]|:wink:|😉)", m.Content) + if winks { + s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("<@%s> Oboe!", m.Author.ID)) + s.ChannelMessageDelete(m.ChannelID, m.ID) + channel := getChannel(s.State, m.ChannelID) + log.Printf("Deleted message by %s in %s. Content: “%s”", userToString(m.Author), channelToString(channel), m.Content) + return + } + + // As per our majesty’s command: + if m.Content == "\\o" { + s.ChannelMessageSend(m.ChannelID, "o/") + log.Printf("o/ at %s", userToString(m.Author)) + } else if m.Content == "o/" { + s.ChannelMessageSend(m.ChannelID, "\\o") + log.Printf("\\o at %s", userToString(m.Author)) + } else if m.Content == "ayy" { + s.ChannelMessageSend(m.ChannelID, "lmao") + log.Printf("ayy lmao at %s", userToString(m.Author)) + } +} + + +// Admin stuff down here. This is very server-specific + +func adminshit (s *discordgo.Session, m *discordgo.MessageCreate) { + if m.Content == fmt.Sprintf("<@%s> <3", s.State.User.ID) { + s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("<@%s> <3", config.AdminID)) + } +/* + if m.Content == "print_rules()" { + channel := getChannel(s.State, m.ChannelID) + log.Printf("print_rules() triggered by %s in %s.", userToString(m.Author), channelToString(channel)) + embedColor := 0xffb90f // kageru gold + embed := &discordgo.MessageEmbed{ + Author: &discordgo.MessageEmbedAuthor{}, + Color: embedColor, + Description: config.WelcomeEmbed.Message, + Fields: []*discordgo.MessageEmbedField{ + &discordgo.MessageEmbedField{ + Name: config.WelcomeEmbed.QuestionsTitle, + Value: config.WelcomeEmbed.QuestionsText, + Inline: true, + }, + &discordgo.MessageEmbedField{ + Name: config.WelcomeEmbed.BugsTitle, + Value: fmt.Sprintf(config.WelcomeEmbed.BugsText, config.AdminID), + Inline: true, + }, + }, + Thumbnail: &discordgo.MessageEmbedThumbnail{ + URL: config.WelcomeEmbed.Image, + }, + } + s.ChannelMessageSendEmbed(m.ChannelID, embed) + embed = &discordgo.MessageEmbed{ + Author: &discordgo.MessageEmbedAuthor{}, + Color: embedColor, + Fields: []*discordgo.MessageEmbedField{ + &discordgo.MessageEmbedField{ + Name: config.WelcomeEmbed.RulesTitle, + Value: config.WelcomeEmbed.RulesText, + Inline: true, + }, + }, + } + s.ChannelMessageSendEmbed(m.ChannelID, embed) + embed = &discordgo.MessageEmbed{ + Author: &discordgo.MessageEmbedAuthor{}, + Color: embedColor, + Fields: []*discordgo.MessageEmbedField{ + &discordgo.MessageEmbedField{ + Name: config.WelcomeEmbed.RulesTitle, + Value: config.WelcomeEmbed.RulesText2, + Inline: true, + }, + }, + } + s.ChannelMessageSendEmbed(m.ChannelID, embed) + } +*/ +} + +func redirectComplaint(s *discordgo.Session, m *discordgo.MessageCreate) { + embed := &discordgo.MessageEmbed { + Author: &discordgo.MessageEmbedAuthor{}, + Color: 0xbb0000, + Description: m.Content, + } + s.ChannelMessageSendEmbed(config.ModChannel, embed) +} + + diff --git a/helpers.go b/helpers.go new file mode 100644 index 0000000..2e1ede9 --- /dev/null +++ b/helpers.go @@ -0,0 +1,40 @@ +package main + +import ( + "github.com/bwmarrin/discordgo" + "log" + "fmt" +) + +func unlockUser(s *discordgo.Session, id string) { + s.GuildMemberRoleRemove(config.ServerID, id, config.LockedRoleID) + log.Printf("Removed lock from user: %s", userToString(getUser(s, id))) +} + +func userToString(u *discordgo.User) string { + return fmt.Sprintf("%s#%s (ID: %s)", u.Username, u.Discriminator, u.ID) +} + +func roleName(s *discordgo.State, rid string) string { + role, _ := s.Role(config.ServerID, rid) + return role.Name +} + +func channelToString(c *discordgo.Channel) string { + return fmt.Sprintf("%s (ID: %s) on %s", c.Name, c.ID, c.GuildID) +} + +func messageToString(m *discordgo.Message) string { + return fmt.Sprintf("<%s#%s>: %s", m.Author.Username, m.Author.Discriminator, m.Content) +} + +func getChannel(s *discordgo.State, cid string) *discordgo.Channel { + channel, _ := s.Channel(cid) + return channel +} + +func getUser(s *discordgo.Session, uid string) *discordgo.User { + user, _ := s.User(uid) + return user +} + diff --git a/main.go b/main.go index 12d7a1b..bbeec11 100644 --- a/main.go +++ b/main.go @@ -2,28 +2,24 @@ package main import ( "fmt" - "strings" "os/signal" "os" "syscall" - "regexp" "log" "github.com/bwmarrin/discordgo" ) var config = readConfig() var commands []Command -var t CommandType func main() { - fmt.Println(t) dg, err := discordgo.New("Bot " + config.Token) if err != nil { fmt.Println("error: ", err) return } - dg.AddHandler(genericReply) + dg.AddHandler(evaluateMessage) dg.AddHandler(onJoin) err = dg.Open() if err != nil { @@ -38,6 +34,9 @@ func main() { defer f.Close() log.SetOutput(f) + registerCommand(Command{Trigger: "o/", Output: "\\o", Type: CommandTypeFullMatch}) + registerCommand(Command{Trigger: "\\o", Output: "o/", Type: CommandTypeFullMatch}) + fmt.Println("bot running. selphyWoo") sc := make(chan os.Signal, 1) signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill) @@ -46,234 +45,9 @@ func main() { dg.Close() } -func getWelcomeEmbed() *discordgo.MessageEmbed { - return &discordgo.MessageEmbed { - Author: &discordgo.MessageEmbedAuthor{}, - Color: 0xffb90f, - Description: config.WelcomeEmbed.Message, - Fields: []*discordgo.MessageEmbedField { - &discordgo.MessageEmbedField { - Name: config.WelcomeEmbed.QuestionsTitle, - Value: config.WelcomeEmbed.QuestionsText, - Inline: true, - }, - &discordgo.MessageEmbedField { - Name: config.WelcomeEmbed.BugsTitle, - Value: fmt.Sprintf(config.WelcomeEmbed.BugsText, config.AdminID), - Inline: true, - }, - }, - Thumbnail: &discordgo.MessageEmbedThumbnail{ - URL: config.WelcomeEmbed.Image, - }, - } -} - -func onJoin(s *discordgo.Session, member *discordgo.GuildMemberAdd) { - if !member.User.Bot && config.RequireAccept { - s.GuildMemberRoleAdd(config.ServerID, member.User.ID, config.LockedRoleID) - } - if !member.User.Bot && config.SendWelcomeDM { - dm, err := s.UserChannelCreate(member.User.ID) - if err != nil { - log.Println(fmt.Sprintf("Error creating DM with %s", userToString(member.User), err)) - } else { - embed := getWelcomeEmbed() - _, err = s.ChannelMessageSendEmbed(dm.ID, embed) - if err != nil { - log.Println(fmt.Sprintf("Error sending DM to %s", userToString(member.User), err)) - } - } - if err != nil { - // if any of the preceding operations produced an error - log.Printf("Sending welcome @mention at %s", userToString(member.User)) - s.ChannelMessageSend(config.GeneralChannel, fmt.Sprintf("Wilkommen <@%s>. Bitte aktiviere vorübergehend DMs für diesen Server und sende eine Nachricht mit !welcome an mich.", member.User.ID)) - } - } - log.Printf("User joined: %s", userToString(member.User)) -} - -func unlockUser(s *discordgo.Session, id string) { - s.GuildMemberRoleRemove(config.ServerID, id, config.LockedRoleID) - log.Printf("Removed lock from user: %s", userToString(getUser(s, id))) -} - -func userToString(u *discordgo.User) string { - return fmt.Sprintf("%s#%s (ID: %s)", u.Username, u.Discriminator, u.ID) -} - -func roleName(s *discordgo.State, rid string) string { - role, _ := s.Role(config.ServerID, rid) - return role.Name -} - -func channelToString(c *discordgo.Channel) string { - return fmt.Sprintf("%s (ID: %s) on %s", c.Name, c.ID, c.GuildID) -} - -func messageToString(m *discordgo.Message) string { - return fmt.Sprintf("<%s#%s>: %s", m.Author.Username, m.Author.Discriminator, m.Content) -} - -func getChannel(s *discordgo.State, cid string) *discordgo.Channel { - channel, _ := s.Channel(cid) - return channel -} - -func getUser(s *discordgo.Session, uid string) *discordgo.User { - user, _ := s.User(uid) - return user -} - /*func undelete(s *discordgo.Session, m *discordgo.MessageDelete) { channel, _ := s.State.Channel(m.ChannelID) message, _ := s.State.Message(m.ChannelID, m.ID) log.Println(fmt.Sprintf("Someone deleted a message in %s: “%s”", channel.Name, messageToString(message))) }*/ -func redirectComplaint(s *discordgo.Session, m *discordgo.MessageCreate) { - embed := &discordgo.MessageEmbed { - Author: &discordgo.MessageEmbedAuthor{}, - Color: 0xbb0000, - Description: m.Content, - } - s.ChannelMessageSendEmbed(config.ModChannel, embed) -} - -func receivedDM(s *discordgo.Session, m *discordgo.MessageCreate) { - log.Printf("Received DM from %s with content: “%s”", userToString(m.Author), m.Content) - fmt.Sprintf("Received DM from %s with content: “%s”", userToString(m.Author), m.Content) - Member, _ := s.GuildMember(config.ServerID, m.Author.ID) - dm, _ := s.UserChannelCreate(Member.User.ID) - if m.Content == "!welcome" { - s.ChannelMessageSendEmbed(dm.ID, getWelcomeEmbed()) - return - } - if strings.HasPrefix(m.Content, "!complain") { - redirectComplaint(s, m) - s.ChannelMessageSend(dm.ID, config.ComplaintReceivedMessage) - return - } - for comm, role := range config.RoleCommands { - if m.Content == comm { - for _, irole := range config.RoleCommands { - for _, mrole := range Member.Roles { - if irole == mrole { - s.ChannelMessageSend(dm.ID, "Baka, du kannst nur eine der Rollen haben.") - log.Printf("Denied Role %s to %s. User already has %s", roleName(s.State, irole), userToString(m.Author), roleName(s.State, irole)) - return - } - } - } - log.Printf("Giving Role %s to %s", roleName(s.State, role), userToString(m.Author)) - s.ChannelMessageSend(dm.ID, "Haaai, Ryoukai desu~") - s.GuildMemberRoleAdd(config.ServerID, m.Author.ID, role) - } - } - -} - -func genericReply(s *discordgo.Session, m *discordgo.MessageCreate) { - if m.Author.ID == s.State.User.ID { - log.Printf(" %s", m.Content) - return - } - - if getChannel(s.State, m.ChannelID).Type == discordgo.ChannelTypeDM { - receivedDM(s, m) - } - - if m.Author.ID == config.AdminID { - replyGodmode(s, m) - } else if m.ChannelID == config.WelcomeChannel { - s.ChannelMessageDelete(m.ChannelID, m.ID) - if m.Content == "!accept" { - unlockUser(s, m.Author.ID) - } - return - } - - // In case this doesn’t work with your font: the last character is a winking emoji. - winks, _ := regexp.MatchString("([()|DoO];|;[()|DoOpP]|:wink:|😉)", m.Content) - if winks { - s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("<@%s> Oboe!", m.Author.ID)) - s.ChannelMessageDelete(m.ChannelID, m.ID) - channel := getChannel(s.State, m.ChannelID) - log.Printf("Deleted message by %s in %s. Content: “%s”", userToString(m.Author), channelToString(channel), m.Content) - return - } - - // As per our majesty’s command: - if m.Content == "\\o" { - s.ChannelMessageSend(m.ChannelID, "o/") - log.Printf("o/ at %s", userToString(m.Author)) - } else if m.Content == "o/" { - s.ChannelMessageSend(m.ChannelID, "\\o") - log.Printf("\\o at %s", userToString(m.Author)) - } else if m.Content == "ayy" { - s.ChannelMessageSend(m.ChannelID, "lmao") - log.Printf("ayy lmao at %s", userToString(m.Author)) - } -} - - -// Admin stuff down here. This is very server-specific - -func replyGodmode(s *discordgo.Session, m *discordgo.MessageCreate) { - if m.Content == fmt.Sprintf("<@%s> <3", s.State.User.ID) { - s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("<@%s> <3", config.AdminID)) - } -/* - if m.Content == "print_rules()" { - channel := getChannel(s.State, m.ChannelID) - log.Printf("print_rules() triggered by %s in %s.", userToString(m.Author), channelToString(channel)) - embedColor := 0xffb90f // kageru gold - embed := &discordgo.MessageEmbed{ - Author: &discordgo.MessageEmbedAuthor{}, - Color: embedColor, - Description: config.WelcomeEmbed.Message, - Fields: []*discordgo.MessageEmbedField{ - &discordgo.MessageEmbedField{ - Name: config.WelcomeEmbed.QuestionsTitle, - Value: config.WelcomeEmbed.QuestionsText, - Inline: true, - }, - &discordgo.MessageEmbedField{ - Name: config.WelcomeEmbed.BugsTitle, - Value: fmt.Sprintf(config.WelcomeEmbed.BugsText, config.AdminID), - Inline: true, - }, - }, - Thumbnail: &discordgo.MessageEmbedThumbnail{ - URL: config.WelcomeEmbed.Image, - }, - } - s.ChannelMessageSendEmbed(m.ChannelID, embed) - embed = &discordgo.MessageEmbed{ - Author: &discordgo.MessageEmbedAuthor{}, - Color: embedColor, - Fields: []*discordgo.MessageEmbedField{ - &discordgo.MessageEmbedField{ - Name: config.WelcomeEmbed.RulesTitle, - Value: config.WelcomeEmbed.RulesText, - Inline: true, - }, - }, - } - s.ChannelMessageSendEmbed(m.ChannelID, embed) - embed = &discordgo.MessageEmbed{ - Author: &discordgo.MessageEmbedAuthor{}, - Color: embedColor, - Fields: []*discordgo.MessageEmbedField{ - &discordgo.MessageEmbedField{ - Name: config.WelcomeEmbed.RulesTitle, - Value: config.WelcomeEmbed.RulesText2, - Inline: true, - }, - }, - } - s.ChannelMessageSendEmbed(m.ChannelID, embed) - } -*/ -} - diff --git a/types.go b/types.go deleted file mode 100644 index 9c0053a..0000000 --- a/types.go +++ /dev/null @@ -1,20 +0,0 @@ -package main - -type CommandType int - -const ( - CommandTypePrefix CommandType = 0 - CommandTypeFullMatch CommandType = 1 - CommandTypeRegex CommandType = 2 -) - -type Command struct { - Input string - Output string - Type CommandType - OutputIsReply bool - DeleteInput bool - DMOnly bool -} - - diff --git a/welcome.go b/welcome.go new file mode 100644 index 0000000..64977cb --- /dev/null +++ b/welcome.go @@ -0,0 +1,29 @@ +package main + +import ( + "github.com/bwmarrin/discordgo" + "fmt" +) + +func getWelcomeEmbed() *discordgo.MessageEmbed { + return &discordgo.MessageEmbed { + Author: &discordgo.MessageEmbedAuthor{}, + Color: 0xffb90f, + Description: config.WelcomeEmbed.Message, + Fields: []*discordgo.MessageEmbedField { + &discordgo.MessageEmbedField { + Name: config.WelcomeEmbed.QuestionsTitle, + Value: config.WelcomeEmbed.QuestionsText, + Inline: true, + }, + &discordgo.MessageEmbedField { + Name: config.WelcomeEmbed.BugsTitle, + Value: fmt.Sprintf(config.WelcomeEmbed.BugsText, config.AdminID), + Inline: true, + }, + }, + Thumbnail: &discordgo.MessageEmbedThumbnail{ + URL: config.WelcomeEmbed.Image, + }, + } +}