diff --git a/config.go b/config.go index 5270b8c..ac0e179 100644 --- a/config.go +++ b/config.go @@ -14,37 +14,6 @@ import ( "github.com/bwmarrin/discordgo" ) -func rebootBump() { - time.Sleep(time.Until(config.BumpTime.Add(2 * time.Hour))) - dg.ChannelMessageSend(config.AdminChannel, "!d bump is ready") - -} - -func storeVerification(v Verification) { - defer log.PanicSafe() - fileURL, _ := url.Parse(v.Photo) - path := fileURL.Path - segments := strings.Split(path, "/") - - fileName := segments[len(segments)-1] - file, _ := os.Create(fmt.Sprintf("./verifications/%s-%s-%s", v.UserID, v.Username, fileName)) - client := http.Client{ - CheckRedirect: func(r *http.Request, via []*http.Request) error { - r.URL.Opaque = r.URL.Path - return nil - }, - } - resp, err := client.Get(v.Photo) - if err != nil { - log.LogError("Unable to download verification %s-%s-%s", v.UserID, v.Username, fileName) - } - defer resp.Body.Close() - defer file.Close() - _, err = io.Copy(file, resp.Body) - if err != nil { - log.LogError("Unable to store verification %s-%s-%s", v.UserID, v.Username, fileName) - } -} func loadConfig() { var c Config confFile, _ := ioutil.ReadFile(configFile) @@ -89,6 +58,23 @@ func saveConfig() { } } +func adminInteraction(s *discordgo.Session, m string) { + admin, _ := s.GuildMember(config.GuildID, m) + counter, ok := config.Stats[admin.User.ID] + if !ok { + config.Stats[admin.User.ID] = 0 + } else { + config.Stats[admin.User.ID] = counter + 1 + } + +} + +func rebootBump() { + time.Sleep(time.Until(config.BumpTime.Add(2 * time.Hour))) + dg.ChannelMessageSend(config.AdminChannel, "!d bump is ready") + +} + func bumpTimer(s *discordgo.Session) { if !bump { return @@ -102,6 +88,7 @@ func bumpTimer(s *discordgo.Session) { s.ChannelMessageSend(config.AdminChannel, "!d bump is ready.") bump = true } + func purgeTimer(s *discordgo.Session) { for { runPurge(s) @@ -124,13 +111,28 @@ func (v Verification) prettyPrint() string { return ret } -func adminInteraction(s *discordgo.Session, m string) { - admin, _ := s.GuildMember(config.GuildID, m) - counter, ok := config.Stats[admin.User.ID] - if !ok { - config.Stats[admin.User.ID] = 0 - } else { - config.Stats[admin.User.ID] = counter + 1 - } +func storeVerification(v Verification) { + defer log.PanicSafe() + fileURL, _ := url.Parse(v.Photo) + path := fileURL.Path + segments := strings.Split(path, "/") + fileName := segments[len(segments)-1] + file, _ := os.Create(fmt.Sprintf("./verifications/%s-%s-%s", v.UserID, v.Username, fileName)) + client := http.Client{ + CheckRedirect: func(r *http.Request, via []*http.Request) error { + r.URL.Opaque = r.URL.Path + return nil + }, + } + resp, err := client.Get(v.Photo) + if err != nil { + log.LogError("Unable to download verification %s-%s-%s", v.UserID, v.Username, fileName) + } + defer resp.Body.Close() + defer file.Close() + _, err = io.Copy(file, resp.Body) + if err != nil { + log.LogError("Unable to store verification %s-%s-%s", v.UserID, v.Username, fileName) + } } diff --git a/discordEvents.go b/discordEvents.go new file mode 100644 index 0000000..0942036 --- /dev/null +++ b/discordEvents.go @@ -0,0 +1,116 @@ +package main + +import ( + "fmt" + "time" + + "github.com/bwmarrin/discordgo" +) + +func ready(s *discordgo.Session, event *discordgo.Ready) { + // Set the playing status. + s.UpdateGameStatus(0, fmt.Sprintf("DreamDaddy v%+v %+v", version, gitCommit)) +} + +func guildMemberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) { + defer log.PanicSafe() + for role := range m.Roles { + if fmt.Sprintf("%+v", role) == config.MonitorRole { + s.ChannelMessageSend(config.AdminChannel, "New unverified user detected.") + s.ChannelMessageSend(config.MonitorChann, fmt.Sprintf("Welcome %+v, you may PM me your verification, or I will ban you in an hour!\nSay \"!rules\" in this channel, without quotes for the rules. You may private/direct message me for verification instructions.\n\nYou will not be able to read/see other channels or users until you verify.", m.User.Mention())) + config.Unverified[m.User.ID] = time.Now() + config.Probations[m.User.ID] = time.Now() + saveConfig() + } + } + +} + +func guildMemberAdd(s *discordgo.Session, m *discordgo.GuildMemberAdd) { + defer log.PanicSafe() + config.Unverified[m.User.ID] = time.Now() + config.Probations[m.User.ID] = time.Now() + s.GuildMemberRoleAdd(config.GuildID, m.User.ID, config.MonitorRole) + s.ChannelMessageSend(config.MonitorChann, fmt.Sprintf("Welcome %+v, you may PM me your verification, or I will ban you in an hour!\nSay \"!rules\" in this channel, without quotes for the rules. You may private/direct message me for verification instructions.\n\nYou will not be able to read/see other channels or users until you verify.", m.User.Mention())) + saveConfig() +} + +func guildMemberBanned(s *discordgo.Session, m *discordgo.GuildBanAdd) { + defer log.PanicSafe() + for uid := range config.Probations { + if m.User.Email == uid { + delete(config.Probations, uid) + s.ChannelMessageDelete(config.IntroChann, introMsg[uid]) + } + } + saveConfig() +} + +func guildMemberRemove(s *discordgo.Session, m *discordgo.GuildMemberRemove) { + defer log.PanicSafe() + go runPurge(s) + banned := false + for uid, join := range config.Probations { + if time.Since(join) < 2*time.Hour { + if m.User.ID == uid { + banned = true + s.GuildBanCreateWithReason(config.GuildID, m.User.ID, fmt.Sprintf("Left within 2 hours of joining. %+v", time.Since(join)), 0) + delete(config.Probations, uid) + s.ChannelMessageDelete(config.IntroChann, introMsg[uid]) + } + } else { + delete(config.Probations, uid) + s.ChannelMessageDelete(config.IntroChann, introMsg[uid]) + } + } + s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v (@%+v) has left, ban: %+v", m.User.ID, m.User.Username, banned)) + delete(config.Unverified, m.User.ID) + for msg, v := range config.Verifications { + if v.UserID == m.User.ID { + delete(config.Verifications, msg) + s.ChannelMessageDelete(config.IntroChann, introMsg[m.User.ID]) + } + } + saveConfig() + +} + +func readReaction(s *discordgo.Session, m *discordgo.MessageReactionAdd) { + defer log.PanicSafe() + if m.ChannelID != config.AdminChannel || m.UserID == s.State.User.ID { + return + } + admin, _ := s.GuildMember(config.GuildID, m.UserID) + adminInteraction(s, admin.User.ID) + verification, ok := config.Verifications[m.MessageID] + if !ok { + return + } + verification.Admin = admin.User.Username + verification.Closed = time.Now() + user := userFromID(verification.UserID) + if user.ID == "" { + s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v, that user was not found, they might have left.", admin.Mention())) + delete(config.Verifications, m.MessageID) + return + } + if m.Emoji.Name == "👎" { + rejectVerification(s, user) + verification.Status = "Rejected" + } else if m.Emoji.Name == "👍" { + verifyMember(s, user) + verification.Status = "Accepted" + go storeVerification(verification) + } else if m.Emoji.Name == "👶" { + requestAge(s, user) + log.LogInfo("%+v has requested ASL for user %+v.", admin.User.Username, user.Username) + return + } else if m.Emoji.Name == "⛔" { + s.GuildBanCreateWithReason(config.GuildID, user.ID, fmt.Sprintf("Underage or too many failed verifications. %+v", admin.User.Username), 5) + verification.Status = "Banned" + } else { + return + } + log.LogInfo("%+v", verification.prettyPrint()) + delete(config.Verifications, m.MessageID) +} diff --git a/discordMessage.go b/discordMessage.go new file mode 100644 index 0000000..d3ace6a --- /dev/null +++ b/discordMessage.go @@ -0,0 +1,106 @@ +package main + +import ( + "fmt" + "strings" + "time" + + "github.com/bwmarrin/discordgo" +) + +func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { + defer log.PanicSafe() + var b BotCommand + if strings.HasPrefix(m.Content, s.State.User.Mention()) { + b = BotCommand{ + Session: s, + Message: m, + Parts: strings.Split(m.Content, " ")[1:], + } + } + if m.Author.ID == s.State.User.ID || m.Author.Bot { + return + } + if m.GuildID == "" { + handlePM(s, m) + return + } + if m.ChannelID == config.MonitorChann { + if strings.Contains(m.Content, "erif") && !m.Author.Bot { + s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("%+v send me a private message for verification.", m.Author.Mention())) + } + return + } + for role := range m.Member.Roles { + if fmt.Sprintf("%+v", role) == config.AdminRole { + adminInteraction(s, m.Author.ID) + } + } + if m.ChannelID != config.AdminChannel { + lastActiveChan = m.ChannelID + lastActiveTime = time.Now() + } + if strings.HasPrefix(m.Content, "!d bump") { + if time.Since(config.BumpTime) < 2*time.Hour { + s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Sorry, <@%+v> already claimed the bump. Better luck next time!", config.LastBumper)) + return + } + config.LastBumper = m.Author.ID + go bumpTimer(s) + return + } + if time.Since(config.BumpTime) > 2*time.Hour { + s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("%+v please say \"!d bump\" without the quotes to bump our server :)", m.Author.Mention())) + } + if m.ChannelID == config.AdminChannel { + if strings.HasPrefix(m.Content, s.State.User.Mention()) { + for _, cmd := range commands { + for _, keyword := range cmd.Keywords { + if strings.Contains(m.Content, keyword) { + b.Command = keyword + if !cmd.Exec(b) { + s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("There was an error running %+v\n%+v", cmd.Name, cmd.Help)) + } + } + } + } + } + } +} + +func handlePM(s *discordgo.Session, m *discordgo.MessageCreate) { + defer log.PanicSafe() + if strings.Contains(m.Content, "Rule") || strings.Contains(m.Content, "rule") { + s.ChannelMessageSend(m.ChannelID, "I specifically said to say \"!rules\" without quotes in the unverified channel for the rules.") + } + for _, uid := range config.Verifications { + user := userFromID(uid.UserID) + if m.Author.ID == user.ID { + s.ChannelMessageSend(m.ChannelID, "Your verification is pending. An admin will respond to it when they are available.") + s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v said: %+v", m.Author.Mention(), m.Content)) + return + } + } + if len(m.Attachments) != 1 { + s.ChannelMessageSend(m.ChannelID, "```I am a bot and this is an autoreply.\n\nUntil you send a verification, I will always say the following message:```\nYou may only send me your verification (and nothing else) to be passed to the admins (and no one else). Verification is a clear full face pic, with your pinky finger held to the corner of your mouth.") + s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v said: %+v", m.Author.Mention(), m.Content)) + return + } + if strings.HasSuffix(strings.ToUpper(m.Attachments[0].ProxyURL), "HEIC") { + s.ChannelMessageSend(m.ChannelID, "You have tried to send an unsupported file (HEIC). Please try again using an image (jpeg, jpg, png, etc).") + return + } + delete(config.Unverified, m.Author.ID) + var v Verification + v.Submitted = time.Now() + v.UserID = m.Author.ID + v.Username = m.Author.Username + v.Photo = m.Attachments[0].ProxyURL + v.Status = "Submitted" + msg, _ := s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v\n%+v", v.Username, v.Photo)) + config.Verifications[msg.ID] = v + s.MessageReactionAdd(config.AdminChannel, msg.ID, "👎") + s.MessageReactionAdd(config.AdminChannel, msg.ID, "👍") + s.MessageReactionAdd(config.AdminChannel, msg.ID, "👶") + s.MessageReactionAdd(config.AdminChannel, msg.ID, "⛔") +} diff --git a/main.go b/main.go index 1500a62..e26df60 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,6 @@ import ( "math/rand" "os" "os/signal" - "strings" "syscall" "time" @@ -30,7 +29,7 @@ var ( lastPM = make(map[string]time.Time) introMsg = make(map[string]string) quotes = []string{"The hardest choices require the strongest wills.", "You're strong, but I could snap my fingers and you'd all cease to exist.", "Fun isn't something one considers when balancing the universe. But this... does put a smile on my face.", "Perfectly balanced, as all things should be.", "I am inevitable."} - version = "2.7" + version = "3.0" gitCommit string commands []Command ) @@ -69,6 +68,7 @@ func main() { dg.AddHandler(guildMemberRemove) dg.AddHandler(guildMemberAdd) dg.AddHandler(guildMemberBanned) + go setupCommands() dg.AddHandler(messageCreate) dg.AddHandler(readReaction) dg.AddHandler(guildMemberUpdate) @@ -156,74 +156,6 @@ func runPurge(s *discordgo.Session) { saveConfig() } -func ready(s *discordgo.Session, event *discordgo.Ready) { - // Set the playing status. - s.UpdateGameStatus(0, fmt.Sprintf("DreamDaddy v%+v %+v", version, gitCommit)) -} - -func guildMemberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate) { - defer log.PanicSafe() - for role := range m.Roles { - if fmt.Sprintf("%+v", role) == config.MonitorRole { - s.ChannelMessageSend(config.AdminChannel, "New unverified user detected.") - s.ChannelMessageSend(config.MonitorChann, fmt.Sprintf("Welcome %+v, you may PM me your verification, or I will ban you in an hour!\nSay \"!rules\" in this channel, without quotes for the rules. You may private/direct message me for verification instructions.\n\nYou will not be able to read/see other channels or users until you verify.", m.User.Mention())) - config.Unverified[m.User.ID] = time.Now() - config.Probations[m.User.ID] = time.Now() - saveConfig() - } - } - -} - -func guildMemberAdd(s *discordgo.Session, m *discordgo.GuildMemberAdd) { - defer log.PanicSafe() - config.Unverified[m.User.ID] = time.Now() - config.Probations[m.User.ID] = time.Now() - s.GuildMemberRoleAdd(config.GuildID, m.User.ID, config.MonitorRole) - s.ChannelMessageSend(config.MonitorChann, fmt.Sprintf("Welcome %+v, you may PM me your verification, or I will ban you in an hour!\nSay \"!rules\" in this channel, without quotes for the rules. You may private/direct message me for verification instructions.\n\nYou will not be able to read/see other channels or users until you verify.", m.User.Mention())) - saveConfig() -} - -func guildMemberBanned(s *discordgo.Session, m *discordgo.GuildBanAdd) { - defer log.PanicSafe() - for uid := range config.Probations { - if m.User.Email == uid { - delete(config.Probations, uid) - s.ChannelMessageDelete(config.IntroChann, introMsg[uid]) - } - } - saveConfig() -} - -func guildMemberRemove(s *discordgo.Session, m *discordgo.GuildMemberRemove) { - defer log.PanicSafe() - go runPurge(s) - banned := false - for uid, join := range config.Probations { - if time.Since(join) < 2*time.Hour { - if m.User.ID == uid { - banned = true - s.GuildBanCreateWithReason(config.GuildID, m.User.ID, fmt.Sprintf("Left within 2 hours of joining. %+v", time.Since(join)), 0) - delete(config.Probations, uid) - s.ChannelMessageDelete(config.IntroChann, introMsg[uid]) - } - } else { - delete(config.Probations, uid) - s.ChannelMessageDelete(config.IntroChann, introMsg[uid]) - } - } - s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v (@%+v) has left, ban: %+v", m.User.ID, m.User.Username, banned)) - delete(config.Unverified, m.User.ID) - for msg, v := range config.Verifications { - if v.UserID == m.User.ID { - delete(config.Verifications, msg) - s.ChannelMessageDelete(config.IntroChann, introMsg[m.User.ID]) - } - } - saveConfig() - -} - func verifyMember(s *discordgo.Session, u discordgo.User) { defer log.PanicSafe() s.GuildMemberRoleAdd(config.GuildID, u.ID, config.VerifiedRole) @@ -249,140 +181,3 @@ func requestAge(s *discordgo.Session, u discordgo.User) { s.ChannelMessageSend(st.ID, "What is your ASL? (Age/Sex/Language) Please note, this is NOT requesting your gender, but your biological sex. Gender is a social construct, sex is biology and in the context of pornographic images more important.") } - -func handlePM(s *discordgo.Session, m *discordgo.MessageCreate) { - defer log.PanicSafe() - if strings.Contains(m.Content, "Rule") || strings.Contains(m.Content, "rule") { - s.ChannelMessageSend(m.ChannelID, "I specifically said to say \"!rules\" without quotes in the unverified channel for the rules.") - } - for _, uid := range config.Verifications { - user := userFromID(uid.UserID) - if m.Author.ID == user.ID { - s.ChannelMessageSend(m.ChannelID, "Your verification is pending. An admin will respond to it when they are available.") - s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v said: %+v", m.Author.Mention(), m.Content)) - return - } - } - if len(m.Attachments) != 1 { - s.ChannelMessageSend(m.ChannelID, "```I am a bot and this is an autoreply.\n\nUntil you send a verification, I will always say the following message:```\nYou may only send me your verification (and nothing else) to be passed to the admins (and no one else). Verification is a clear full face pic, with your pinky finger held to the corner of your mouth.") - s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v said: %+v", m.Author.Mention(), m.Content)) - return - } - if strings.HasSuffix(strings.ToUpper(m.Attachments[0].ProxyURL), "HEIC") { - s.ChannelMessageSend(m.ChannelID, "You have tried to send an unsupported file (HEIC). Please try again using an image (jpeg, jpg, png, etc).") - return - } - delete(config.Unverified, m.Author.ID) - var v Verification - v.Submitted = time.Now() - v.UserID = m.Author.ID - v.Username = m.Author.Username - v.Photo = m.Attachments[0].ProxyURL - v.Status = "Submitted" - msg, _ := s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v\n%+v", v.Username, v.Photo)) - config.Verifications[msg.ID] = v - s.MessageReactionAdd(config.AdminChannel, msg.ID, "👎") - s.MessageReactionAdd(config.AdminChannel, msg.ID, "👍") - s.MessageReactionAdd(config.AdminChannel, msg.ID, "👶") - s.MessageReactionAdd(config.AdminChannel, msg.ID, "⛔") -} - -func readReaction(s *discordgo.Session, m *discordgo.MessageReactionAdd) { - defer log.PanicSafe() - if m.ChannelID != config.AdminChannel || m.UserID == s.State.User.ID { - return - } - admin, _ := s.GuildMember(config.GuildID, m.UserID) - adminInteraction(s, admin.User.ID) - verification, ok := config.Verifications[m.MessageID] - if !ok { - return - } - verification.Admin = admin.User.Username - verification.Closed = time.Now() - user := userFromID(verification.UserID) - if user.ID == "" { - s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v, that user was not found, they might have left.", admin.Mention())) - delete(config.Verifications, m.MessageID) - return - } - if m.Emoji.Name == "👎" { - rejectVerification(s, user) - verification.Status = "Rejected" - } else if m.Emoji.Name == "👍" { - verifyMember(s, user) - verification.Status = "Accepted" - go storeVerification(verification) - } else if m.Emoji.Name == "👶" { - requestAge(s, user) - log.LogInfo("%+v has requested ASL for user %+v.", admin.User.Username, user.Username) - return - } else if m.Emoji.Name == "⛔" { - s.GuildBanCreateWithReason(config.GuildID, user.ID, fmt.Sprintf("Underage or too many failed verifications. %+v", admin.User.Username), 5) - verification.Status = "Banned" - } else { - return - } - log.LogInfo("%+v", verification.prettyPrint()) - delete(config.Verifications, m.MessageID) -} - -func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) { - defer log.PanicSafe() - var b BotCommand - if strings.HasPrefix(m.Content, s.State.User.Mention()) { - b = BotCommand{ - Session: s, - Message: m, - Parts: strings.Split(m.Content, " ")[1:], - } - } - if m.Author.ID == s.State.User.ID || m.Author.Bot { - return - } - if m.GuildID == "" { - handlePM(s, m) - return - } - if m.ChannelID == config.MonitorChann { - if strings.Contains(m.Content, "erif") && !m.Author.Bot { - s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("%+v send me a private message for verification.", m.Author.Mention())) - } - return - } - for role := range m.Member.Roles { - if fmt.Sprintf("%+v", role) == config.AdminRole { - adminInteraction(s, m.Author.ID) - } - } - if m.ChannelID != config.AdminChannel { - lastActiveChan = m.ChannelID - lastActiveTime = time.Now() - } - if strings.HasPrefix(m.Content, "!d bump") { - if time.Since(config.BumpTime) < 2*time.Hour { - s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Sorry, <@%+v> already claimed the bump. Better luck next time!", config.LastBumper)) - return - } - config.LastBumper = m.Author.ID - go bumpTimer(s) - return - } - if time.Since(config.BumpTime) > 2*time.Hour { - s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("%+v please say \"!d bump\" without the quotes to bump our server :)", m.Author.Mention())) - } - if m.ChannelID == config.AdminChannel { - if strings.HasPrefix(m.Content, s.State.User.Mention()) { - for _, cmd := range commands { - for _, keyword := range cmd.Keywords { - if strings.Contains(m.Content, keyword) { - b.Command = keyword - if !cmd.Exec(b) { - s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("There was an error running %+v\n%+v", cmd.Name, cmd.Help)) - } - } - } - } - } - } -}