gofmt all the things
This commit is contained in:
parent
6e7229d787
commit
4566ffc230
@ -4,6 +4,7 @@ Updates are listed in reverse chronological order.
|
||||
### 1.4 (dev)
|
||||
- a copy of each deleted message is now send via DM to the author (suggested by CommanderLook)
|
||||
- seasonal fluff
|
||||
- finally use gofmt
|
||||
|
||||
### 1.3
|
||||
- use global array of pointers to commands to allow easier modification and avoid unnecessary memcpy
|
||||
|
412
command.go
412
command.go
@ -1,257 +1,255 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/deckarep/golang-set"
|
||||
"strings"
|
||||
"time"
|
||||
"log"
|
||||
"regexp"
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/deckarep/golang-set"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type CommandType int
|
||||
|
||||
// These are used to specify Command.CommandType when registering new commands
|
||||
const (
|
||||
CommandTypePrefix CommandType = 0
|
||||
CommandTypeFullMatch CommandType = 1
|
||||
CommandTypeRegex CommandType = 2
|
||||
CommandTypeContains CommandType = 3
|
||||
CommandTypePrefix CommandType = 0
|
||||
CommandTypeFullMatch CommandType = 1
|
||||
CommandTypeRegex CommandType = 2
|
||||
CommandTypeContains CommandType = 3
|
||||
)
|
||||
|
||||
/*
|
||||
This struct represents a command object.
|
||||
The options should be self-explanatory, but they are also explained in the readme.
|
||||
A struct can be initialized by passing any number of its attributes as parameters.
|
||||
Everything not set will be set to the go-usual defaults ("" for string, 0 for int, false for bool, nil for the rest)
|
||||
Any command that has a Trigger is valid (but useless if nothing else is specified)
|
||||
*/
|
||||
/*
|
||||
This struct represents a command object.
|
||||
The options should be self-explanatory, but they are also explained in the readme.
|
||||
A struct can be initialized by passing any number of its attributes as parameters.
|
||||
Everything not set will be set to the go-usual defaults ("" for string, 0 for int, false for bool, nil for the rest)
|
||||
Any command that has a Trigger is valid (but useless if nothing else is specified)
|
||||
*/
|
||||
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
|
||||
Cooldown int // defaults to 0 (no cooldown)
|
||||
OutputIsReply bool
|
||||
RequiresMention bool
|
||||
DeleteInput bool
|
||||
DMOnly bool
|
||||
AdminOnly bool
|
||||
IgnoreCase bool
|
||||
// for custom commands that go beyond prints and deletions
|
||||
Function func(*discordgo.Session, *discordgo.MessageCreate)
|
||||
Trigger string // must be specified
|
||||
Output string // no output if unspecified
|
||||
OutputEmbed *discordgo.MessageEmbed // no embed output if unspecified
|
||||
Type CommandType // defaults to Prefix
|
||||
Cooldown int // defaults to 0 (no cooldown)
|
||||
OutputIsReply bool
|
||||
RequiresMention bool
|
||||
DeleteInput bool
|
||||
DMOnly bool
|
||||
AdminOnly bool
|
||||
IgnoreCase bool
|
||||
// for custom commands that go beyond prints and deletions
|
||||
Function func(*discordgo.Session, *discordgo.MessageCreate)
|
||||
|
||||
UsersOnCooldown mapset.Set // don’t set this manually (it’s overwritten anyway)
|
||||
UsersOnCooldown mapset.Set // don’t set this manually (it’s overwritten anyway)
|
||||
}
|
||||
|
||||
|
||||
// Performs basic input validation on a given command and adds it to the global command array
|
||||
func registerCommand(command Command) {
|
||||
if command.Trigger == "" {
|
||||
fmt.Println("Cannot register a command with no trigger. Skipping.")
|
||||
return
|
||||
}
|
||||
if command.IgnoreCase {
|
||||
command.Trigger = strings.ToLower(command.Trigger)
|
||||
}
|
||||
command.UsersOnCooldown = mapset.NewSet()
|
||||
commands = append(commands, &command)
|
||||
if command.Trigger == "" {
|
||||
fmt.Println("Cannot register a command with no trigger. Skipping.")
|
||||
return
|
||||
}
|
||||
if command.IgnoreCase {
|
||||
command.Trigger = strings.ToLower(command.Trigger)
|
||||
}
|
||||
command.UsersOnCooldown = mapset.NewSet()
|
||||
commands = append(commands, &command)
|
||||
}
|
||||
|
||||
/*
|
||||
Any message that the bot can read is evaluated here.
|
||||
The message is matched against each of the command triggers depending on the respective match type.
|
||||
If one of the commands matches, execute that command and return.
|
||||
Only one command can be executed per message. Earlier defined commands take precedence.
|
||||
This is a deliberate choice (for now).
|
||||
*/
|
||||
/*
|
||||
Any message that the bot can read is evaluated here.
|
||||
The message is matched against each of the command triggers depending on the respective match type.
|
||||
If one of the commands matches, execute that command and return.
|
||||
Only one command can be executed per message. Earlier defined commands take precedence.
|
||||
This is a deliberate choice (for now).
|
||||
*/
|
||||
func evaluateMessage(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
if m.Author.ID == s.State.User.ID {
|
||||
log.Printf("<Self> %s", m.Content)
|
||||
return
|
||||
}
|
||||
for _, command := range commands {
|
||||
content := m.Content
|
||||
if command.IgnoreCase {
|
||||
content = strings.ToLower(content)
|
||||
}
|
||||
if command.RequiresMention {
|
||||
command.Trigger = fmt.Sprintf(command.Trigger, s.State.User.ID)
|
||||
}
|
||||
switch command.Type {
|
||||
case CommandTypePrefix:
|
||||
if strings.HasPrefix(content, command.Trigger) {
|
||||
executeCommand(s, m, command)
|
||||
return
|
||||
}
|
||||
case CommandTypeFullMatch:
|
||||
if content == command.Trigger {
|
||||
executeCommand(s, m, command)
|
||||
return
|
||||
}
|
||||
case CommandTypeRegex:
|
||||
match, _ := regexp.MatchString(command.Trigger, content)
|
||||
if match {
|
||||
executeCommand(s, m, command)
|
||||
return
|
||||
}
|
||||
case CommandTypeContains:
|
||||
if strings.Contains(content, command.Trigger) {
|
||||
executeCommand(s, m, command)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if m.Author.ID == s.State.User.ID {
|
||||
log.Printf("<Self> %s", m.Content)
|
||||
return
|
||||
}
|
||||
for _, command := range commands {
|
||||
content := m.Content
|
||||
if command.IgnoreCase {
|
||||
content = strings.ToLower(content)
|
||||
}
|
||||
if command.RequiresMention {
|
||||
command.Trigger = fmt.Sprintf(command.Trigger, s.State.User.ID)
|
||||
}
|
||||
switch command.Type {
|
||||
case CommandTypePrefix:
|
||||
if strings.HasPrefix(content, command.Trigger) {
|
||||
executeCommand(s, m, command)
|
||||
return
|
||||
}
|
||||
case CommandTypeFullMatch:
|
||||
if content == command.Trigger {
|
||||
executeCommand(s, m, command)
|
||||
return
|
||||
}
|
||||
case CommandTypeRegex:
|
||||
match, _ := regexp.MatchString(command.Trigger, content)
|
||||
if match {
|
||||
executeCommand(s, m, command)
|
||||
return
|
||||
}
|
||||
case CommandTypeContains:
|
||||
if strings.Contains(content, command.Trigger) {
|
||||
executeCommand(s, m, command)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Executes the given command on the given message and session.
|
||||
Sets command cooldowns if necessary and also clears them again.
|
||||
*/
|
||||
/*
|
||||
Executes the given command on the given message and session.
|
||||
Sets command cooldowns if necessary and also clears them again.
|
||||
*/
|
||||
func executeCommand(session *discordgo.Session, message *discordgo.MessageCreate, command *Command) {
|
||||
if isAdmin(message.Author) || // no restrictions for admins
|
||||
(!command.AdminOnly && (isDM(session, message) || !command.UsersOnCooldown.Contains(message.Author.ID)) &&
|
||||
(!command.DMOnly || isDM(session, message))) {
|
||||
if isAdmin(message.Author) || // no restrictions for admins
|
||||
(!command.AdminOnly && (isDM(session, message) || !command.UsersOnCooldown.Contains(message.Author.ID)) &&
|
||||
(!command.DMOnly || isDM(session, message))) {
|
||||
|
||||
log.Printf("Executed command %s triggered by user %s", command.Trigger, userToString(message.Author))
|
||||
if command.Cooldown > 0 && !isDM(session, message) && !isAdmin(message.Author) {
|
||||
command.UsersOnCooldown.Add(message.Author.ID)
|
||||
go removeCooldown(command, message.Author.ID)
|
||||
}
|
||||
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 {
|
||||
deleteAndSendViaDM(session, message)
|
||||
}
|
||||
} else {
|
||||
// execute custom function
|
||||
command.Function(session, message)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Denied command %s to user %s.", command.Trigger, userToString(message.Author))
|
||||
}
|
||||
log.Printf("Executed command %s triggered by user %s", command.Trigger, userToString(message.Author))
|
||||
if command.Cooldown > 0 && !isDM(session, message) && !isAdmin(message.Author) {
|
||||
command.UsersOnCooldown.Add(message.Author.ID)
|
||||
go removeCooldown(command, message.Author.ID)
|
||||
}
|
||||
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 {
|
||||
deleteAndSendViaDM(session, message)
|
||||
}
|
||||
} else {
|
||||
// execute custom function
|
||||
command.Function(session, message)
|
||||
}
|
||||
} else {
|
||||
log.Printf("Denied command %s to user %s.", command.Trigger, userToString(message.Author))
|
||||
}
|
||||
}
|
||||
|
||||
func removeCooldown(command *Command, uid string) {
|
||||
time.Sleep(time.Duration(command.Cooldown) * time.Second)
|
||||
if command.UsersOnCooldown.Contains(uid) {
|
||||
command.UsersOnCooldown.Remove(uid)
|
||||
}
|
||||
time.Sleep(time.Duration(command.Cooldown) * time.Second)
|
||||
if command.UsersOnCooldown.Contains(uid) {
|
||||
command.UsersOnCooldown.Remove(uid)
|
||||
}
|
||||
}
|
||||
|
||||
func deleteAndSendViaDM(s *discordgo.Session, message *discordgo.MessageCreate) {
|
||||
s.ChannelMessageDelete(message.ChannelID, message.ID)
|
||||
dm := getDMChannelFromMessage(s, message)
|
||||
s.ChannelMessageSend(dm.ID, "Deine Nachricht wurde gelöscht, weil sie ein verbotenes Wort enthielt. Falls du sie editieren und erneut abschicken willst, hier die Nachricht:")
|
||||
s.ChannelMessageSend(dm.ID, message.Content)
|
||||
s.ChannelMessageDelete(message.ChannelID, message.ID)
|
||||
dm := getDMChannelFromMessage(s, message)
|
||||
s.ChannelMessageSend(dm.ID, "Deine Nachricht wurde gelöscht, weil sie ein verbotenes Wort enthielt. Falls du sie editieren und erneut abschicken willst, hier die Nachricht:")
|
||||
s.ChannelMessageSend(dm.ID, message.Content)
|
||||
}
|
||||
|
||||
func generateReply(message *discordgo.MessageCreate, command *Command) string {
|
||||
output := command.Output
|
||||
if command.OutputIsReply {
|
||||
output = fmt.Sprintf(output, message.Author.ID)
|
||||
}
|
||||
return output
|
||||
output := command.Output
|
||||
if command.OutputIsReply {
|
||||
output = fmt.Sprintf(output, message.Author.ID)
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
/*
|
||||
Any message passed to this method will be redirected to config.ModChannel.
|
||||
This is useful for anonymous complaints or similar messages.
|
||||
*/
|
||||
/*
|
||||
Any message passed to this method will be redirected to config.ModChannel.
|
||||
This is useful for anonymous complaints or similar messages.
|
||||
*/
|
||||
func redirectComplaint(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
embed := &discordgo.MessageEmbed {
|
||||
Author: &discordgo.MessageEmbedAuthor{},
|
||||
Color: 0xbb0000,
|
||||
Description: m.Content,
|
||||
}
|
||||
s.ChannelMessageSendEmbed(config.ModChannel, embed)
|
||||
dm, _ := s.UserChannelCreate(m.Author.ID)
|
||||
s.ChannelMessageSend(dm.ID, config.ComplaintReceivedMessage)
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Author: &discordgo.MessageEmbedAuthor{},
|
||||
Color: 0xbb0000,
|
||||
Description: m.Content,
|
||||
}
|
||||
s.ChannelMessageSendEmbed(config.ModChannel, embed)
|
||||
dm, _ := s.UserChannelCreate(m.Author.ID)
|
||||
s.ChannelMessageSend(dm.ID, config.ComplaintReceivedMessage)
|
||||
}
|
||||
|
||||
// copy paste programming btw :haHAA:
|
||||
func redirectComplaintToDM(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
embed := &discordgo.MessageEmbed {
|
||||
Author: &discordgo.MessageEmbedAuthor{},
|
||||
Color: 0xbb0000,
|
||||
Description: m.Content,
|
||||
}
|
||||
dm_target, _ := s.UserChannelCreate("190958368301645824")
|
||||
s.ChannelMessageSendEmbed(dm_target.ID, embed)
|
||||
dm, _ := s.UserChannelCreate(m.Author.ID)
|
||||
s.ChannelMessageSend(dm.ID, config.ComplaintReceivedMessage)
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Author: &discordgo.MessageEmbedAuthor{},
|
||||
Color: 0xbb0000,
|
||||
Description: m.Content,
|
||||
}
|
||||
dm_target, _ := s.UserChannelCreate("190958368301645824")
|
||||
s.ChannelMessageSendEmbed(dm_target.ID, embed)
|
||||
dm, _ := s.UserChannelCreate(m.Author.ID)
|
||||
s.ChannelMessageSend(dm.ID, config.ComplaintReceivedMessage)
|
||||
}
|
||||
|
||||
func echoMessage(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
s.ChannelMessageSend(m.ChannelID, m.Content)
|
||||
s.ChannelMessageSend(m.ChannelID, m.Content)
|
||||
}
|
||||
|
||||
func giveAgeRole(s *discordgo.Session, m *discordgo.MessageCreate) {
|
||||
Member, _ := s.GuildMember(config.ServerID, m.Author.ID)
|
||||
dm, _ := s.UserChannelCreate(Member.User.ID)
|
||||
for command, role := range config.RoleCommands {
|
||||
if m.Content == command {
|
||||
// Found the command that was triggered
|
||||
// This is a restriction imposed by my own wrapper,
|
||||
// but working around it is not actually necessary for performance and makes the code uglier in other places.
|
||||
for _, newRole := range config.RoleCommands {
|
||||
for _, curRole := range Member.Roles {
|
||||
// If the user already has one of the available roles, tell him and exit
|
||||
if newRole == curRole {
|
||||
if curRole == role {
|
||||
// User is trying to get the role they already have
|
||||
s.ChannelMessageSend(dm.ID, "Baka, die Rolle hast du doch schon.")
|
||||
log.Printf("Denied Role %s to %s. User already has %s", roleName(s.State, curRole), userToString(m.Author), roleName(s.State, curRole))
|
||||
} else {
|
||||
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, curRole), userToString(m.Author), roleName(s.State, curRole))
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
Member, _ := s.GuildMember(config.ServerID, m.Author.ID)
|
||||
dm, _ := s.UserChannelCreate(Member.User.ID)
|
||||
for command, role := range config.RoleCommands {
|
||||
if m.Content == command {
|
||||
// Found the command that was triggered
|
||||
// This is a restriction imposed by my own wrapper,
|
||||
// but working around it is not actually necessary for performance and makes the code uglier in other places.
|
||||
for _, newRole := range config.RoleCommands {
|
||||
for _, curRole := range Member.Roles {
|
||||
// If the user already has one of the available roles, tell him and exit
|
||||
if newRole == curRole {
|
||||
if curRole == role {
|
||||
// User is trying to get the role they already have
|
||||
s.ChannelMessageSend(dm.ID, "Baka, die Rolle hast du doch schon.")
|
||||
log.Printf("Denied Role %s to %s. User already has %s", roleName(s.State, curRole), userToString(m.Author), roleName(s.State, curRole))
|
||||
} else {
|
||||
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, curRole), userToString(m.Author), roleName(s.State, curRole))
|
||||
}
|
||||
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 getHelpEmbed() *discordgo.MessageEmbed {
|
||||
commandList := "Im Folgenden findest du eine automatisch generierte Liste aller Commands. Um herauszufinden, was sie tun, probiere sie aus oder lies den Source Code (siehe unten).\n```- !complain\n- !scomplain\n"
|
||||
for _, command := range commands {
|
||||
if command.Type != CommandTypeRegex && !command.AdminOnly && !command.DMOnly {
|
||||
commandList += "- " + command.Trigger + "\n"
|
||||
}
|
||||
}
|
||||
commandList += "```"
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Author: &discordgo.MessageEmbedAuthor{},
|
||||
Color: 0xffb90f,
|
||||
Description: "__Hilfe__",
|
||||
Fields: []*discordgo.MessageEmbedField {
|
||||
&discordgo.MessageEmbedField {
|
||||
Name: "__Commands__",
|
||||
Value: commandList,
|
||||
Inline: true,
|
||||
},
|
||||
&discordgo.MessageEmbedField {
|
||||
Name: "__Bugs__",
|
||||
Value: fmt.Sprintf("Bei Fragen zum Bot, Vorschlägen, Bugs etc. wende dich bitte an <@%s> oder öffne eine Issue auf https://git.kageru.moe/kageru/discord-selphybot.", config.Admins[0]),
|
||||
Inline: true,
|
||||
},
|
||||
},
|
||||
Thumbnail: &discordgo.MessageEmbedThumbnail{
|
||||
URL: "https://static-cdn.jtvnw.net/emoticons/v1/1068185/3.0",
|
||||
},
|
||||
}
|
||||
return embed
|
||||
commandList := "Im Folgenden findest du eine automatisch generierte Liste aller Commands. Um herauszufinden, was sie tun, probiere sie aus oder lies den Source Code (siehe unten).\n```- !complain\n- !scomplain\n"
|
||||
for _, command := range commands {
|
||||
if command.Type != CommandTypeRegex && !command.AdminOnly && !command.DMOnly {
|
||||
commandList += "- " + command.Trigger + "\n"
|
||||
}
|
||||
}
|
||||
commandList += "```"
|
||||
embed := &discordgo.MessageEmbed{
|
||||
Author: &discordgo.MessageEmbedAuthor{},
|
||||
Color: 0xffb90f,
|
||||
Description: "__Hilfe__",
|
||||
Fields: []*discordgo.MessageEmbedField{
|
||||
&discordgo.MessageEmbedField{
|
||||
Name: "__Commands__",
|
||||
Value: commandList,
|
||||
Inline: true,
|
||||
},
|
||||
&discordgo.MessageEmbedField{
|
||||
Name: "__Bugs__",
|
||||
Value: fmt.Sprintf("Bei Fragen zum Bot, Vorschlägen, Bugs etc. wende dich bitte an <@%s> oder öffne eine Issue auf https://git.kageru.moe/kageru/discord-selphybot.", config.Admins[0]),
|
||||
Inline: true,
|
||||
},
|
||||
},
|
||||
Thumbnail: &discordgo.MessageEmbedThumbnail{
|
||||
URL: "https://static-cdn.jtvnw.net/emoticons/v1/1068185/3.0",
|
||||
},
|
||||
}
|
||||
return embed
|
||||
}
|
||||
|
||||
|
52
config.go
52
config.go
@ -1,40 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"encoding/json"
|
||||
"encoding/json"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Embed struct {
|
||||
Message string
|
||||
QuestionsTitle string
|
||||
QuestionsText string
|
||||
BugsTitle string
|
||||
BugsText string
|
||||
Image string
|
||||
Message string
|
||||
QuestionsTitle string
|
||||
QuestionsText string
|
||||
BugsTitle string
|
||||
BugsText string
|
||||
Image string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Admins []string
|
||||
ServerID string
|
||||
LockedRoleID string
|
||||
Token string
|
||||
WelcomeChannel string
|
||||
GeneralChannel string
|
||||
SendWelcomeDM bool
|
||||
RequireAccept bool
|
||||
ComplaintReceivedMessage string
|
||||
ModChannel string
|
||||
WelcomeEmbed Embed
|
||||
RoleCommands map[string]string
|
||||
Admins []string
|
||||
ServerID string
|
||||
LockedRoleID string
|
||||
Token string
|
||||
WelcomeChannel string
|
||||
GeneralChannel string
|
||||
SendWelcomeDM bool
|
||||
RequireAccept bool
|
||||
ComplaintReceivedMessage string
|
||||
ModChannel string
|
||||
WelcomeEmbed Embed
|
||||
RoleCommands map[string]string
|
||||
}
|
||||
|
||||
|
||||
func readConfig() Config {
|
||||
file, _ := os.Open("config.json")
|
||||
conf := Config{}
|
||||
json.NewDecoder(file).Decode(&conf)
|
||||
file.Close()
|
||||
return conf
|
||||
file, _ := os.Open("config.json")
|
||||
conf := Config{}
|
||||
json.NewDecoder(file).Decode(&conf)
|
||||
file.Close()
|
||||
return conf
|
||||
}
|
||||
|
||||
|
89
events.go
89
events.go
@ -1,55 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"log"
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"log"
|
||||
)
|
||||
|
||||
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))
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
42
helpers.go
42
helpers.go
@ -1,45 +1,45 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"log"
|
||||
"fmt"
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"log"
|
||||
)
|
||||
|
||||
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)))
|
||||
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)
|
||||
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
|
||||
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)
|
||||
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)
|
||||
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
|
||||
channel, _ := s.Channel(cid)
|
||||
return channel
|
||||
}
|
||||
|
||||
func getUser(s *discordgo.Session, uid string) *discordgo.User {
|
||||
user, _ := s.User(uid)
|
||||
return user
|
||||
user, _ := s.User(uid)
|
||||
return user
|
||||
}
|
||||
|
||||
func isDM(s *discordgo.Session, m *discordgo.MessageCreate) bool {
|
||||
return (getChannel(s.State, m.ChannelID).Type == discordgo.ChannelTypeDM)
|
||||
return (getChannel(s.State, m.ChannelID).Type == discordgo.ChannelTypeDM)
|
||||
}
|
||||
|
||||
func getDMChannelFromMessage(s *discordgo.Session, m *discordgo.MessageCreate) *discordgo.Channel {
|
||||
@ -48,10 +48,10 @@ func getDMChannelFromMessage(s *discordgo.Session, m *discordgo.MessageCreate) *
|
||||
}
|
||||
|
||||
func isAdmin(u *discordgo.User) bool {
|
||||
for _, admin := range config.Admins {
|
||||
if u.ID == admin {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
for _, admin := range config.Admins {
|
||||
if u.ID == admin {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
128
main.go
128
main.go
@ -1,89 +1,87 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/signal"
|
||||
"os"
|
||||
"syscall"
|
||||
"log"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var config = readConfig()
|
||||
var commands []*Command
|
||||
|
||||
func main() {
|
||||
dg, err := discordgo.New("Bot " + config.Token)
|
||||
if err != nil {
|
||||
fmt.Println("error: ", err)
|
||||
return
|
||||
}
|
||||
defer dg.Close()
|
||||
dg, err := discordgo.New("Bot " + config.Token)
|
||||
if err != nil {
|
||||
fmt.Println("error: ", err)
|
||||
return
|
||||
}
|
||||
defer dg.Close()
|
||||
|
||||
dg.AddHandler(evaluateMessage)
|
||||
dg.AddHandler(onJoin)
|
||||
err = dg.Open()
|
||||
if err != nil {
|
||||
fmt.Println("No connection:\n", err)
|
||||
return
|
||||
}
|
||||
dg.AddHandler(evaluateMessage)
|
||||
dg.AddHandler(onJoin)
|
||||
err = dg.Open()
|
||||
if err != nil {
|
||||
fmt.Println("No connection:\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.OpenFile("selphybot.log", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
fmt.Println("Error opening log file:\n", err)
|
||||
}
|
||||
defer f.Close()
|
||||
log.SetOutput(f)
|
||||
dg.UpdateStatus(0, "!help")
|
||||
addCommands()
|
||||
f, err := os.OpenFile("selphybot.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
fmt.Println("Error opening log file:\n", err)
|
||||
}
|
||||
defer f.Close()
|
||||
log.SetOutput(f)
|
||||
dg.UpdateStatus(0, "!help")
|
||||
addCommands()
|
||||
|
||||
fmt.Println("Bot running. selphyWoo")
|
||||
log.Println("Bot running. selphyWoo")
|
||||
sc := make(chan os.Signal, 1)
|
||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
||||
<-sc
|
||||
fmt.Println("Bot running. selphyWoo")
|
||||
log.Println("Bot running. selphyWoo")
|
||||
sc := make(chan os.Signal, 1)
|
||||
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
|
||||
<-sc
|
||||
|
||||
fmt.Println("Exiting...")
|
||||
log.Println("Exiting...")
|
||||
fmt.Println("Exiting...")
|
||||
log.Println("Exiting...")
|
||||
}
|
||||
|
||||
// I’ll just put all of the commands here for now.
|
||||
func addCommands() {
|
||||
// Moderation
|
||||
registerCommand(Command{Trigger: "^[^`]*([()|DoOvVcC][-=^']?;|;[-=^']?[()|DoOpPvVcC3]|:wink:|😉)[^`]*$", Output: "<@%s> Oboe!", DeleteInput: true, OutputIsReply: true, Type: CommandTypeRegex})
|
||||
registerCommand(Command{Trigger: "(\\s|\n|^)[nN][hH]([ ?.,\n]|$)", Output: "<@%s> „nh“ ist kein Wort, du Oboe!", DeleteInput: true, OutputIsReply: true, Type: CommandTypeRegex})
|
||||
registerCommand(Command{Trigger: "einzigste", Output: "<@%s> Es heißt „einzige“, du Tuba.", DeleteInput: true, OutputIsReply: true, Type: CommandTypeContains})
|
||||
registerCommand(Command{Trigger: "!complain", Type: CommandTypePrefix, DMOnly: true, Function: redirectComplaint})
|
||||
registerCommand(Command{Trigger: "!scomplain", Type: CommandTypePrefix, DMOnly: true, Function: redirectComplaintToDM})
|
||||
registerCommand(Command{Trigger: "!beschwerde", Type: CommandTypePrefix, DMOnly: true, Function: redirectComplaint})
|
||||
// Moderation
|
||||
registerCommand(Command{Trigger: "^[^`]*([()|DoOvVcC][-=^']?;|;[-=^']?[()|DoOpPvVcC3]|:wink:|😉)[^`]*$", Output: "<@%s> Oboe!", DeleteInput: true, OutputIsReply: true, Type: CommandTypeRegex})
|
||||
registerCommand(Command{Trigger: "(\\s|\n|^)[nN][hH]([ ?.,\n]|$)", Output: "<@%s> „nh“ ist kein Wort, du Oboe!", DeleteInput: true, OutputIsReply: true, Type: CommandTypeRegex})
|
||||
registerCommand(Command{Trigger: "einzigste", Output: "<@%s> Es heißt „einzige“, du Tuba.", DeleteInput: true, OutputIsReply: true, Type: CommandTypeContains})
|
||||
registerCommand(Command{Trigger: "!complain", Type: CommandTypePrefix, DMOnly: true, Function: redirectComplaint})
|
||||
registerCommand(Command{Trigger: "!scomplain", Type: CommandTypePrefix, DMOnly: true, Function: redirectComplaintToDM})
|
||||
registerCommand(Command{Trigger: "!beschwerde", Type: CommandTypePrefix, DMOnly: true, Function: redirectComplaint})
|
||||
|
||||
for comm, _ := range config.RoleCommands {
|
||||
registerCommand(Command{Trigger: comm, Type: CommandTypeFullMatch, DMOnly: true, Function: giveAgeRole})
|
||||
}
|
||||
for comm, _ := range config.RoleCommands {
|
||||
registerCommand(Command{Trigger: comm, Type: CommandTypeFullMatch, DMOnly: true, Function: giveAgeRole})
|
||||
}
|
||||
|
||||
// Misc commands
|
||||
registerCommand(Command{Trigger: "o/", Output: "\\o", Type: CommandTypeFullMatch, Cooldown: 10})
|
||||
registerCommand(Command{Trigger: "\\o", Output: "o/", Type: CommandTypeFullMatch, Cooldown: 10})
|
||||
registerCommand(Command{Trigger: "\\o/", Output: "/o\\", Type: CommandTypeFullMatch, Cooldown: 10})
|
||||
registerCommand(Command{Trigger: "/o\\", Output: "\\o/", Type: CommandTypeFullMatch, Cooldown: 10})
|
||||
registerCommand(Command{Trigger: "!heil", Output: "(ノ・ェ・)ノ Selphy (ノ・ェ・)ノ", Type: CommandTypeFullMatch, Cooldown: 30})
|
||||
registerCommand(Command{Trigger: "ayy", Output: "lmao", Type: CommandTypeFullMatch, Cooldown: 0})
|
||||
registerCommand(Command{Trigger: "<:selphyPadoru:525766188240732180>", Output: "<:selphypadoru:526644596558659594> Padoru <:selphypadoru:526644596558659594> Padoru <:selphypadoru:526644596558659594> Pado Padoru <:selphypadoru:526644596558659594>", Type: CommandTypeFullMatch, Cooldown: 10800})
|
||||
registerCommand(Command{Trigger: "<:selphyDango:507979223244341267>", Output: "<:dango:430669469799677953> :notes: Dango Daikazoku :notes: <:dango:430669469799677953>", Type: CommandTypeFullMatch, Cooldown: 10800})
|
||||
registerCommand(Command{Trigger: "praise the sun", Output: "If only I could be so grossly incandescent \\\\[T]/", Type: CommandTypeContains, IgnoreCase: true, Cooldown: 85600})
|
||||
// Misc commands
|
||||
registerCommand(Command{Trigger: "o/", Output: "\\o", Type: CommandTypeFullMatch, Cooldown: 10})
|
||||
registerCommand(Command{Trigger: "\\o", Output: "o/", Type: CommandTypeFullMatch, Cooldown: 10})
|
||||
registerCommand(Command{Trigger: "\\o/", Output: "/o\\", Type: CommandTypeFullMatch, Cooldown: 10})
|
||||
registerCommand(Command{Trigger: "/o\\", Output: "\\o/", Type: CommandTypeFullMatch, Cooldown: 10})
|
||||
registerCommand(Command{Trigger: "!heil", Output: "(ノ・ェ・)ノ Selphy (ノ・ェ・)ノ", Type: CommandTypeFullMatch, Cooldown: 30})
|
||||
registerCommand(Command{Trigger: "ayy", Output: "lmao", Type: CommandTypeFullMatch, Cooldown: 0})
|
||||
registerCommand(Command{Trigger: "<:selphyDango:531594585424527370>", Output: "<:dango:430669469799677953> :notes: Dango Daikazoku :notes: <:dango:430669469799677953>", Type: CommandTypeFullMatch, Cooldown: 10800})
|
||||
registerCommand(Command{Trigger: "praise the sun", Output: "If only I could be so grossly incandescent \\\\[T]/", Type: CommandTypeContains, IgnoreCase: true, Cooldown: 85600})
|
||||
|
||||
// Information
|
||||
registerCommand(Command{Trigger: "!welcome", OutputEmbed: getWelcomeEmbed(), Type: CommandTypeFullMatch, DMOnly: true})
|
||||
registerCommand(Command{Trigger: "!mods", Output: "Bei Fragen, Problemen und Beschwerden wende dich bitte an die Moderatoren oder schick mir eine Nachricht beginnend mit !complain, um dich anonym zu beschweren.\nAktuell anwesende Mods werden dir rechts mit dem Rang „Maid“ angezeigt.", Type: CommandTypeFullMatch})
|
||||
// Information
|
||||
registerCommand(Command{Trigger: "!welcome", OutputEmbed: getWelcomeEmbed(), Type: CommandTypeFullMatch, DMOnly: true})
|
||||
registerCommand(Command{Trigger: "!mods", Output: "Bei Fragen, Problemen und Beschwerden wende dich bitte an die Moderatoren oder schick mir eine Nachricht beginnend mit !complain, um dich anonym zu beschweren.\nAktuell anwesende Mods werden dir rechts mit dem Rang „Maid“ angezeigt.", Type: CommandTypeFullMatch})
|
||||
|
||||
// Admin and/or debug
|
||||
registerCommand(Command{Trigger: "<@%s> <3", Output: "<@%s> <3", Type: CommandTypeFullMatch, AdminOnly: true, OutputIsReply: true, RequiresMention: true})
|
||||
registerCommand(Command{Trigger: "echo", Type: CommandTypePrefix, Function: echoMessage, AdminOnly: true})
|
||||
// Admin and/or debug
|
||||
registerCommand(Command{Trigger: "<@%s> <3", Output: "<@%s> <3", Type: CommandTypeFullMatch, AdminOnly: true, OutputIsReply: true, RequiresMention: true})
|
||||
registerCommand(Command{Trigger: "echo", Type: CommandTypePrefix, Function: echoMessage, AdminOnly: true})
|
||||
|
||||
// This needs to be the last command because getHelpEmbed is evaluated here once, not on every function call. Putting it too early will result in missing commands in the output.
|
||||
registerCommand(Command{Trigger: "!help", OutputEmbed: getHelpEmbed(), Type: CommandTypeFullMatch})
|
||||
// This needs to be the last command because getHelpEmbed is evaluated here once, not on every function call. Putting it too early will result in missing commands in the output.
|
||||
registerCommand(Command{Trigger: "!help", OutputEmbed: getHelpEmbed(), Type: CommandTypeFullMatch})
|
||||
|
||||
fmt.Printf("Successfully initialized %d commands\n", len(commands))
|
||||
log.Printf("Successfully initialized %d commands", len(commands))
|
||||
fmt.Printf("Successfully initialized %d commands\n", len(commands))
|
||||
log.Printf("Successfully initialized %d commands", len(commands))
|
||||
}
|
||||
|
||||
|
44
welcome.go
44
welcome.go
@ -1,29 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"fmt"
|
||||
"fmt"
|
||||
"github.com/bwmarrin/discordgo"
|
||||
)
|
||||
|
||||
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.Admins[0]),
|
||||
Inline: true,
|
||||
},
|
||||
},
|
||||
Thumbnail: &discordgo.MessageEmbedThumbnail{
|
||||
URL: config.WelcomeEmbed.Image,
|
||||
},
|
||||
}
|
||||
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.Admins[0]),
|
||||
Inline: true,
|
||||
},
|
||||
},
|
||||
Thumbnail: &discordgo.MessageEmbedThumbnail{
|
||||
URL: config.WelcomeEmbed.Image,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user