Golang bot for managing discord verifications
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

221 lines
6.6 KiB

package main
import (
"flag"
"fmt"
"math/rand"
"os"
"os/signal"
"syscall"
"time"
"github.com/bwmarrin/discordgo"
"github.com/rudi9719/loggy"
)
var (
startupTime time.Time
setupToken = fmt.Sprintf("%+v", rand.Intn(9999)+1000)
rebootToken = fmt.Sprintf("%+v", rand.Intn(9999)+1000)
bump = true
config Config
log = loggy.NewLogger(config.LogOpts)
lastActiveTime time.Time
token string
configFile string
dg *discordgo.Session
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."}
gitCommit string
commands []Command
)
func init() {
flag.StringVar(&token, "t", "", "Bot Token")
flag.StringVar(&configFile, "c", "", "Config file")
flag.Parse()
}
func main() {
go runWeb()
defer log.PanicSafe()
if configFile == "" {
configFile = "config.json"
} else {
loadConfig()
}
log = loggy.NewLogger(config.LogOpts)
startupTime = time.Now()
lastActiveTime = time.Now()
if token == "" {
log.LogPanic("No token provided. Please run: disgord-thanos -t <bot token>")
}
log.LogCritical("SetupToken: %+v\nRebootToken: %+v", setupToken, rebootToken)
var err error
dg, err = discordgo.New("Bot " + token)
if err != nil {
log.LogErrorType(err)
log.LogPanic("Unable to create bot using token.")
}
dg.AddHandler(ready)
dg.AddHandler(guildMemberRemove)
dg.AddHandler(guildMemberAdd)
dg.AddHandler(guildMemberBanned)
go setupCommands()
dg.AddHandler(messageCreate)
dg.AddHandler(readReaction)
dg.AddHandler(guildMemberUpdate)
dg.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAll)
err = dg.Open()
if err != nil {
log.LogErrorType(err)
log.LogPanic("Unable to open websocket.")
}
log.LogInfo("Thanos is now running. Press CTRL-C to exit.")
go purgeTimer(dg)
go rebootBump()
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
<-sc
saveConfig()
dg.Close()
}
func exit(s *discordgo.Session) {
s.Close()
saveConfig()
os.Exit(0)
}
func runPurge(s *discordgo.Session) {
defer log.PanicSafe()
if time.Since(config.BumpTime) > 2*time.Hour {
bump = true
}
for uid, join := range config.Probations {
if time.Since(join) > 2*time.Hour {
delete(config.Probations, uid)
s.ChannelMessageDelete(config.IntroChann, introMsg[uid])
}
}
for k, v := range config.Unverified {
isUnverified := false
m, err := s.GuildMember(config.GuildID, k)
if err != nil {
delete(config.Unverified, k)
continue
}
for _, role := range m.Roles {
if role == config.MonitorRole {
isUnverified = true
}
}
if isUnverified {
if val, ok := lastPM[k]; ok && time.Since(val) < 5*time.Minute {
continue
}
lastPM[k] = time.Now()
pmChann, _ := s.UserChannelCreate(k)
s.ChannelMessageSend(pmChann.ID,
fmt.Sprintf("This is a reminder that you have not verified with me and will be removed at <t:%+v:t>. You may reply to this message for verification instructions.", v.Add(1*time.Hour).Unix()))
if time.Since(v) > (time.Hour * 1) {
s.ChannelMessageSend(config.AdminChannel, fmt.Sprintf("%+v was removed.", m.Mention()))
s.GuildMemberDeleteWithReason(config.GuildID, k, fmt.Sprintf("Unverified user %+v.", v))
}
} else {
delete(config.Unverified, k)
}
}
messages, _ := s.ChannelMessages(config.MonitorChann, 100, "", "", "")
for _, message := range messages {
found := false
for user := range config.Unverified {
if message.Author.ID == user {
found = true
}
for _, mention := range message.Mentions {
if mention.ID == user {
found = true
}
}
}
if !found {
s.ChannelMessageDelete(config.MonitorChann, message.ID)
}
}
go cleanSocials(s)
saveConfig()
}
func cleanSocials(s *discordgo.Session) {
for _, channel := range config.SocialChanns {
go func(channel string, s *discordgo.Session) {
messages, _ := s.ChannelMessages(channel, 100, "", "", "")
for _, message := range messages {
_, err := s.GuildMember(config.GuildID, message.Author.ID)
if err != nil {
s.ChannelMessageDelete(channel, message.ID)
}
}
}(channel, s)
}
}
func verifyMember(s *discordgo.Session, u discordgo.User) {
defer log.PanicSafe()
log.LogDebug("Adding verified roll")
s.GuildMemberRoleAdd(config.GuildID, u.ID, config.VerifiedRole)
log.LogDebug("Removing monitor role")
s.GuildMemberRoleRemove(config.GuildID, u.ID, config.MonitorRole)
log.LogDebug("Creating PM channel")
st, err := s.UserChannelCreate(u.ID)
if err != nil {
log.LogErrorType(err)
}
log.LogDebug("Sending acceptance message!")
s.ChannelMessageSend(st.ID, "Your verification has been accepted, welcome!")
log.LogDebug("Sending Intro message")
m, err := s.ChannelMessageSend(config.IntroChann, fmt.Sprintf("Welcome %+v please introduce yourself! :) feel free to check out <#710557387937022034> to tag your roles. Also please mute any channels you are not interested in!", u.Mention()))
if err != nil {
log.LogErrorType(err)
}
log.LogDebug("Storing introMsg ID to be deleted later")
introMsg[u.ID] = m.ID
}
func rejectVerification(s *discordgo.Session, u discordgo.User) {
defer log.PanicSafe()
st, err := s.UserChannelCreate(u.ID)
if err != nil {
log.LogErrorType(err)
}
if st != nil {
s.ChannelMessageSend(st.ID, fmt.Sprintf("Your verification has been rejected. This means it did not clearly show your face, with your pinkie finger held to the corner of your mouth, or the photo looked edited/filtered. No filters will be accepted.\n\nPlease try again before <t:%+v:t>", time.Now().Add(1*time.Hour).Unix()))
}
config.Unverified[u.ID] = time.Now()
}
func requestAge(s *discordgo.Session, u discordgo.User) {
defer log.PanicSafe()
st, err := s.UserChannelCreate(u.ID)
if err != nil {
log.LogErrorType(err)
}
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 measurable and in the context of pornographic images more important.")
}
func requestReupload(s *discordgo.Session, u discordgo.User) {
defer log.PanicSafe()
st, err := s.UserChannelCreate(u.ID)
if err != nil {
log.LogErrorType(err)
}
s.ChannelMessageSend(st.ID, "Hello! Your verification has been denied because it failed to load. Please try again! The instructions will follow this message:")
rejectVerification(s, u)
}