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 "" }