123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792 |
- package main
- import (
- "fmt"
- "log"
- "net/url"
- "os"
- "strconv"
- "strings"
- "time"
- "github.com/AvraamMavridis/randomcolor"
- "github.com/aidarkhanov/nanoid/v2"
- "github.com/bwmarrin/discordgo"
- "github.com/dustin/go-humanize"
- "github.com/fatih/color"
- "github.com/hako/durafmt"
- "github.com/teris-io/shortid"
- )
- //#region Get
- //TODO: Clean below
- /*func getChannelState(channelID string) *discordgo.Channel {
- sourceChannel, _ := bot.State.Channel(channelID)
- if sourceChannel != nil {
- return sourceChannel
- }
- return &discordgo.Channel{}
- }*/
- /*func getGuildState(guildID string) *discordgo.Guild {
- sourceGuild, _ := bot.State.Guild(guildID)
- if sourceGuild != nil {
- return sourceGuild
- }
- return &discordgo.Guild{}
- }*/
- const (
- fmtBotSendPerm = "Bot does not have permission to send messages in %s"
- )
- func getChannelGuildID(channelID string) string {
- sourceChannel, _ := bot.State.Channel(channelID)
- if sourceChannel != nil {
- return sourceChannel.GuildID
- }
- return ""
- }
- func getGuildName(guildID string) string {
- sourceGuildName := "UNKNOWN"
- sourceGuild, _ := bot.State.Guild(guildID)
- if sourceGuild != nil && sourceGuild.Name != "" {
- sourceGuildName = sourceGuild.Name
- }
- return sourceGuildName
- }
- func getChannelCategoryName(channelID string) string {
- sourceChannelName := "unknown"
- sourceChannel, _ := bot.State.Channel(channelID)
- if sourceChannel != nil {
- sourceParent, _ := bot.State.Channel(sourceChannel.ParentID)
- if sourceParent != nil {
- if sourceChannel.Name != "" {
- sourceChannelName = sourceParent.Name
- }
- }
- }
- return sourceChannelName
- }
- func getChannelName(channelID string, channelData *discordgo.Channel) string {
- sourceChannelName := "unknown"
- sourceChannel, _ := bot.State.Channel(channelID)
- if channelData != nil {
- sourceChannel = channelData
- }
- if sourceChannel != nil {
- if sourceChannel.Name != "" {
- sourceChannelName = sourceChannel.Name
- } else if sourceChannel.Topic != "" {
- sourceChannelName = sourceChannel.Topic
- } else {
- switch sourceChannel.Type {
- case discordgo.ChannelTypeDM:
- sourceChannelName = "dm"
- case discordgo.ChannelTypeGroupDM:
- sourceChannelName = "group-dm"
- }
- }
- }
- return sourceChannelName
- }
- //#endregion
- //#region Time
- const (
- discordEpoch = 1420070400000
- )
- //TODO: Clean these two
- func discordTimestampToSnowflake(format string, timestamp string) string {
- if t, err := time.ParseInLocation(format, timestamp, time.Local); err == nil {
- return fmt.Sprint(((t.UnixNano() / int64(time.Millisecond)) - discordEpoch) << 22)
- }
- log.Println(lg("Main", "", color.HiRedString,
- "Failed to convert timestamp to discord snowflake... Format: '%s', Timestamp: '%s' - Error:\t%s",
- format, timestamp, err))
- return ""
- }
- func discordSnowflakeToTimestamp(snowflake string, format string) string {
- i, err := strconv.ParseInt(snowflake, 10, 64)
- if err != nil {
- return ""
- }
- t := time.Unix(0, ((i>>22)+discordEpoch)*1000000)
- return t.Local().Format(format)
- }
- //#endregion
- //#region Messages
- // For command case-insensitivity
- func messageToLower(message *discordgo.Message) *discordgo.Message {
- newMessage := *message
- newMessage.Content = strings.ToLower(newMessage.Content)
- return &newMessage
- }
- func fixMessage(m *discordgo.Message) *discordgo.Message {
- // If message content is empty (likely due to userbot/selfbot)
- ubIssue := "Message is corrupted due to endpoint restriction"
- if m.Content == "" && len(m.Attachments) == 0 && len(m.Embeds) == 0 {
- // Get message history
- mCache, err := bot.ChannelMessages(m.ChannelID, 20, "", "", "")
- if err == nil {
- if len(mCache) > 0 {
- for _, mCached := range mCache {
- if mCached.ID == m.ID {
- // Fix original message having empty Guild ID
- guildID := m.GuildID
- // Replace message
- m = mCached
- // ^^
- if m.GuildID == "" && guildID != "" {
- m.GuildID = guildID
- }
- // Parse commands
- botCommands.FindAndExecute(bot, strings.ToLower(config.CommandPrefix), bot.State.User.ID, messageToLower(m))
- break
- }
- }
- } else if config.Debug {
- log.Println(lg("Debug", "fixMessage",
- color.RedString, "%s, and an attempt to get channel messages found nothing...",
- ubIssue))
- }
- } else if config.Debug {
- log.Println(lg("Debug", "fixMessage",
- color.HiRedString, "%s, and an attempt to get channel messages encountered an error:\t%s", ubIssue, err))
- }
- }
- if m.Content == "" && len(m.Attachments) == 0 && len(m.Embeds) == 0 {
- if config.Debug && selfbot {
- log.Println(lg("Debug", "fixMessage",
- color.YellowString, "%s, and attempts to fix seem to have failed...", ubIssue))
- }
- }
- return m
- }
- //#endregion
- func channelDisplay(channelID string) (string, string) {
- sourceChannelName := channelID
- sourceName := "UNKNOWN"
- sourceChannel, _ := bot.State.Channel(channelID)
- if sourceChannel != nil {
- // Channel Naming
- if sourceChannel.Name != "" {
- sourceChannelName = "#" + sourceChannel.Name
- }
- switch sourceChannel.Type {
- case discordgo.ChannelTypeGuildText:
- // Server Naming
- if sourceChannel.GuildID != "" {
- sourceGuild, _ := bot.State.Guild(sourceChannel.GuildID)
- if sourceGuild != nil && sourceGuild.Name != "" {
- sourceName = sourceGuild.Name
- }
- }
- // Category Naming
- if sourceChannel.ParentID != "" {
- sourceParent, _ := bot.State.Channel(sourceChannel.ParentID)
- if sourceParent != nil {
- if sourceParent.Name != "" {
- sourceChannelName = sourceParent.Name + " / " + sourceChannelName
- }
- }
- }
- case discordgo.ChannelTypeDM:
- sourceName = "Direct Messages"
- case discordgo.ChannelTypeGroupDM:
- sourceName = "Group Messages"
- }
- }
- return sourceName, sourceChannelName
- }
- //#region Presence
- func dataKeyReplacement(input string) string {
- //TODO: Case-insensitive key replacement. -- If no streamlined way to do it, convert to lower to find substring location but replace normally
- if strings.Contains(input, "{{") && strings.Contains(input, "}}") {
- countInt := int64(dbDownloadCount()) + *config.InflateDownloadCount
- timeNow := time.Now()
- keys := [][]string{
- {"{{dgVersion}}",
- discordgo.VERSION},
- {"{{ddgVersion}}",
- projectVersion},
- {"{{apiVersion}}",
- discordgo.APIVersion},
- {"{{countNoCommas}}",
- fmt.Sprint(countInt)},
- {"{{count}}",
- formatNumber(countInt)},
- {"{{countShort}}",
- formatNumberShort(countInt)},
- {"{{numServers}}",
- fmt.Sprint(len(bot.State.Guilds))},
- {"{{numBoundChannels}}",
- fmt.Sprint(getBoundChannelsCount())},
- {"{{numBoundCategories}}",
- fmt.Sprint(getBoundCategoriesCount())},
- {"{{numBoundServers}}",
- fmt.Sprint(getBoundServersCount())},
- {"{{numBoundUsers}}",
- fmt.Sprint(getBoundUsersCount())},
- {"{{numAdminChannels}}",
- fmt.Sprint(len(config.AdminChannels))},
- {"{{numAdmins}}",
- fmt.Sprint(len(config.Admins))},
- {"{{timeSavedShort}}",
- timeLastUpdated.Format("3:04pm")},
- {"{{timeSavedShortTZ}}",
- timeLastUpdated.Format("3:04pm MST")},
- {"{{timeSavedMid}}",
- timeLastUpdated.Format("3:04pm MST 1/2/2006")},
- {"{{timeSavedLong}}",
- timeLastUpdated.Format("3:04:05pm MST - January 2, 2006")},
- {"{{timeSavedShort24}}",
- timeLastUpdated.Format("15:04")},
- {"{{timeSavedShortTZ24}}",
- timeLastUpdated.Format("15:04 MST")},
- {"{{timeSavedMid24}}",
- timeLastUpdated.Format("15:04 MST 2/1/2006")},
- {"{{timeSavedLong24}}",
- timeLastUpdated.Format("15:04:05 MST - 2 January, 2006")},
- {"{{timeNowShort}}",
- timeNow.Format("3:04pm")},
- {"{{timeNowShortTZ}}",
- timeNow.Format("3:04pm MST")},
- {"{{timeNowMid}}",
- timeNow.Format("3:04pm MST 1/2/2006")},
- {"{{timeNowLong}}",
- timeNow.Format("3:04:05pm MST - January 2, 2006")},
- {"{{timeNowShort24}}",
- timeNow.Format("15:04")},
- {"{{timeNowShortTZ24}}",
- timeNow.Format("15:04 MST")},
- {"{{timeNowMid24}}",
- timeNow.Format("15:04 MST 2/1/2006")},
- {"{{timeNowLong24}}",
- timeNow.Format("15:04:05 MST - 2 January, 2006")},
- {"{{uptime}}",
- shortenTime(durafmt.ParseShort(time.Since(startTime)).String())},
- }
- for _, key := range keys {
- if strings.Contains(input, key[0]) {
- input = strings.ReplaceAll(input, key[0], key[1])
- }
- }
- }
- return input
- }
- func channelKeyReplacement(input string, srcchannel string) string {
- ret := input
- if strings.Contains(ret, "{{") && strings.Contains(ret, "}}") {
- if channel, err := bot.State.Channel(srcchannel); err == nil {
- keys := [][]string{
- {"{{channelID}}", channel.ID},
- {"{{serverID}}", channel.GuildID},
- {"{{channelName}}", channel.Name},
- }
- for _, key := range keys {
- if strings.Contains(ret, key[0]) {
- ret = strings.ReplaceAll(ret, key[0], key[1])
- }
- }
- }
- }
- return dataKeyReplacement(ret)
- }
- func dynamicKeyReplacement(channelConfig configurationSource, download downloadRequestStruct) string {
- //TODO: same as dataKeyReplacement
- ret := config.FilenameFormat
- if channelConfig.FilenameFormat != nil {
- if *channelConfig.FilenameFormat != "" {
- ret = *channelConfig.FilenameFormat
- }
- }
- if strings.Contains(ret, "{{") && strings.Contains(ret, "}}") {
- // Format Filename Date
- filenameDateFormat := config.FilenameDateFormat
- if channelConfig.FilenameDateFormat != nil {
- if *channelConfig.FilenameDateFormat != "" {
- filenameDateFormat = *channelConfig.FilenameDateFormat
- }
- }
- messageTime := download.Message.Timestamp
- shortID, err := shortid.Generate()
- if err != nil && config.Debug {
- log.Println(lg("Debug", "dynamicKeyReplacement", color.HiCyanString, "Error when generating a shortID %s", err))
- }
- nanoID, err := nanoid.New()
- if err != nil && config.Debug {
- log.Println(lg("Debug", "dynamicKeyReplacement", color.HiCyanString, "Error when creating a nanoID %s", err))
- }
- userID := ""
- username := ""
- if download.Message.Author != nil {
- userID = download.Message.Author.ID
- username = download.Message.Author.Username
- }
- channelName := download.Message.ChannelID
- categoryID := download.Message.ChannelID
- categoryName := download.Message.ChannelID
- guildName := download.Message.GuildID
- if chinfo, err := bot.State.Channel(download.Message.ChannelID); err == nil {
- channelName = chinfo.Name
- categoryID = chinfo.ParentID
- if catinfo, err := bot.State.Channel(categoryID); err == nil {
- categoryName = catinfo.Name
- }
- }
- if guildinfo, err := bot.State.Guild(download.Message.GuildID); err == nil {
- guildName = guildinfo.Name
- }
- domain := "unknown"
- if parsedURL, err := url.Parse(download.InputURL); err == nil {
- domain = parsedURL.Hostname()
- }
- fileinfo, err := os.Stat(download.Path + download.Filename)
- filesize := "unknown"
- if err == nil {
- filesize = humanize.Bytes(uint64(fileinfo.Size()))
- }
- keys := [][]string{
- {"{{date}}", messageTime.Format(filenameDateFormat)},
- {"{{file}}", download.Filename},
- {"{{fileType}}", download.Extension},
- {"{{fileSize}}", filesize},
- {"{{messageID}}", download.Message.ID},
- {"{{userID}}", userID},
- {"{{username}}", username},
- {"{{channelID}}", download.Message.ChannelID},
- {"{{channelName}}", channelName},
- {"{{categoryID}}", categoryID},
- {"{{categoryName}}", categoryName},
- {"{{serverID}}", download.Message.GuildID},
- {"{{serverName}}", guildName},
- {"{{message}}", clearPath(download.Message.Content)},
- {"{{downloadTime}}", shortenTime(durafmt.ParseShort(time.Since(download.StartTime)).String())},
- {"{{downloadTimeLong}}", durafmt.Parse(time.Since(download.StartTime)).String()},
- {"{{url}}", clearPath(download.InputURL)},
- {"{{domain}}", domain},
- {"{{nanoID}}", nanoID},
- {"{{shortID}}", shortID},
- }
- for _, key := range keys {
- if strings.Contains(ret, key[0]) {
- ret = strings.ReplaceAll(ret, key[0], key[1])
- }
- }
- }
- return dataKeyReplacement(ret)
- }
- func updateDiscordPresence() {
- if config.PresenceEnabled {
- // Vars
- countInt := int64(dbDownloadCount()) + *config.InflateDownloadCount
- count := formatNumber(countInt)
- countShort := formatNumberShort(countInt)
- timeShort := timeLastUpdated.Format("3:04pm")
- timeLong := timeLastUpdated.Format("3:04:05pm MST - January 2, 2006")
- // Defaults
- status := fmt.Sprintf("%s - %s files", timeShort, countShort)
- statusDetails := timeLong
- statusState := fmt.Sprintf("%s files total", count)
- // Overwrite Presence
- if config.PresenceLabel != nil {
- status = *config.PresenceLabel
- if status != "" {
- status = dataKeyReplacement(status)
- }
- }
- // Overwrite Details
- if config.PresenceDetails != nil {
- statusDetails = *config.PresenceDetails
- if statusDetails != "" {
- statusDetails = dataKeyReplacement(statusDetails)
- }
- }
- // Overwrite State
- if config.PresenceState != nil {
- statusState = *config.PresenceState
- if statusState != "" {
- statusState = dataKeyReplacement(statusState)
- }
- }
- // Update
- bot.UpdateStatusComplex(discordgo.UpdateStatusData{
- Game: &discordgo.Game{
- Name: status,
- Type: config.PresenceType,
- Details: statusDetails, // Only visible if real user
- State: statusState, // Only visible if real user
- },
- Status: config.PresenceStatus,
- })
- } else if config.PresenceStatus != string(discordgo.StatusOnline) {
- bot.UpdateStatusComplex(discordgo.UpdateStatusData{
- Status: config.PresenceStatus,
- })
- }
- }
- //#endregion
- //#region Embeds
- func getEmbedColor(channelID string) int {
- var err error
- var color *string
- var channelInfo *discordgo.Channel
- // Assign Defined Color
- if config.EmbedColor != nil {
- if *config.EmbedColor != "" {
- color = config.EmbedColor
- }
- }
- // Overwrite with Defined Color for Channel
- /*var msg *discordgo.Message
- msg.ChannelID = channelID
- if channelRegistered(msg) {
- channelConfig := getSource(channelID)
- if channelConfig.OverwriteEmbedColor != nil {
- if *channelConfig.OverwriteEmbedColor != "" {
- color = channelConfig.OverwriteEmbedColor
- }
- }
- }*/
- // Use Defined Color
- if color != nil {
- // Defined as Role, fetch role color
- if *color == "role" || *color == "user" {
- botColor := bot.State.UserColor(botUser.ID, channelID)
- if botColor != 0 {
- return botColor
- }
- goto color_random
- }
- // Defined as Random, jump below (not preferred method but seems to work flawlessly)
- if *color == "random" || *color == "rand" {
- goto color_random
- }
- var colorString string = *color
- // Input is Hex
- colorString = strings.ReplaceAll(colorString, "#", "")
- if convertedHex, err := strconv.ParseUint(colorString, 16, 64); err == nil {
- return int(convertedHex)
- }
- // Input is Int
- if convertedInt, err := strconv.Atoi(colorString); err == nil {
- return convertedInt
- }
- // Definition is invalid since hasn't returned, so defaults to below...
- }
- // User color
- channelInfo, err = bot.State.Channel(channelID)
- if err == nil {
- if channelInfo.Type != discordgo.ChannelTypeDM && channelInfo.Type != discordgo.ChannelTypeGroupDM {
- if bot.State.UserColor(botUser.ID, channelID) != 0 {
- return bot.State.UserColor(botUser.ID, channelID)
- }
- }
- }
- // Random color
- color_random:
- var randomColor string = randomcolor.GetRandomColorInHex()
- if convertedRandom, err := strconv.ParseUint(strings.ReplaceAll(randomColor, "#", ""), 16, 64); err == nil {
- return int(convertedRandom)
- }
- return 16777215 // white
- }
- // Shortcut function for quickly constructing a styled embed with Title & Description
- func buildEmbed(channelID string, title string, description string) *discordgo.MessageEmbed {
- return &discordgo.MessageEmbed{
- Title: title,
- Description: description,
- Color: getEmbedColor(channelID),
- Footer: &discordgo.MessageEmbedFooter{
- IconURL: projectIcon,
- Text: fmt.Sprintf("%s v%s", projectName, projectVersion),
- },
- }
- }
- // Shortcut function for quickly replying a styled embed with Title & Description
- func replyEmbed(m *discordgo.Message, title string, description string) (*discordgo.Message, error) {
- if m != nil {
- if hasPerms(m.ChannelID, discordgo.PermissionSendMessages) {
- if selfbot {
- return bot.ChannelMessageSend(m.ChannelID, fmt.Sprintf("%s **%s**\n\n%s", m.Author.Mention(), title, description))
- } else {
- return bot.ChannelMessageSendComplex(m.ChannelID,
- &discordgo.MessageSend{
- Content: m.Author.Mention(),
- Embed: buildEmbed(m.ChannelID, title, description),
- },
- )
- }
- }
- log.Println(lg("Discord", "replyEmbed", color.HiRedString, fmtBotSendPerm, m.ChannelID))
- }
- return nil, nil
- }
- //#endregion
- //#region Send Status
- type sendStatusType int
- const (
- sendStatusStartup sendStatusType = iota
- sendStatusReconnect
- sendStatusExit
- sendStatusSettings
- )
- func sendStatusLabel(status sendStatusType) string {
- switch status {
- case sendStatusStartup:
- return "has launched"
- case sendStatusReconnect:
- return "has reconnected"
- case sendStatusExit:
- return "is exiting"
- case sendStatusSettings:
- return "updated settings"
- }
- return "is confused"
- }
- func sendStatusMessage(status sendStatusType) {
- for _, adminChannel := range config.AdminChannels {
- if *adminChannel.LogStatus {
- var message string
- var label string
- var emoji string
- //TODO: CLEAN
- if status == sendStatusStartup || status == sendStatusReconnect {
- label = "startup"
- emoji = "🟩"
- if status == sendStatusReconnect {
- emoji = "🟧"
- }
- message += fmt.Sprintf("%s %s and connected to %d server%s...\n", projectLabel, sendStatusLabel(status), len(bot.State.Guilds), pluralS(len(bot.State.Guilds)))
- message += fmt.Sprintf("\n• Uptime is %s", uptime())
- message += fmt.Sprintf("\n• %s total downloads", formatNumber(int64(dbDownloadCount())))
- message += fmt.Sprintf("\n• Bound to %d channel%s, %d categories, %d server%s, %d user%s",
- getBoundChannelsCount(), pluralS(getBoundChannelsCount()),
- getBoundCategoriesCount(),
- getBoundServersCount(), pluralS(getBoundServersCount()),
- getBoundUsersCount(), pluralS(getBoundUsersCount()),
- )
- if config.All != nil {
- message += "\n• **ALL MODE ENABLED -** Bot will use all available channels"
- }
- allChannels := getAllRegisteredChannels()
- message += fmt.Sprintf("\n• ***Listening to %s channel%s...***\n", formatNumber(int64(len(allChannels))), pluralS(len(allChannels)))
- message += fmt.Sprintf("\n_%s_", versions(true))
- } else if status == sendStatusExit {
- label = "exit"
- emoji = "🟥"
- message += fmt.Sprintf("%s %s...\n", projectLabel, sendStatusLabel(status))
- message += fmt.Sprintf("\n• Uptime was %s", uptime())
- message += fmt.Sprintf("\n• %s total downloads", formatNumber(int64(dbDownloadCount())))
- message += fmt.Sprintf("\n• Bound to %d channel%s, %d categories, %d server%s, %d user%s",
- getBoundChannelsCount(), pluralS(getBoundChannelsCount()),
- getBoundCategoriesCount(),
- getBoundServersCount(), pluralS(getBoundServersCount()),
- getBoundUsersCount(), pluralS(getBoundUsersCount()),
- )
- } else if status == sendStatusSettings {
- label = "settings"
- emoji = "🟨"
- message += fmt.Sprintf("%s %s...\n", projectLabel, sendStatusLabel(status))
- message += fmt.Sprintf("\n• Bound to %d channel%s, %d categories, %d server%s, %d user%s",
- getBoundChannelsCount(), pluralS(getBoundChannelsCount()),
- getBoundCategoriesCount(),
- getBoundServersCount(), pluralS(getBoundServersCount()),
- getBoundUsersCount(), pluralS(getBoundUsersCount()),
- )
- }
- // Send
- if config.Debug {
- log.Println(lg("Debug", "Status", color.HiCyanString, "Sending log for %s to admin channel %s",
- label, adminChannel.ChannelID))
- }
- if hasPerms(adminChannel.ChannelID, discordgo.PermissionEmbedLinks) && !selfbot {
- bot.ChannelMessageSendEmbed(adminChannel.ChannelID,
- buildEmbed(adminChannel.ChannelID, emoji+" Log — Status", message))
- } else if hasPerms(adminChannel.ChannelID, discordgo.PermissionSendMessages) {
- bot.ChannelMessageSend(adminChannel.ChannelID, message)
- } else {
- log.Println(lg("Debug", "Status", color.HiRedString, "Perms checks failed for sending status log to %s",
- adminChannel.ChannelID))
- }
- }
- }
- }
- func sendErrorMessage(err string) {
- for _, adminChannel := range config.AdminChannels {
- if *adminChannel.LogErrors {
- // Send
- if hasPerms(adminChannel.ChannelID, discordgo.PermissionEmbedLinks) && !selfbot { // not confident this is the right permission
- if config.Debug {
- log.Println(lg("Debug", "sendErrorMessage", color.HiCyanString, "Sending embed log for error to %s",
- adminChannel.ChannelID))
- }
- bot.ChannelMessageSendEmbed(adminChannel.ChannelID, buildEmbed(adminChannel.ChannelID, "Log — Error", err))
- } else if hasPerms(adminChannel.ChannelID, discordgo.PermissionSendMessages) {
- if config.Debug {
- log.Println(lg("Debug", "sendErrorMessage", color.HiCyanString, "Sending embed log for error to %s",
- adminChannel.ChannelID))
- }
- bot.ChannelMessageSend(adminChannel.ChannelID, err)
- } else {
- log.Println(lg("Debug", "sendErrorMessage", color.HiRedString, "Perms checks failed for sending error log to %s",
- adminChannel.ChannelID))
- }
- }
- }
- }
- //#endregion
- //#region Permissions
- // Checks if message author is a specified bot admin.
- func isBotAdmin(m *discordgo.Message) bool {
- // No Admins or Admin Channels
- if len(config.Admins) == 0 && len(config.AdminChannels) == 0 {
- return true
- }
- // configurationAdminChannel.UnlockCommands Bypass
- if isAdminChannelRegistered(m.ChannelID) {
- channelConfig := getAdminChannelConfig(m.ChannelID)
- if *channelConfig.UnlockCommands {
- return true
- }
- }
- return m.Author.ID == botUser.ID || stringInSlice(m.Author.ID, config.Admins)
- }
- // Checks if message author is a specified bot admin OR is server admin OR has message management perms in channel
- /*func isLocalAdmin(m *discordgo.Message) bool {
- if m == nil {
- if config.Debug {
- log.Println(lg("Debug", "isLocalAdmin", color.YellowString, "check failed due to empty message"))
- }
- return true
- }
- sourceChannel, err := bot.State.Channel(m.ChannelID)
- if err != nil || sourceChannel == nil {
- if config.Debug {
- log.Println(lg("Debug", "isLocalAdmin", color.YellowString,
- "check failed due to an error or received empty channel info for message:\t%s", err))
- }
- return true
- } else if sourceChannel.Name == "" || sourceChannel.GuildID == "" {
- if config.Debug {
- log.Println(lg("Debug", "isLocalAdmin", color.YellowString,
- "check failed due to incomplete channel info"))
- }
- return true
- }
- guild, _ := bot.State.Guild(m.GuildID)
- localPerms, err := bot.State.UserChannelPermissions(m.Author.ID, m.ChannelID)
- if err != nil {
- if config.Debug {
- log.Println(lg("Debug", "isLocalAdmin", color.YellowString,
- "check failed due to error when checking permissions:\t%s", err))
- }
- return true
- }
- botSelf := m.Author.ID == botUser.ID
- botAdmin := stringInSlice(m.Author.ID, config.Admins)
- guildOwner := m.Author.ID == guild.OwnerID
- guildAdmin := localPerms&discordgo.PermissionAdministrator > 0
- localManageMessages := localPerms&discordgo.PermissionManageMessages > 0
- return botSelf || botAdmin || guildOwner || guildAdmin || localManageMessages
- }*/
- func hasPerms(channelID string, permission int64) bool {
- if selfbot {
- return true
- }
- sourceChannel, err := bot.State.Channel(channelID)
- if sourceChannel != nil && err == nil {
- switch sourceChannel.Type {
- case discordgo.ChannelTypeDM:
- return true
- case discordgo.ChannelTypeGroupDM:
- return true
- case discordgo.ChannelTypeGuildText:
- perms, err := bot.UserChannelPermissions(botUser.ID, channelID)
- if err == nil {
- return perms&permission == permission
- }
- log.Println(lg("Debug", "hasPerms", color.HiRedString,
- "Failed to check permissions (%d) for %s:\t%s", permission, channelID, err))
- }
- }
- return true
- }
- //#endregion
- //#region Labeling
- func getUserIdentifier(usr discordgo.User) string {
- return fmt.Sprintf("\"%s\"#%s", usr.Username, usr.Discriminator)
- }
- //#endregion
|