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.

285 lines
8.3 KiB

package main
import (
"fmt"
"strconv"
"strings"
"time"
"github.com/bwmarrin/discordgo"
"github.com/google/uuid"
)
var session *discordgo.Session
var pendingV []Verification
var rebootTS time.Time
const alpha = "abcdefghijklmnopqrstuvwxyz1234567890"
func configureDiscord() {
dg, err := discordgo.New("Bot " + config.DiscordToken)
if err != nil {
log.LogErrorType(err)
log.LogPanic("Unable to create bot using token.")
}
dg.AddHandler(ready)
dg.AddHandler(readReaction)
dg.AddHandler(messageCreate)
//dg.AddHandler(guildMemberAdd)
session = dg
err = dg.Open()
if err != nil {
log.LogErrorType(err)
log.LogPanic("Unable to open websocket")
}
log.LogInfo("Discord link is now online.")
}
func discordExit() {
log.LogCritical("Closing Discord (closing Session)")
session.Close()
}
func sendDiscordMessage(msg string) {
session.ChannelMessageSend(config.VerifiedChan, fixMentions(msg))
}
func sendAdminDiscordMessage(msg string) {
session.ChannelMessageSend(config.AdminChan, msg)
}
func ready(s *discordgo.Session, m *discordgo.Ready) {
s.UpdateStatus(0, "Minecraft")
}
func banUser(s *discordgo.Session, u discordgo.User) {
s.GuildBanCreate(config.GuildID, u.ID, 0)
}
func readReaction(s *discordgo.Session, m *discordgo.MessageReactionAdd) {
defer log.PanicSafe()
if m.Emoji.Name != "⚠" && m.Emoji.Name != "❗" {
return
}
log.LogDebug(fmt.Sprintf("Report emoji: ```%+v```", *m))
msg, err := s.ChannelMessage(m.ChannelID, m.MessageID)
log.LogDebug(fmt.Sprintf("Message retrieved: %+v", *msg))
if err != nil {
s.ChannelMessageSend(config.AdminChan, "A message was reported that I could not detect.")
return
}
reporter, _ := s.GuildMember(config.GuildID, m.UserID)
violator, _ := s.GuildMember(config.GuildID, msg.Author.ID)
s.ChannelMessageSend(config.AdminChan, fmt.Sprintf("A message was reported! %+v reported %+v's message: %+v\n```%+v```", reporter.Nick, violator.Nick, msg.Content, *msg))
var r Report
var violatorUser User
violatorUser.DiscordID = m.UserID
violatorUser.Retrieve()
var reporterUser User
reporterUser.DiscordID = msg.Author.ID
reporterUser.Retrieve()
reporterUser.Write() // Update last seen
r.Time = time.Now()
r.Reporter = reporterUser
r.Abuser = violatorUser
r.Msg = msg.Content
r.Write()
}
func guildMemberAdd(s *discordgo.Session, m *discordgo.GuildMemberAdd) {
defer log.PanicSafe()
s.GuildMemberRoleAdd(config.GuildID, m.User.ID, config.MonitorRole)
st, _ := s.UserChannelCreate(m.User.ID) // Get the ID of PM channel
id := uuid.New() // Generate new UUID4
var v Verification // Set up new Verification
v.DiscordID = m.User.ID // ID is what really matters, username is garbage
v.Created = time.Now() // Setup the created time for reasons
v.Code = id.String() // Generate Random UUID
pendingV = append(pendingV, v)
s.ChannelMessageSend(st.ID, "Hello! You have not yet verified with me. Type !sitnet [your sitnet ID here] to verify who you are. You will get an email explaining what to do next. https://web.cs.sunyit.edu/polymc")
}
func fixMentions(s string) string {
defer log.PanicSafe()
var ret string
if !strings.Contains(s, "@") {
return s
}
parts := strings.Split(s, " ")
for _, part := range parts {
if strings.HasPrefix(part, "@") {
var u User
u.Email = strings.Replace(part, "@", "", -1)
u.Retrieve()
ret += fmt.Sprintf("<@!%+v>", u.DiscordID)
} else {
ret += part
}
ret += " "
}
return ret
}
func setupVerifications(s *discordgo.Session, m *discordgo.MessageCreate) {
defer log.PanicSafe()
st, _ := s.UserChannelCreate(m.Author.ID) // Get the ID of PM channel
id := uuid.New() // Generate new UUID4
var v Verification // Set up new Verification
v.DiscordID = m.Author.ID // ID is what really matters, username is garbage
v.Created = time.Now() // Setup the created time for reasons
v.Code = id.String() // Generate Random UUID
pendingV = append(pendingV, v)
s.ChannelMessageSend(st.ID, "Hello! You have not yet verified with me. Type !sitnet [your sitnet ID here] to verify who you are. You will get an email explaining what to do next. https://web.cs.sunyit.edu/polymc")
}
func alphaOnly(s string) bool {
for _, char := range s {
if !strings.Contains(alpha, strings.ToLower(string(char))) {
return false
}
}
return true
}
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
defer log.PanicSafe()
if m.Author.ID == s.State.User.ID {
return
}
if m.GuildID == "" {
return
}
if m.ChannelID == config.MonitorChan && strings.HasPrefix(m.Content, "!verify") {
for _, v := range pendingV {
if v.DiscordID == m.Author.ID {
return
}
}
setupVerifications(s, m)
return
}
if m.ChannelID == config.MonitorChan {
return
}
var u User
u.DiscordID = m.Author.ID
u.Retrieve()
u.Write() // Update last seen
if strings.HasPrefix(m.Content, "!verify") && m.ChannelID != config.AdminChan {
s.ChannelMessageSend(m.ChannelID, "That command ONLY works for unverified users in the unverified channel. Instead, for account resets try !resetme")
return
}
if strings.HasPrefix(m.Content, "!resetme") {
mcCommand(fmt.Sprintf("whitelist remove %+v", u.McUser))
u.Delete()
s.GuildMemberRoleAdd(config.GuildID, m.Author.ID, config.MonitorRole)
s.GuildMemberRoleRemove(config.GuildID, m.Author.ID, config.VerifiedRole)
return
}
if strings.HasPrefix(m.Content, "!online") {
if len(onlineUsers) == 0 {
s.ChannelMessageSend(m.ChannelID, "There are no users online.")
return
}
str := fmt.Sprintf("The following %+v users are online:\n```", len(onlineUsers))
for _, usr := range onlineUsers {
str += fmt.Sprintf("%+v : %+v\n", usr.Email, usr.McUser)
}
str += "```"
s.ChannelMessageSend(m.ChannelID, str)
return
}
if m.ChannelID == config.VerifiedChan {
log.LogDebug(fmt.Sprintf("Discord message from retrieved user %+v", u))
// if debug message shows complete user, you may replace userStr with u.SITNresET
if m.Member.Nick != u.Email {
s.GuildMemberNickname(config.GuildID, m.Author.ID, u.Email)
}
mcSay(fmt.Sprintf("[%+v]: %+v", u.Email, m.Content))
return
}
if m.ChannelID == config.AdminChan {
go handleAdmin(s, m)
}
}
func manualVerifyUser(s *discordgo.Session, m *discordgo.MessageCreate) {
parts := strings.Split(m.Content, " ")
if len(parts) != 4 {
sendAdminDiscordMessage("Usage !verify $SITNET $McUser $DiscordID")
sendAdminDiscordMessage("Please note, DiscordID is the numerical ID, not their username.")
}
var u User
u.Email = parts[1]
u.McUser = parts[2]
u.DiscordID = parts[3]
u.Write()
}
func handleAdmin(s *discordgo.Session, m *discordgo.MessageCreate) {
if !strings.HasPrefix(m.Content, "!") {
return
}
if strings.HasPrefix(m.Content, "!verify") {
manualVerifyUser(s, m)
}
if strings.HasPrefix(m.Content, "!mc") {
mcCommand(strings.Replace(m.Content, "!mc", "", -1))
return
}
if strings.HasPrefix(m.Content, "!wb") {
if strings.Contains(m.Content, "stop") {
config.WbFinished = true
} else {
config.WbFinished = false
}
}
if strings.HasPrefix(m.Content, "!reboot") {
if serverRebooting {
s.ChannelMessageSend(config.AdminChan, fmt.Sprintf("Reboot pending: %+v", time.Until(rebootTS)))
return
}
serverRebooting = true
rebootTS = time.Now().Add(30 * time.Minute)
parts := strings.Split(m.Content, " ")
if len(parts) == 1 {
s.ChannelMessageSend(config.AdminChan, "A reboot has been queued. I will poll for when users log out and then execute.")
timeout := 120
for {
if len(onlineUsers) == 0 || timeout == 0 {
mcExit()
discordExit()
log.LogPanic("Shutting down server from queued reboot.")
}
time.Sleep(15 * time.Second)
timeout--
}
return
}
if len(parts) != 2 && len(parts) != 3 {
s.ChannelMessageSend(config.AdminChan, "You dumbass. I take one or two arguments.")
return
}
when, err := strconv.Atoi(parts[1])
if err != nil {
s.ChannelMessageSend(config.AdminChan, "The first argument must be an int, number of minutes.")
return
}
reminders := 0
if len(parts) == 3 {
reminders, err = strconv.Atoi(parts[2])
if err != nil {
s.ChannelMessageSend(config.AdminChan, "You supplied a second argument.. So that also has to be an int, number of reminders.")
return
}
}
mcReboot(when, reminders)
}
}