Elara6331
a1257cd9e7
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
192 lines
5.7 KiB
Go
192 lines
5.7 KiB
Go
package members
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/bwmarrin/discordgo"
|
|
"go.elara.ws/logger/log"
|
|
"go.elara.ws/owobot/internal/cache"
|
|
"go.elara.ws/owobot/internal/systems/eventlog"
|
|
)
|
|
|
|
// onMemberAdd attempts to detect which invite(s) were used to invite the user
|
|
// and logs the member join.
|
|
func onMemberAdd(s *discordgo.Session, gma *discordgo.GuildMemberAdd) {
|
|
invites, err := findLastUsedInvites(s, gma.GuildID)
|
|
if err != nil {
|
|
log.Warn("Error finding last used invite").Err(err).Send()
|
|
}
|
|
|
|
code := "Unknown"
|
|
if len(invites) > 0 {
|
|
code = strings.Join(invites, " or ")
|
|
}
|
|
|
|
err = eventlog.Log(s, gma.GuildID, eventlog.Entry{
|
|
Title: "New Member Joined!",
|
|
Description: fmt.Sprintf("**User:**\n%s\n**ID:**\n%s\n**Invite Code:**\n%s", gma.Member.User.Mention(), gma.Member.User.ID, code),
|
|
Author: gma.Member.User,
|
|
})
|
|
if err != nil {
|
|
log.Warn("Error sending member joined log").Str("member", gma.Member.User.Username).Err(err).Send()
|
|
}
|
|
}
|
|
|
|
// onMemberUpdate logs member updates, such as roles being assigned or removed
|
|
func onMemberUpdate(s *discordgo.Session, gmu *discordgo.GuildMemberUpdate) {
|
|
if gmu.BeforeUpdate == nil || gmu.Member == nil {
|
|
return
|
|
}
|
|
|
|
if !slices.Equal(gmu.BeforeUpdate.Roles, gmu.Member.Roles) {
|
|
var added, removed []string
|
|
for _, newRole := range gmu.Member.Roles {
|
|
if !slices.Contains(gmu.BeforeUpdate.Roles, newRole) {
|
|
added = append(added, fmt.Sprintf("<@&%s>", newRole))
|
|
}
|
|
}
|
|
for _, oldRole := range gmu.BeforeUpdate.Roles {
|
|
if !slices.Contains(gmu.Member.Roles, oldRole) {
|
|
removed = append(removed, fmt.Sprintf("<@&%s>", oldRole))
|
|
}
|
|
}
|
|
|
|
err := eventlog.Log(s, gmu.GuildID, eventlog.Entry{
|
|
Title: "Roles Updated",
|
|
Description: fmt.Sprintf(
|
|
"**User:** %s\n**Added:** %s\n**Removed:** %s",
|
|
gmu.Member.User.Mention(),
|
|
strings.Join(added, " "),
|
|
strings.Join(removed, " "),
|
|
),
|
|
Author: gmu.Member.User,
|
|
})
|
|
if err != nil {
|
|
log.Warn("Error roles updated log").Str("member", gmu.Member.User.Username).Err(err).Send()
|
|
}
|
|
}
|
|
}
|
|
|
|
// onMemberLeave logs member leave events and handles bans and kicks
|
|
func onMemberLeave(s *discordgo.Session, gmr *discordgo.GuildMemberRemove) {
|
|
err := handleBanOrKick(s, gmr)
|
|
if err != nil {
|
|
log.Warn("Error logging ban or kick").Str("member", gmr.Member.User.Username).Err(err).Send()
|
|
}
|
|
|
|
err = eventlog.Log(s, gmr.GuildID, eventlog.Entry{
|
|
Title: "Member Left",
|
|
Description: fmt.Sprintf("**User:**\n%s\n**ID:**\n%s", gmr.Member.User.Mention(), gmr.Member.User.ID),
|
|
Author: gmr.Member.User,
|
|
})
|
|
if err != nil {
|
|
log.Warn("Error sending member left log").Str("member", gmr.Member.User.Username).Err(err).Send()
|
|
}
|
|
}
|
|
|
|
// onChannelDelete attempts to detect the user responsible for a channel deletion
|
|
// and logs it. It also handles rate limiting for channel delete events.
|
|
func onChannelDelete(s *discordgo.Session, cd *discordgo.ChannelDelete) {
|
|
if cd.Type == discordgo.ChannelTypeDM || cd.Type == discordgo.ChannelTypeGroupDM {
|
|
return
|
|
}
|
|
|
|
auditLog, err := s.GuildAuditLog(cd.GuildID, "", "", int(discordgo.AuditLogActionChannelDelete), 5)
|
|
if err != nil {
|
|
log.Error("Error getting audit log").Err(err).Send()
|
|
return
|
|
}
|
|
|
|
for _, entry := range auditLog.AuditLogEntries {
|
|
// If the deleted channel isn't the one this event is for,
|
|
// skip it.
|
|
if entry.TargetID != cd.ID {
|
|
continue
|
|
}
|
|
|
|
// If the bot deleted the channel, we don't care about this event
|
|
if entry.UserID == s.State.User.ID {
|
|
return
|
|
}
|
|
|
|
err = handleRatelimit(s, "channel_delete", cd.GuildID, entry.UserID)
|
|
if err != nil {
|
|
log.Error("Error handling rate limit").Err(err).Send()
|
|
}
|
|
|
|
member, err := cache.Member(s, cd.GuildID, entry.UserID)
|
|
if err != nil {
|
|
log.Error("Error getting member").Err(err).Send()
|
|
return
|
|
}
|
|
|
|
err = eventlog.Log(s, cd.GuildID, eventlog.Entry{
|
|
Title: "Channel Deleted",
|
|
Description: fmt.Sprintf("**Name:** `%s`\n**Deleted By:** %s", cd.Name, member.User.Mention()),
|
|
Author: member.User,
|
|
})
|
|
if err != nil {
|
|
log.Warn("Error sending channel deleted log").Str("channel", cd.Name).Err(err).Send()
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
}
|
|
|
|
// handleBanOrKick attempts to detect the user responsible for a ban or kick, and
|
|
// logs it. It also handles rate limiting for bans and kicks.
|
|
func handleBanOrKick(s *discordgo.Session, gmr *discordgo.GuildMemberRemove) error {
|
|
auditLog, err := s.GuildAuditLog(gmr.GuildID, "", "", 0, 5)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, entry := range auditLog.AuditLogEntries {
|
|
// If there's no action type or the user isn't the one this
|
|
// event is for, skip it.
|
|
if entry.ActionType == nil || entry.TargetID != gmr.User.ID {
|
|
continue
|
|
}
|
|
|
|
switch *entry.ActionType {
|
|
case discordgo.AuditLogActionMemberBanAdd:
|
|
executor, err := cache.Member(s, gmr.GuildID, entry.UserID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = eventlog.Log(s, gmr.GuildID, eventlog.Entry{
|
|
Title: "User banned",
|
|
Description: fmt.Sprintf("**Target:** %s\n**Banned by:** %s\n**Reason:** %s", gmr.User.Mention(), executor.User.Mention(), entry.Reason),
|
|
Author: gmr.User,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return handleRatelimit(s, "ban", gmr.GuildID, executor.User.ID)
|
|
case discordgo.AuditLogActionMemberKick:
|
|
executor, err := cache.Member(s, gmr.GuildID, entry.UserID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = eventlog.Log(s, gmr.GuildID, eventlog.Entry{
|
|
Title: "User kicked",
|
|
Description: fmt.Sprintf("**Target:** %s\n**Kicked by:** %s\n**Reason:** %s", gmr.User.Mention(), executor.User.Mention(), entry.Reason),
|
|
Author: gmr.User,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return handleRatelimit(s, "kick", gmr.GuildID, executor.User.ID)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|