diff --git a/cmd/prepbot/main.go b/cmd/prepbot/main.go index 7adca80..1bf3318 100644 --- a/cmd/prepbot/main.go +++ b/cmd/prepbot/main.go @@ -8,6 +8,7 @@ import ( "github.com/bwmarrin/discordgo" "github.com/dustinpianalto/disgoman" + "github.com/dustinpianalto/prepbot/internal/exts/members" "github.com/dustinpianalto/prepbot/internal/exts/messages" ) @@ -40,6 +41,8 @@ func main() { } dg.AddHandler(messages.CleanAmazonURLs) + dg.AddHandler(members.OnGuildMemberAddLogging) + dg.AddHandler(members.OnGuildMemberRemoveLogging) err = dg.Open() if err != nil { diff --git a/internal/discord_utils/date_strings.go b/internal/discord_utils/date_strings.go new file mode 100644 index 0000000..f55d808 --- /dev/null +++ b/internal/discord_utils/date_strings.go @@ -0,0 +1,64 @@ +package discord_utils + +import ( + "fmt" + "time" +) + +func ParseDateString(inTime time.Time) string { + d := time.Now().Sub(inTime) + s := int64(d.Seconds()) + days := s / 86400 + s = s - (days * 86400) + hours := s / 3600 + s = s - (hours * 3600) + minutes := s / 60 + seconds := s - (minutes * 60) + dateString := "" + if days != 0 { + dateString += fmt.Sprintf("%v days ", days) + } + if hours != 0 { + dateString += fmt.Sprintf("%v hours ", hours) + } + if minutes != 0 { + dateString += fmt.Sprintf("%v minutes ", minutes) + } + if seconds != 0 { + dateString += fmt.Sprintf("%v seconds ", seconds) + } + if dateString != "" { + dateString += " ago." + } else { + dateString = "Now" + } + stamp := inTime.Format("2006-01-02 15:04:05") + return fmt.Sprintf("%v\n%v", dateString, stamp) +} + +func ParseDurationString(inDur time.Duration) string { + s := int64(inDur.Seconds()) + days := s / 86400 + s = s - (days * 86400) + hours := s / 3600 + s = s - (hours * 3600) + minutes := s / 60 + seconds := s - (minutes * 60) + durString := "" + if days != 0 { + durString += fmt.Sprintf("%v days ", days) + } + if hours != 0 { + durString += fmt.Sprintf("%v hours ", hours) + } + if minutes != 0 { + durString += fmt.Sprintf("%v minutes ", minutes) + } + if seconds != 0 { + durString += fmt.Sprintf("%v seconds ", seconds) + } + if durString == "" { + durString = "0 seconds" + } + return fmt.Sprintf("%v", durString) +} diff --git a/internal/discord_utils/snowflake.go b/internal/discord_utils/snowflake.go new file mode 100644 index 0000000..d521086 --- /dev/null +++ b/internal/discord_utils/snowflake.go @@ -0,0 +1,32 @@ +package discord_utils + +import "time" + +type Snowflake struct { + CreationTime time.Time + WorkerID int8 + ProcessID int8 + Increment int16 +} + +func ParseSnowflake(s int64) Snowflake { + const ( + DISCORD_EPOCH = 1420070400000 + TIME_BITS_LOC = 22 + WORKER_ID_LOC = 17 + WORKER_ID_MASK = 0x3E0000 + PROCESS_ID_LOC = 12 + PROCESS_ID_MASK = 0x1F000 + INCREMENT_MASK = 0xFFF + ) + creationTime := time.Unix(((s>>TIME_BITS_LOC)+DISCORD_EPOCH)/1000.0, 0) + workerID := (s & WORKER_ID_MASK) >> WORKER_ID_LOC + processID := (s & PROCESS_ID_MASK) >> PROCESS_ID_LOC + increment := s & INCREMENT_MASK + return Snowflake{ + CreationTime: creationTime, + WorkerID: int8(workerID), + ProcessID: int8(processID), + Increment: int16(increment), + } +} diff --git a/internal/exts/members/member_logging.go b/internal/exts/members/member_logging.go new file mode 100644 index 0000000..8aaad41 --- /dev/null +++ b/internal/exts/members/member_logging.go @@ -0,0 +1,125 @@ +package members + +import ( + "fmt" + "log" + "strconv" + "time" + + "github.com/bwmarrin/discordgo" + "github.com/dustinpianalto/prepbot/internal/discord_utils" +) + +var joinChannelID = "768571410133418037" + +func OnGuildMemberAddLogging(s *discordgo.Session, member *discordgo.GuildMemberAdd) { + defer func() { + if r := recover(); r != nil { + log.Println("Recovered from panic in OnGuildMemberAddLogging", r) + } + }() + guild, err := s.State.Guild(member.GuildID) + if err != nil { + log.Println(err) + return + } + + var title string + if member.User.Bot { + title = "Bot Joined" + } else { + title = "Member Joined" + } + + thumb := &discordgo.MessageEmbedThumbnail{ + URL: member.User.AvatarURL(""), + } + + int64ID, _ := strconv.ParseInt(member.User.ID, 10, 64) + snow := discord_utils.ParseSnowflake(int64ID) + + field := &discordgo.MessageEmbedField{ + Name: "User was created:", + Value: discord_utils.ParseDateString(snow.CreationTime), + Inline: false, + } + + joinTime, _ := member.JoinedAt.Parse() + + embed := &discordgo.MessageEmbed{ + Title: title, + Description: fmt.Sprintf("%v (%v) Has Joined the Server", member.User.Mention(), member.User.ID), + Color: 0x0cc56a, + Thumbnail: thumb, + Footer: &discordgo.MessageEmbedFooter{ + Text: fmt.Sprintf("Current Member Count: %v", guild.MemberCount), + IconURL: guild.IconURL(), + }, + Timestamp: joinTime.Format(time.RFC3339), + Fields: []*discordgo.MessageEmbedField{field}, + } + s.ChannelMessageSendEmbed(joinChannelID, embed) +} + +func OnGuildMemberRemoveLogging(s *discordgo.Session, member *discordgo.GuildMemberRemove) { + defer func() { + if r := recover(); r != nil { + log.Println("Recovered from panic in OnGuildMemberAddLogging", r) + } + }() + timeNow := time.Now() + guild, err := s.State.Guild(member.GuildID) + if err != nil { + log.Println(err) + return + } + + var title string + if member.User.Bot { + title = "Bot Left" + } else { + title = "Member Left" + } + + thumb := &discordgo.MessageEmbedThumbnail{ + URL: member.User.AvatarURL(""), + } + + desc := "" + al, err := s.GuildAuditLog(member.GuildID, "", "", 20, 1) + if err != nil { + log.Println(err) + } else { + for _, log := range al.AuditLogEntries { + if log.TargetID == member.User.ID { + int64ID, _ := strconv.ParseInt(log.ID, 10, 64) + logSnow := discord_utils.ParseSnowflake(int64ID) + if timeNow.Sub(logSnow.CreationTime).Seconds() <= 10 { + user, err := s.User(log.UserID) + if err == nil { + desc = fmt.Sprintf("%v (%v) was Kicked by: %v\nReason: %v", member.User.String(), member.User.ID, user.String(), log.Reason) + } else { + desc = fmt.Sprintf("%v (%v) was Kicked by: %v\nReason: %v", member.User.String(), member.User.ID, log.UserID, log.Reason) + } + break + } + } + } + } + if desc == "" { + desc = fmt.Sprintf("%v (%v) Has Left the Server", member.User.String(), member.User.ID) + } + + embed := &discordgo.MessageEmbed{ + Title: title, + Description: desc, + Color: 0xff9431, + Thumbnail: thumb, + Footer: &discordgo.MessageEmbedFooter{ + Text: fmt.Sprintf("Current Member Count: %v", guild.MemberCount), + IconURL: guild.IconURL(), + }, + Timestamp: timeNow.Format(time.RFC3339), + } + s.ChannelMessageSendEmbed(joinChannelID, embed) +}