package main import ( "encoding/json" "fmt" "io" "io/ioutil" "net/http" "net/url" "os" "path/filepath" "strconv" "strings" "time" "github.com/bwmarrin/discordgo" ) func status(s *discordgo.Session) { defer log.PanicSafe() status := fmt.Sprintf("Uptime: %+v\n", time.Since(startupTime)) status += fmt.Sprintf("Last bump: %+v\n", time.Since(config.BumpTime)) status += fmt.Sprintf("Last bumper: <@%+v>\n", userFromID(config.LastBumper).Username) status += fmt.Sprintf("Bump needed: %+v\n", bump) if len(config.Unverified) > 0 { status += "Unverified users:\n```" for k, v := range config.Unverified { uvUser := userFromID(k) status += fmt.Sprintf("\n%+v will be removed in %+v", uvUser.Username, time.Until(v.Add(1*time.Hour))) } status += "```" } else { status += "There are no unverified users.\n" } if len(config.Verifications) > 0 { status += "Pending verifications:\n" status += "```" for _, v := range config.Verifications { status += fmt.Sprintf("%+v has submitted a verification.", v.Username) } status += "```" } else { status += "There are no pending verifications." } if len(config.Probations) > 0 { status += "\nThe following users are on probation: \n```" for uid, join := range config.Probations { probationUser := userFromID(uid) status += fmt.Sprintf("%+v for another %+v\n", probationUser.Username, time.Until(join.Add(2*time.Hour))) } status += "```" } s.ChannelMessageSend(config.AdminChannel, status) statistics := "```" for k, v := range config.Stats { adminUser, err := s.GuildMember(config.GuildID, k) if err == nil { statistics += fmt.Sprintf("\n%+v: %+v", adminUser.User.Username, v+1) } else { log.LogErrorType(err) } } statistics += "\n```" log.LogInfo("Private statistics: %+v", statistics) go runPurge(s) return } 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) err := json.Unmarshal([]byte(confFile), &c) if err != nil { log.LogErrorType(err) return } config = c if time.Since(config.BumpTime) < (2 * time.Hour) { bump = false } else { bump = true } if config.Stats == nil { config.Stats = make(map[string]int) } if config.Unverified == nil { config.Unverified = make(map[string]time.Time) } if config.Verifications == nil { config.Verifications = make(map[string]Verification) } if config.Probations == nil { config.Probations = make(map[string]time.Time) } log.LogInfo("Setup completed using config file.") } func saveConfig() { defer log.PanicSafe() file, err := json.Marshal(config) if err != nil { log.LogErrorType(err) } err = ioutil.WriteFile(configFile, file, 0600) if err != nil { log.LogErrorType(err) } } func findVerification(s *discordgo.Session, m *discordgo.MessageCreate) { defer log.PanicSafe() parts := strings.Split(m.Content, " ") discordId := parts[1] _, err := strconv.Atoi(discordId) if err != nil { discordId = idFromUsername(discordId) } user, err := s.GuildMember(config.GuildID, discordId) if err != nil { log.LogErrorType(err) } matches, err := filepath.Glob(fmt.Sprintf("./verifications/*%+v*", discordId)) if err != nil { log.LogErrorType(err) return } if len(matches) != 1 { s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Error finding verification for ID %+v", discordId)) return } verificationImage, err := os.Open(matches[0]) if err != nil { log.LogErrorType(err) return } msg := fmt.Sprintf("```%+v\nJoined: %+v\n```", user.User.Username, user.JoinedAt) s.ChannelFileSendWithMessage(m.ChannelID, msg, fmt.Sprintf("%+v Verification", discordId), verificationImage) } func bumpTimer(s *discordgo.Session) { if !bump { return } bump = false config.BumpTime = time.Now() time.Sleep(2 * time.Hour) if time.Since(lastActiveTime) < (5*time.Minute) && lastActiveChan != config.AdminChannel { s.ChannelMessageSend(lastActiveChan, "!d bump is ready, please use it. (say \"!d bump\" without the quotes)") } s.ChannelMessageSend(config.AdminChannel, "!d bump is ready.") bump = true } func purgeTimer(s *discordgo.Session) { for { runPurge(s) saveConfig() if time.Since(lastActiveTime) > 4*time.Hour && time.Since(startupTime) > 12*time.Hour { log.LogInfo("Restarting.") saveConfig() os.Exit(0) } time.Sleep(20 * time.Minute) } } func (v Verification) prettyPrint() string { ret := "" ret += fmt.Sprintf("```%+v has marked %+v's verification as %+v\n", v.Admin, v.Username, v.Status) ret += fmt.Sprintf("Submitted: %+v\nClosed: %+v\n", v.Submitted, v.Closed) ret += fmt.Sprintf("Turnaround time: %+v```", time.Since(v.Submitted)) ret += fmt.Sprintf("\n%+v", v.Photo) 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 } }