- Added a logging service to manage server event logs including message edits, deletions, member joins/leaves, and moderation actions. - Introduced commands to configure logging settings, including setting the log channel and enabling/disabling logging. - Updated the README to document the new logging features and commands. - Enhanced moderation commands to log actions taken on members.
164 lines
4.3 KiB
Go
164 lines
4.3 KiB
Go
package events
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"velox-bot/internal/db/services"
|
|
|
|
"github.com/bwmarrin/discordgo"
|
|
)
|
|
|
|
// HandleBotAddedOnGuild applies safe defaults when this bot is added to a guild
|
|
// and DMs setup instructions to the inviter (or guild owner fallback).
|
|
func HandleBotAddedOnGuild(s *discordgo.Session, m *discordgo.GuildMemberAdd, svc *services.Services) {
|
|
if s == nil || m == nil || m.Member == nil || m.User == nil || svc == nil {
|
|
return
|
|
}
|
|
if s.State == nil || s.State.User == nil {
|
|
return
|
|
}
|
|
if m.User.ID != s.State.User.ID {
|
|
return
|
|
}
|
|
|
|
guildID64, err := strconv.ParseInt(m.GuildID, 10, 64)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
// Treat an existing logsettings row as "already onboarded once".
|
|
alreadyOnboarded := false
|
|
if svc.LogSettings != nil {
|
|
exists, err := svc.LogSettings.HasSettings(context.Background(), guildID64)
|
|
if err == nil {
|
|
alreadyOnboarded = exists
|
|
}
|
|
}
|
|
if alreadyOnboarded {
|
|
return
|
|
}
|
|
|
|
// Explicitly disable toggleable systems by default.
|
|
if svc.LevelSettings != nil {
|
|
if err := svc.LevelSettings.SetLevelSystemEnabled(context.Background(), guildID64, false); err != nil {
|
|
log.Printf("onboarding: failed to set default level state for guild %s: %v", m.GuildID, err)
|
|
}
|
|
}
|
|
if svc.LogSettings != nil {
|
|
if err := svc.LogSettings.SetEnabled(context.Background(), guildID64, false); err != nil {
|
|
log.Printf("onboarding: failed to set default log state for guild %s: %v", m.GuildID, err)
|
|
}
|
|
}
|
|
|
|
recipientID := findRecentBotAdderID(s, m.GuildID)
|
|
if recipientID == "" {
|
|
recipientID = guildOwnerID(s, m.GuildID)
|
|
}
|
|
if recipientID == "" {
|
|
log.Printf("onboarding: unable to resolve DM recipient for guild %s", m.GuildID)
|
|
return
|
|
}
|
|
|
|
dmCh, err := s.UserChannelCreate(recipientID)
|
|
if err != nil {
|
|
log.Printf("onboarding: failed creating DM for user %s: %v", recipientID, err)
|
|
return
|
|
}
|
|
|
|
guildName := m.GuildID
|
|
if g, err := s.State.Guild(m.GuildID); err == nil && g != nil && strings.TrimSpace(g.Name) != "" {
|
|
guildName = g.Name
|
|
} else if g, err := s.Guild(m.GuildID); err == nil && g != nil && strings.TrimSpace(g.Name) != "" {
|
|
guildName = g.Name
|
|
}
|
|
|
|
embed := &discordgo.MessageEmbed{
|
|
Title: "Thanks for adding Velox Bot!",
|
|
Color: 0x5865F2,
|
|
Description: fmt.Sprintf(
|
|
"Server: **%s**\n\nFor safety, toggleable systems start **disabled by default**.\nUse these commands in your server to enable features:",
|
|
guildName,
|
|
),
|
|
Fields: []*discordgo.MessageEmbedField{
|
|
{
|
|
Name: "Level System",
|
|
Value: "`/slvl toggle`",
|
|
Inline: false,
|
|
},
|
|
{
|
|
Name: "Logging System",
|
|
Value: "" +
|
|
"`/config setlogchannel channel:#channel`\n" +
|
|
"`/config enablelogging`",
|
|
Inline: false,
|
|
},
|
|
{
|
|
Name: "Welcome System",
|
|
Value: "" +
|
|
"`/config setwelcomechannel channel:#channel`\n" +
|
|
"`/config setwelcomemessage message:\"...\"`\n" +
|
|
"`/config setwelcomedm message:\"...\"`",
|
|
Inline: false,
|
|
},
|
|
},
|
|
Footer: &discordgo.MessageEmbedFooter{
|
|
Text: "Tip: run /help in any server channel for the full command reference.",
|
|
},
|
|
Timestamp: time.Now().Format(time.RFC3339),
|
|
}
|
|
|
|
if _, err := s.ChannelMessageSendEmbed(dmCh.ID, embed); err != nil {
|
|
log.Printf("onboarding: failed sending setup DM to user %s: %v", recipientID, err)
|
|
}
|
|
}
|
|
|
|
func findRecentBotAdderID(s *discordgo.Session, guildID string) string {
|
|
if s == nil || s.State == nil || s.State.User == nil {
|
|
return ""
|
|
}
|
|
logs, err := s.GuildAuditLog(guildID, "", "", int(discordgo.AuditLogActionBotAdd), 10)
|
|
if err != nil || logs == nil {
|
|
return ""
|
|
}
|
|
|
|
botID := s.State.User.ID
|
|
now := time.Now().UTC()
|
|
for _, entry := range logs.AuditLogEntries {
|
|
if entry == nil || entry.TargetID != botID || entry.ActionType == nil || *entry.ActionType != discordgo.AuditLogActionBotAdd {
|
|
continue
|
|
}
|
|
ts, err := discordgo.SnowflakeTimestamp(entry.ID)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if now.Sub(ts) > 10*time.Minute {
|
|
continue
|
|
}
|
|
if entry.UserID != "" {
|
|
return entry.UserID
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func guildOwnerID(s *discordgo.Session, guildID string) string {
|
|
if s == nil || guildID == "" {
|
|
return ""
|
|
}
|
|
if s.State != nil {
|
|
if g, err := s.State.Guild(guildID); err == nil && g != nil && g.OwnerID != "" {
|
|
return g.OwnerID
|
|
}
|
|
}
|
|
if g, err := s.Guild(guildID); err == nil && g != nil {
|
|
return g.OwnerID
|
|
}
|
|
return ""
|
|
}
|
|
|