sweetiebot

package
Version: v0.0.0-...-5a53b0f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 13, 2022 License: MIT Imports: 33 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ChannelEmpty     = DiscordChannel("")
	ChannelExclusion = DiscordChannel("!")
	RoleEmpty        = DiscordRole("")
	RoleExclusion    = DiscordRole("!")
	UserEmpty        = DiscordUser("")
	GuildEmpty       = DiscordGuild("")
)
View Source
const (
	CleanMentions  = 1 << iota
	CleanPings     = 1 << iota
	CleanURL       = 1 << iota
	CleanEmotes    = 1 << iota
	CleanCode      = 1 << iota
	CleanCodeBlock = CleanCode | CleanEmotes
	CleanAll       = CleanMentions | CleanURL | CleanEmotes | CleanCode | CleanPings
	CleanMost      = CleanMentions | CleanURL | CleanEmotes | CleanPings
)
View Source
const (
	AuditTypeLog     = iota
	AuditTypeAction  = iota
	AuditTypeCommand = iota
)

Audit types

View Source
const (
	STRING_INVALID_COMMAND                   = iota
	STRING_PM_FAILURE                        = iota
	STRING_CHECK_PM                          = iota
	STRING_DATABASE_ERROR                    = iota
	STRING_NO_SERVER                         = iota
	STRING_COMMANDS_LIMIT                    = iota
	STRING_COMMAND_LIMIT                     = iota
	STRING_SETUP_MESSAGE                     = iota
	STRING_SPAM_DESCRIPTION                  = iota
	STRING_SPAM_ERROR_UNSILENCING            = iota
	STRING_SPAM_UNSILENCING                  = iota
	STRING_SPAM_EMBEDDED_URLS                = iota
	STRING_SPAM_TRUNCATED                    = iota
	STRING_SPAM_KILLING_SPAMMER_DETAIL       = iota
	STRING_SPAM_AUTOBANNED_REASON            = iota
	STRING_SPAM_BAN_ALERT                    = iota
	STRING_SPAM_ERROR_RETRIEVE_MESSAGES      = iota
	STRING_SPAM_WILL_BE_UNSILENCED           = iota
	STRING_SPAM_SILENCE_ALERT                = iota
	STRING_SPAM_KILLING_SPAMMER              = iota
	STRING_SPAM_REASON_MESSAGES              = iota
	STRING_SPAM_REASON_FILES                 = iota
	STRING_SPAM_REASON_IMAGES                = iota
	STRING_SPAM_REASON_PINGS                 = iota
	STRING_SPAM_REASON_LENGTH                = iota
	STRING_SPAM_REASON_NEWLINES              = iota
	STRING_SPAM_REASON_COPY                  = iota
	STRING_SPAM_GUILD_NOT_FOUND              = iota
	STRING_SPAM_VERIFICATION_LEVEL_ERROR     = iota
	STRING_SPAM_LOCKDOWN_DISENGAGE_FAILURE   = iota
	STRING_SPAM_LOCKDOWN_DISENGAGE           = iota
	STRING_SPAM_USER_JOINED                  = iota
	STRING_SPAM_JOINED_APPEND                = iota
	STRING_SPAM_RAIDSILENCE_ALL_POSTFIX      = iota
	STRING_SPAM_RAIDSILENCE_ENGAGED          = iota
	STRING_SPAM_RAID_DETECTED                = iota
	STRING_SPAM_LOCKDOWN_ENGAGE_FAILURE      = iota
	STRING_SPAM_LOCKDOWN_ENGAGE              = iota
	STRING_SPAM_RAIDSILENCE_USAGE            = iota
	STRING_SPAM_RAIDSILENCE_ARGS_ERROR       = iota
	STRING_SPAM_RAIDSILENCE_ARGS             = iota
	STRING_SPAM_RAIDSILENCE_DATABASE_ERROR   = iota
	STRING_SPAM_RAIDSILENCE_SET_RAID         = iota
	STRING_SPAM_RAIDSILENCE_DETECTION        = iota
	STRING_SPAM_RAIDSILENCE_SET              = iota
	STRING_SPAM_RAIDSILENCE_DESCRIPTION      = iota
	STRING_SPAM_RAIDSILENCE_DESCRIPTION_NAME = iota
	STRING_SPAM_WIPE_USAGE                   = iota
	STRING_SPAM_WIPE_ARG_ERROR               = iota
	STRING_SPAM_WIPE_PM_ERROR                = iota
	STRING_SPAM_WIPE_CHANNEL_ERROR           = iota
	STRING_SPAM_WIPE_NO_MESSAGES             = iota
	STRING_SPAM_WIPE_RETRIEVAL_ERROR         = iota
	STRING_SPAM_WIPE_DELETED                 = iota
	STRING_SPAM_WIPE_DESCRIPTION             = iota
	STRING_SPAM_WIPE_CHANNEL                 = iota
	STRING_SPAM_WIPE_MESSAGES                = iota
	STRING_SPAM_PRESSURE_USAGE               = iota
	STRING_SPAM_PRESSURE_ARG_ERROR           = iota
	STRING_SPAM_PRESSURE_DESCRIPTION         = iota
	STRING_SPAM_PRESSURE_USER                = iota
	STRING_SPAM_RAID_USAGE                   = iota
	STRING_SPAM_RAID_NONE                    = iota
	STRING_SPAM_RAID_USERS                   = iota
	STRING_SPAM_RAID_DESCRIPTION             = iota
	STRING_SPAM_BANRAID_USAGE                = iota
	STRING_SPAM_BANRAID_REASON               = iota
	STRING_SPAM_BANRAID_RESULT               = iota
	STRING_SPAM_BANRAID_DESCRIPTION          = iota
	STRING_USERS_BAN_MOD_ERROR               = iota
	STRING_USERS_SILENCE_USAGE               = iota
	STRING_USERS_SILENCE_ARG_ERROR           = iota
	STRING_USERS_SILENCE_ERROR               = iota
	STRING_USERS_SILENCE_MOD_ERROR           = iota
	STRING_USERS_SILENCE_ALREADY_SILENCED    = iota
	STRING_USERS_SILENCE_WILL_BE_UNSILENCED  = iota
	STRING_USERS_SILENCE_REASON              = iota
	STRING_USERS_SILENCE                     = iota
	STRING_USERS_SILENCE_DESCRIPTION         = iota
	STRING_USERS_SILENCE_USER                = iota
	STRING_USERS_SILENCE_DURATION            = iota
	STRING_USERS_UNSILENCE_USAGE             = iota
	STRING_USERS_UNSILENCE_ARG_ERROR         = iota
	STRING_USERS_UNSILENCE_ERROR             = iota
	STRING_USERS_UNSILENCE_MOD_ERROR         = iota
	STRING_USERS_UNSILENCE                   = iota
	STRING_USERS_UNSILENCE_DESCRIPTION       = iota
	STRING_USERS_UNSILENCE_USER              = iota
)
View Source
const (
	MaxPublicLines = 12

	SilverServerID  = "105443346608095232"
	PatreonURL      = "https://www.patreon.com/erikmcclure"
	QuitNone        = 0
	QuitNow         = 1
	QuitRaid        = 2
	UpdateGrace     = 120
	MaxUpdateGrace  = 600
	UpdateInterval  = 300
	CleanInterval   = 3600
	ExpireTime      = 3600 * 72
	MaxScheduleRows = 5000
	DelayTime       = time.Duration(200 * time.Millisecond)
)
View Source
const (
	FormatPartialYear = 0
	FormatFullYear    = 1
	FormatNoYear      = 2
	FormatYearNum     = 3
	FormatStandard    = 0
	FormatMilitary    = 1
	FormatNoTime      = 2
	FormatTimeNum     = 3
	FormatZoneOffset  = 0
	FormatZoneHours   = 1
	FormatNoZone      = 2
	FormatZoneNum     = 3
)

Time format options

View Source
const DBReconnectTimeout = time.Duration(30) * time.Second

DBReconnectTimeout is the reconnect time interval in seconds

View Source
const DiscordEpoch uint64 = 1420070400000

DiscordEpoch is used to figure out snowflake creation times

Variables

View Source
var BotVersion = Version{1, 0, 2, 1}

BotVersion stores the current version of sweetiebot

View Source
var ChannelRegex = regexp.MustCompile("<#([0-9]+)>")

ChannelRegex matches any valid discord channel ping

View Source
var ConfigHelp = map[string]map[string]string{
	"basic": {
		"ignoreinvalidcommands": "If true, the bot won't display an error if a nonsensical command is used. This helps reduce confusion with other bots that use the same prefix.",
		"importable":            "If true, the collections on this server will be importable into another server.",
		"modrole":               "This is intended to point at a moderator role shared by all admins and moderators of the server for notification purposes.",
		"modchannel":            "This should point at the hidden moderator channel, or whatever channel moderates want to be notified on.",
		"freechannels":          "This is a list of all channels that are exempt from bot command rate limiting. Usually set to the dedicated `#botabuse` channel in a server. Does NOT affect anti-spam! To exclude anti-spam from a channel, use `!setconfig modules.channels spam ! #yourchannel`.",
		"botchannel":            "This allows you to designate a particular channel to point users if they are trying to run too many commands at once. Usually this channel will also be included in `basic.freechannels`. Again, this is for bot commands, not general spamming!",
		"aliases":               "Can be used to redirect commands, such as making `!listgroup` call the `!listgroups` command. Useful for making shortcuts.\n\nExample: `!setconfig basic.aliases kawaii pick cute` sets an alias mapping `!kawaii arg1...` to `!pick cute arg1...`, preserving all arguments that are passed to the alias.",
		"listentobots":          "If true, processes messages from other bots and allows them to run commands. Bots can never trigger anti-spam. Defaults to false.",
		"commandprefix":         "Determines the SINGLE ASCII CHARACTER prefix used to denote bot commands. You can't set it to an emoji or any weird foreign character. The default is `!`. If this is set to an invalid value, it defaults to `!`.",
		"silencerole":           "This should be a role with no permissions, so the bot can quarantine potential spammers without banning them. The bot usually manages this role for you, so you should almost never touch this value.",
		"memberrole":            "This should be a role with all permissions that the everyone role would normally have. You shouldn't touch this value, use the !SetMemberRole command to manage it instead.",
	},
	"modules": {
		"commandroles":       "A map of which roles are allowed to run which command. If no mapping exists, everyone can run the command.",
		"commandchannels":    "A map of which channels commands are allowed to run on. No entry means a command can be run anywhere. If `!` is included as a channel, it switches from a whitelist to a blacklist, enabling you to exclude certain channels instead of allow certain channels.",
		"commandlimits":      "A map of timeouts for commands. A value of 30 means the command can't be used more than once every 30 seconds.",
		"commanddisabled":    "A list of disabled commands. Disabled commands can still be run by administrators, but can't be run by the bot and will not function as a bored command.",
		"commandperduration": "Maximum number of commands that can be run within `commandmaxduration` seconds. Default: 3",
		"commandmaxduration": "Default: 20. This means that by default, at most 3 commands can be run every 20 seconds.",
		"disabled":           "A list of disabled modules. This disables any hooks the modules normally process, and also disables all commands inside that module (although commands can be selectively re-enabled without enabling the module).",
		"channels":           "A mapping of what channels a given module can operate on. If no mapping is given, a module operates on all channels. If `!` is included as a channel, it switches from a whitelist to a blacklist, enabling you to exclude certain channels instead of allow certain channels. Restricting a module to a channel DOES NOT restrict its commands to that channel.",
	},
	"spam": {
		"imagepressure":      "Additional pressure generated by each image, link or attachment in a message. Defaults to (MaxPressure - BasePressure) / 6 = 8.3, instantly silencing anyone posting 6 or more links at once.",
		"repeatpressure":     "Additional pressure generated by a message that is identical to the previous message sent (ignores case). Defaults to BasePressure, effectively doubling the pressure penalty for repeated messages.",
		"pingpressure":       "Additional pressure generated by each unique ping in a message. Defaults to (MaxPressure - BasePressure) / 20 = 2.5, instantly silencing anyone pinging 20 or more people at once.",
		"lengthpressure":     "Additional pressure generated by each individual character in the message. Discord allows messages up to 2000 characters in length. Defaults to (MaxPressure - BasePressure) / 8000 = 0.00625, silencing anyone posting 3 huge messages at the same time.",
		"linepressure":       "Additional pressure generated by each newline in the message. Defaults to (MaxPressure - BasePressure) / 70 = 0.714, silencing anyone posting more than 70 newlines in a single message",
		"basepressure":       "The base pressure generated by sending a message, regardless of length or content. Defaults to 10",
		"maxpressure":        "The maximum pressure allowed. If a user's pressure exceeds this amount, they will be silenced. Defaults to 60, which is intended to ban after a maximum of 6 short messages sent in rapid succession.",
		"maxchannelpressure": "Per-channel pressure override. If a channel's pressure is specified in this map, it will override the global maxpressure setting.",
		"pressuredecay":      "The number of seconds it takes for a user to lose Spam.BasePressure from their pressure amount. Defaults to 2.5, so after sending 3 messages, it will take 7.5 seconds for their pressure to return to 0.",
		"maxremovelookback":  "Number of seconds back the bot should delete messages of a silenced user on the channel they spammed on. If set to 0, the bot will only delete the message that caused the user to be silenced. If less than 0, the bot won't delete any messages.",
		"ignorerole":         "If set, the bot will exclude anyone with this role from spam detection. Use with caution. Does NOT prevent people from sending the bot commands.",
		"raidtime":           "In order to trigger a raid alarm, at least `spam.raidsize` people must join the chat within this many seconds of each other.",
		"raidsize":           "Specifies how many people must have joined the server within the `spam.raidtime` period to qualify as a raid.",
		"raidsilence":        "Gets the current raidsilence state. Use the `!RaidSilence` command to set this.",
		"lockdownduration":   "Determines how long the server's verification mode will temporarily be increased to tableflip levels after a raid is detected. If set to 0, disables lockdown entirely.",
		"silencetimeout":     "If greater than 0, any members silenced by the bot (not by the `!silence` command) will be automatically unsilenced after this many seconds. This includes anyone silenced during a raid.",
	},
	"bucket": {
		"maxitems":       "Determines the maximum number of items that can be carried in the bucket. If set to 0, the bucket is disabled.",
		"maxitemlength":  "Determines the maximum length of a string that can be added to the bucket.",
		"maxfighthp":     "Maximum HP of the randomly generated enemy for the `!fight` command.",
		"maxfightdamage": "Maximum amount of damage a randomly generated weapon can deal for the `!fight` command.",
		"items":          "List of items in the bucket.",
	},
	"markov": {
		"maxpmlines":     "This is the maximum number of lines a response can be before its automatically sent as a PM to avoid cluttering the chat. Default: 5",
		"maxlines":       "Maximum number of lines the `!episodequote` command can be given.",
		"defaultlines":   "Number of lines for the markov chain to spawn when not given a line count.",
		"usemembernames": "Use member names instead of random pony names.",
	},
	"users": {
		"timezonelocation": "Sets the timezone location of the server itself. When no user timezone is available, the bot will use this.",
		"welcomechannel":   "If set to a channel ID, the bot will treat this channel as a \"quarantine zone\" for new members that haven't had their Member role set. If RaidSilence is enabled, new users will be sent to this channel.",
		"jailchannel":      "If set to a channel ID, the bot will treat this channel as a \"quarantine zone\" for silenced members. This can be the same as the welcome channel, or it can be a different one.",
		"welcomemessage":   "If RaidSilence is enabled, this message will be sent to a new user upon joining.",
		"silencemessage":   "This message will be sent to users that have been silenced by the `!silence` command.",
		"roles":            "A list of all user-assignable roles. Manage it via !addrole and !removerole",
		"notifychannel":    "If set to a channel ID other than zero, sends a message to that channel whenever a new user joins the server.",
		"trackuserleft":    "If true, tracks users that leave the server if notifychannel is set.",
		"newuserrole":      "If this is set and `newuserduration` is nonzero, this role is given to any new user that joins, regardless of raid settings. It is automatically removed after `newuserduration` seconds.",
		"newuserduration":  "The number of seconds a new user will have the `newuserrole` role. If zero, `newuserrole` won't be given to any new user.",
	},
	"filter": {
		"filters":   "A collection of word lists for each filter. These are combined into a single regex of the form `(word1|word2|etc...)`, depending on the filter template.",
		"channels":  "A collection of channel exclusions for each filter.",
		"responses": "The response message sent by each filter when triggered. If this is set to `!`, the bot won't respond AND she won't delete the message, only the pressure will be added.",
		"templates": "The template used to construct the regex. `%%` is replaced with `(word1|word2|etc...)` using the filter's word list. Example: `\\[\\]\\(\\/r?%%[-) \"]` is transformed into `\\[\\]\\(\\/r?(word1|word2)[-) \"]`",
		"pressure":  "The amount of pressure added to the user when the filter is triggered (defaults to 0).",
	},
	"bored": {
		"cooldown": "The bored cooldown timer, in seconds. This is the length of time a channel must be inactive before a bored message is posted.",
		"exponent": "The exponential increase in time between bored posts if no one other than the bot is posting. A value of about 1.41 doubles the amount of time between bored posts until someone else says something. Defaults to 1, which means no increase. The actual formula is (2^n + n).",
		"commands": "This determines what commands will be run when nothing has been said in a channel for a while. One command will be chosen from this list at random.\n\nExample: `!setconfig bored.commands !drop \"!pick bored\"`",
	},
	"information": {
		"rules":             "Contains a list of numbered rules. The numbers do not need to be contiguous, and can be negative.",
		"hidenegativerules": "If true, `!rules -1` will display a rule at index -1, but `!rules` will not. This is useful for joke rules or additional rules that newcomers don't need to know about.",
	},
	"log": {
		"channel":  "This is the channel where log output is sent.",
		"cooldown": "The cooldown time to display an error message, in seconds, intended to prevent the bot from spamming itself. Default: 4",
	},
	"witty": {
		"responses": "Stores the replies used by the Witty module and must be configured using `!addwit` or `!removewit`",
		"cooldown":  "The cooldown time for the witty module. At least this many seconds must have passed before the bot will make another witty reply.",
	},
	"scheduler": {
		"birthdayrole": " This is the role given to members on their birthday.",
	},
	"miscellaneous": {
		"maxsearchresults": "Maximum number of search results that can be requested at once.",
	},
	"spoiler": {
		"channels": "A list of channels that are exempt from the spoiler rules.",
	},
	"status": {
		"cooldown": "Number of seconds the bot waits before changing its status to a string picked randomly from the `status` collection.",
		"lines":    "List of possible status messages that the bot can have.",
	},
	"quote": {
		"quotes": "This is a map of quotes, which should be managed via `!addquote` and `!removequote`.",
	},
	"counters": {
		"map":          "This is a map of counters, which should be managed via `!addcounter` and `!removecounter`.",
		"descriptions": "These are descriptions for each counter in map, which should be managed via `!addcounter` and `!removecounter`.",
	},
}

ConfigHelp is a map of help strings for the configuration options above

View Source
var ConfigVersion = 30

ConfigVersion is the latest version of the config file

View Source
var ErrDuplicateEntry = errors.New("Error 1062: Duplicate entry for unique key")

ErrDuplicateEntry - Error 1062: Duplicate entry for unique key

View Source
var ErrLockWaitTimeout = errors.New("Error 1205: Lock wait timeout exceeded")

ErrLockWaitTimeout - Error 1205: Lock wait timeout exceeded

View Source
var ErrMD5Error = errors.New("MD5 mismatch, file corrupt")
View Source
var ErrRoleNoMatch = errors.New("role doesn't exist on this server")

ErrRoleNoMatch is thrown when a role name doesn't exist on the server

View Source
var RoleRegex = regexp.MustCompile("<\\\\?@&([0-9]+)>")

RoleRegex matches any valid role ping

View Source
var StringMap = map[int]string{
	STRING_INVALID_COMMAND:                   "Sorry, %s is not a valid command.\nFor a list of valid commands, type %shelp.",
	STRING_PM_FAILURE:                        "I tried to send you a Private Message, but it failed! Try PMing me the command directly.",
	STRING_CHECK_PM:                          "```\nCheck your Private Messages for my reply!```",
	STRING_DATABASE_ERROR:                    "```\nA temporary database error means I can't process any private message commands right now.```",
	STRING_NO_SERVER:                         "```\nCannot determine what server you belong to! Use !defaultserver to set which server I should use when you PM me.```",
	STRING_COMMANDS_LIMIT:                    "You can't input more than %v commands every %s!%s",
	STRING_COMMAND_LIMIT:                     "You can only run that command once every %s!%s",
	STRING_SETUP_MESSAGE:                     "You haven't set up the bot yet! Run the %ssetup command first and follow the instructions.",
	STRING_SPAM_DESCRIPTION:                  "Tracks all channels it is active on for spammers. Each message someone sends generates \"pressure\", which decays rapidly. Long messages, messages with links, or messages with pings will generate more pressure. If a user generates too much pressure, they will be silenced and the moderators notified. Also detects groups of people joining at the same time and alerts the moderators of a potential raid.\n\nTo force this module to ignore a specific channel, use this command: `%ssetconfig modules.channels spam ! #channelname`. If the bot is silencing everyone, you should re-run `%ssetup OVERRIDE` to reset the spam configuration. If you want to have a containment channel where silenced members can talk, use `%ssetconfig welcomechannel #channelname`.\n\n**IF THE BOT IS OVERWHELMED BY A RAID, FOLLOW THESE INSTRUCTIONS CAREFULLY:** Due to rate limits, the bot can be overwhelmed by spammers using hundreds of different accounts. As a last resort, you can tell the bot to **ban everyone who has sent their first message in the past 3 minutes** by running this command: `%sbannewcomers`. Only use this as a **last resort**, as it can easily ban people who joined and were caught up in the raid.",
	STRING_SPAM_ERROR_UNSILENCING:            "```\nError unsilencing member: %v```",
	STRING_SPAM_UNSILENCING:                  "```\nUnsilenced %v.```",
	STRING_SPAM_EMBEDDED_URLS:                "\nEmbedded URLs: ",
	STRING_SPAM_TRUNCATED:                    "... [truncated]",
	STRING_SPAM_KILLING_SPAMMER_DETAIL:       "Killing spammer %s (pressure: %v -> %v). Last message sent on #%s in %s: \n%s%s",
	STRING_SPAM_AUTOBANNED_REASON:            "Autobanned for %v in the welcome channel.",
	STRING_SPAM_BAN_ALERT:                    "Alert: <@%v> was banned for %v in the welcome channel.",
	STRING_SPAM_ERROR_RETRIEVE_MESSAGES:      "Error encountered while attempting to retrieve messages: ",
	STRING_SPAM_WILL_BE_UNSILENCED:           ", or they will be unsilenced automatically in %v",
	STRING_SPAM_SILENCE_ALERT:                "Alert: <@%v> was silenced for %v. Please investigate%v",
	STRING_SPAM_KILLING_SPAMMER:              "Killing spammer %v",
	STRING_SPAM_REASON_MESSAGES:              "spamming too many messages",
	STRING_SPAM_REASON_FILES:                 "attaching too many files",
	STRING_SPAM_REASON_IMAGES:                "spamming too many images",
	STRING_SPAM_REASON_PINGS:                 "pinging too many people",
	STRING_SPAM_REASON_LENGTH:                "sending a really long message",
	STRING_SPAM_REASON_NEWLINES:              "using too many newlines",
	STRING_SPAM_REASON_COPY:                  "copy+pasting the same message",
	STRING_SPAM_GUILD_NOT_FOUND:              "Guild cannot be found in state?!",
	STRING_SPAM_VERIFICATION_LEVEL_ERROR:     "The verification level is at %v instead of %v, which means it was manually changed by someone other than %v, so it has not been restored.",
	STRING_SPAM_LOCKDOWN_DISENGAGE_FAILURE:   "Could not disengage lockdown! Make sure you've given the %v role the Manage Server permission, you'll have to manually restore it yourself this time.",
	STRING_SPAM_LOCKDOWN_DISENGAGE:           "Lockdown disengaged, server verification levels restored.",
	STRING_SPAM_USER_JOINED:                  "%v (joined: %v)",
	STRING_SPAM_RAIDSILENCE_ALL_POSTFIX:      "Use `%vraidsilenceall to silence them!",
	STRING_SPAM_RAIDSILENCE_ENGAGED:          "RaidSilence has been engaged and the following users silenced:",
	STRING_SPAM_RAID_DETECTED:                " Possible Raid Detected! ",
	STRING_SPAM_LOCKDOWN_ENGAGE_FAILURE:      "Could not engage lockdown! Make sure you've given %v the Manage Server permission, or disable the lockdown entirely via `%vsetconfig spam.lockdownduration 0`.",
	STRING_SPAM_LOCKDOWN_ENGAGE:              "Lockdown engaged! Server verification level will be reset in %v seconds. This lockdown can be manually ended via `%vraidsilence off/alert/log`.",
	STRING_SPAM_RAIDSILENCE_USAGE:            "Toggle raid silencing.",
	STRING_SPAM_RAIDSILENCE_ARGS_ERROR:       "```\nYou must provide a raid silence level (either all, raid, or off).```",
	STRING_SPAM_RAIDSILENCE_ARGS:             "```\nOnly all, raid, and off are valid raid silence levels.```",
	STRING_SPAM_RAIDSILENCE_DATABASE_ERROR:   "```\nRaidSilence was engaged, but a database error prevents me from retroactively applying it!```",
	STRING_SPAM_RAIDSILENCE_SET_RAID:         "```\nRaid silence level set to %v.```",
	STRING_SPAM_RAIDSILENCE_DETECTION:        "```\nDetected a recent raid. All users from the raid have been silenced:",
	STRING_SPAM_RAIDSILENCE_SET:              "```\nRaid silence level set to %v.```",
	STRING_SPAM_RAIDSILENCE_DESCRIPTION:      "Toggles silencing new members during raids. This does not affect spam detection, only new members joining the server.",
	STRING_SPAM_RAIDSILENCE_DESCRIPTION_NAME: "`all` will always silence all new members. `raid` will only silence new members if a raid is detected, up to `spam.raidtime*2` seconds after the raid is detected. `off` disables raid silencing.",
	STRING_SPAM_WIPE_USAGE:                   "Wipes a given channel",
	STRING_SPAM_WIPE_ARG_ERROR:               "```\nYou must specify the duration.```",
	STRING_SPAM_WIPE_PM_ERROR:                "```\nCan't delete messages in a PM!```",
	STRING_SPAM_WIPE_CHANNEL_ERROR:           "```\nThat channel isn't on this server!```",
	STRING_SPAM_WIPE_NO_MESSAGES:             "```\nThere's no point deleting 0 messages!.```",
	STRING_SPAM_WIPE_RETRIEVAL_ERROR:         "```\nError retrieving messages. Are you sure you gave %v a channel that exists? This won't work in PMs! %v```",
	STRING_SPAM_WIPE_DELETED:                 "Deleted %v messages in <#%s>.",
	STRING_SPAM_WIPE_DESCRIPTION:             "Removes all messages in a channel sent within the last N seconds, or remove the last N messages if 'm' is appended to the number. Examples: ```\n%swipe 23m``` ```\n%swipe #channel 10```",
	STRING_SPAM_WIPE_CHANNEL:                 "The channel to delete from. You must use the #channel format so discord actually highlights the channel, otherwise it won't work. If omitted, uses the current channel",
	STRING_SPAM_WIPE_MESSAGES:                "Specifies the number of seconds to look back. The command deletes all messages sent up to this many seconds ago. If you append 'm' to this number, it will instead delete exactly that many messages.",
	STRING_SPAM_PRESSURE_USAGE:               "Gets a user's pressure.",
	STRING_SPAM_PRESSURE_ARG_ERROR:           "```\nYou must provide a user to search for.```",
	STRING_SPAM_PRESSURE_DESCRIPTION:         "Gets the current spam pressure of a user.",
	STRING_SPAM_PRESSURE_USER:                "User to retrieve pressure from.",
	STRING_SPAM_RAID_USAGE:                   "Lists users in most recent raid.",
	STRING_SPAM_RAID_NONE:                    "```\nNo raid has occurred within the past %s.```",
	STRING_SPAM_RAID_USERS:                   "Users in latest raid: ",
	STRING_SPAM_RAID_DESCRIPTION:             "Lists all users that are considered part of the most recent raid, if there was one.",
	STRING_SPAM_BANRAID_USAGE:                "Bans all users in most recent raid.",
	STRING_SPAM_BANRAID_REASON:               "Banned by %s#%s via the %sbanraid command.",
	STRING_SPAM_BANRAID_RESULT:               "```\nBanned %v users. The ban log will reflect who ran this command.```",
	STRING_SPAM_BANRAID_DESCRIPTION:          "Bans all users that are considered part of the most recent raid, if there was one. Use %vgetraid to check who will be banned before using this command.",
	STRING_USERS_BAN_MOD_ERROR:               "```\nCan't ban %s because they're a moderator or an admin!```",
	STRING_USERS_SILENCE_USAGE:               "Silences a user.",
	STRING_USERS_SILENCE_ARG_ERROR:           "```\nYou must provide a user to silence.```",
	STRING_USERS_SILENCE_ERROR:               "```\nError occurred trying to silence %s: %s```",
	STRING_USERS_SILENCE_MOD_ERROR:           "```\nCannot silence %s because they're a moderator or admin!```",
	STRING_USERS_SILENCE_ALREADY_SILENCED:    "```\n%v is already silenced!```",
	STRING_USERS_SILENCE_WILL_BE_UNSILENCED:  "```\n%s is already silenced, and will be unsilenced in %s```",
	STRING_USERS_SILENCE_REASON:              " because %v",
	STRING_USERS_SILENCE:                     "```\nSilenced %s%s.```",
	STRING_USERS_SILENCE_DESCRIPTION:         "Silences the given user.",
	STRING_USERS_SILENCE_USER:                "A ping of the user, or simply their name.",
	STRING_USERS_SILENCE_DURATION:            "If the keyword `for:` is used after the username, looks for a duration of the form `for: 50 MINUTES` and creates an unsilence event that will be fired after that much time has passed from now.",
	STRING_USERS_UNSILENCE_USAGE:             "Unsilences a user.",
	STRING_USERS_UNSILENCE_ARG_ERROR:         "```\nYou must provide a user to unsilence.```",
	STRING_USERS_UNSILENCE_ERROR:             "```\nError unsilencing member: %v```",
	STRING_USERS_UNSILENCE_MOD_ERROR:         "```\nCannot unsilence %s because they are a mod or admin. Remove the status yourself!```",
	STRING_USERS_UNSILENCE:                   "```\nUnsilenced %v.```",
	STRING_USERS_UNSILENCE_DESCRIPTION:       "Unsilences the given user.",
	STRING_USERS_UNSILENCE_USER:              "A ping of the user, or simply their name.",
}

System-wide string map that can be substituted at runtime

View Source
var UserRegex = regexp.MustCompile("<\\\\?@!?([0-9]+)>")

UserRegex matches any valid user or nickname ping

Functions

func AbsInt

func AbsInt(x int64) int64

I'm going to find whoever is responsible for not including this in Go's standard library and dump them in the middle of Death Valley with an entire cactus shoved up their ass.

func AssembleVersion

func AssembleVersion(major byte, minor byte, revision byte, build byte) int

AssembleVersion creates a version integer out of four bytes

func CheckMapNilBool

func CheckMapNilBool(m *map[CommandID]bool)

CheckMapNilBool creates a new map if its nil

func CheckMapNilString

func CheckMapNilString(m *map[string]string)

CheckMapNilString creates a new map if its nil

func CheckRateLimit

func CheckRateLimit(prevtime *int64, interval int64, curtime int64) bool

CheckRateLimit performs a check on the rate limit without updating it

func DownloadFile

func DownloadFile(url string, file string, checkMD5 bool) error

DownloadFile downloads a file from the url and attempts to get a *.md5 to check it against if checkMD5 is true

func DumpCommandsModules

func DumpCommandsModules(info *GuildInfo, footer string, description string, msg *discordgo.Message) *discordgo.MessageEmbed

DumpCommandsModules dumps information about all commands and modules

func DumpScript

func DumpScript(dir string)

func ExecCommand

func ExecCommand(c *exec.Cmd, dir string, env ...string) (string, error)

ExecCommand adds a directory and environment to a command created by exec.Command()

func ExecuteSQLFile

func ExecuteSQLFile(db *sql.DB, file string) error

ExecuteSQLFile splits a file into statements and executes it

func FindRole

func FindRole(name string, guild *discordgo.Guild) (s []*discordgo.Role)

FindRole returns all roles with the given name

func FindUpgradeFiles

func FindUpgradeFiles(scriptdir string, version int) (files []int)

FindUpgradeFiles finds the .sql upgrade files that should be run

func FixRequest

func FixRequest(arg string, t reflect.Value) (string, error)

FixRequest takes a request that is not fully qualified and attempts to find a fully qualified version

func GetCurrentDir

func GetCurrentDir() (string, error)

GetCurrentDir relative to the executable

func GetJoinedAt

func GetJoinedAt(m *discordgo.Member) time.Time

GetJoinedAt returns either the time the member joined or time.Now() if there is an error

func GetRoleByName

func GetRoleByName(role string, info *GuildInfo) (*discordgo.Role, error)

GetRoleByName gets a role by its name

func GetTimestamp

func GetTimestamp(m *discordgo.Message) time.Time

GetTimestamp returns the timestamp of the last edit of the message or time.Now() if there is no valid timestamp

func GuildMemberPermissions

func GuildMemberPermissions(member *discordgo.Member, guild *discordgo.Guild) (apermissions int64)

GuildMemberPermissions gets all permissions for a user, ignoring channel specific overrides

func HTTPRequestData

func HTTPRequestData(url string) (body []byte, err error)

HTTPRequestData returns the result of an HTTP request as a byte array

func Install

func Install(path string, selfhoster *Selfhost)

Install sweetiebot in the given directory

func IsSpace

func IsSpace(b byte) bool

IsSpace returns true if the byte is considered whitespace in ASCII

func MapGetRandomItem

func MapGetRandomItem(m map[string]bool) string

MapGetRandomItem returns a random item from a map without removing it

func MapIntToSlice

func MapIntToSlice(m map[int]string) []int

MapIntToSlice for map[int]bool

func MapStringToSlice

func MapStringToSlice(m map[string]string) []string

MapStringToSlice for map[string]string

func MapToSlice

func MapToSlice(m map[string]bool) []string

MapToSlice for map[string]bool

func MemberHasRole

func MemberHasRole(m *discordgo.Member, role DiscordRole) bool

MemberHasRole returns true if the already resolved member object has the given role ID

func ParseArguments

func ParseArguments(s string) ([]string, []int)

ParseArguments transforms a command line into an array of distinct arguments, while respecting quotes

func ParseRepeatInterval

func ParseRepeatInterval(s string) uint8

ParseRepeatInterval returns what interval a string refers to

func PingAtoi

func PingAtoi(s string) uint64

PingAtoi extracts the internal ping ID and converts it to an integer

func Pluralize

func Pluralize(i int64, str string) string

Pluralize converts i to a string, then appends str to the end, then appends s if it's plural

func RateLimit

func RateLimit(prevtime *int64, interval int64, curtime int64) bool

RateLimit checks the rate limit, returns false if it was violated, and updates the rate limit

func RemoveSliceString

func RemoveSliceString(s *[]string, item string) bool

RemoveSliceString finds and removes an item from the slice

func ReplaceAllRolePings

func ReplaceAllRolePings(s string, info *GuildInfo) string

ReplaceAllRolePings finds any role pings and replaces them with the role name

func ReturnError

func ReturnError(err error) (string, bool, *discordgo.MessageEmbed)

ReturnError formats an error message and returns it as a message

func RunCommand

func RunCommand(path string, dir string, args ...string) (string, error)

RunCommand runs the given command and prints any output

func SBatoi

func SBatoi(s string) uint64

SBatoi converts a string to a uint64. Returns 0 if there is an error.

func SBitoa

func SBitoa(i uint64) string

SBitoa converts a uint64 to a string

func SnowflakeTime

func SnowflakeTime(id uint64) time.Time

SnowflakeTime returns the time a snowflake ID was created

func StartCommand

func StartCommand(path string, dir string, args ...string) error

StartCommand starts the given command but doesn't wait for it to complete

func StripPing

func StripPing(s string) string

StripPing strips the ping or channel information and returns the resulting string

func TimeDiff

func TimeDiff(d time.Duration) string

TimeDiff gets the largest nonzero time value and displays it

func UpdateEndpoint

func UpdateEndpoint(request string, userID DiscordUser, oldversion int) string

UpdateEndpoint returns the update endpoint for the given id and current architecture

func WaitForPID

func WaitForPID(arg string)

WaitForPID loops until there is no longer any running process with the given PID, or returns immediately if no valid ID is given

Types

type AtomicBool

type AtomicBool struct {
	// contains filtered or unexported fields
}

AtomicBool represents an atomic boolean that can be set to true or false

func (*AtomicBool) Get

func (b *AtomicBool) Get() bool

Get the current value of the bool

func (*AtomicBool) Set

func (b *AtomicBool) Set(value bool)

Set the value of the bool

type AtomicFlag

type AtomicFlag struct {
	// contains filtered or unexported fields
}

AtomicFlag represents an atomic bit that can be set or cleared

func (*AtomicFlag) Clear

func (f *AtomicFlag) Clear()

Clear sets the flag to 0

func (*AtomicFlag) TestAndSet

func (f *AtomicFlag) TestAndSet() bool

TestAndSet returns the old value and sets the flag to 1

type BotConfig

type BotConfig struct {
	Version     int   `json:"version"`
	LastVersion int   `json:"lastversion"`
	SetupDone   bool  `json:"setupdone"`
	Expires     int64 `json:"expires"`
	Basic       struct {
		IgnoreInvalidCommands bool                    `json:"ignoreinvalidcommands"`
		Importable            bool                    `json:"importable"`
		ModRole               DiscordRole             `json:"modrole"`
		ModChannel            DiscordChannel          `json:"modchannel"`
		FreeChannels          map[DiscordChannel]bool `json:"freechannels"`
		BotChannel            DiscordChannel          `json:"botchannel"`
		Aliases               map[string]string       `json:"aliases"`
		ListenToBots          bool                    `json:"listentobots"`
		CommandPrefix         string                  `json:"commandprefix"`
		SilenceRole           DiscordRole             `json:"silencerole"`
		MemberRole            DiscordRole             `json:"memberrole"`
	} `json:"basic"`
	Modules struct {
		Channels           map[ModuleID]map[DiscordChannel]bool  `json:"modulechannels"`
		Disabled           map[ModuleID]bool                     `json:"moduledisabled"`
		CommandRoles       map[CommandID]map[DiscordRole]bool    `json:"commandroles"`
		CommandChannels    map[CommandID]map[DiscordChannel]bool `json:"commandchannels"`
		CommandLimits      map[CommandID]int64                   `json:"Commandlimits"`
		CommandDisabled    map[CommandID]bool                    `json:"commanddisabled"`
		CommandPerDuration int                                   `json:"commandperduration"`
		CommandMaxDuration int64                                 `json:"commandmaxduration"`
	} `json:"modules"`
	Spam struct {
		ImagePressure      float32                    `json:"imagepressure"`
		PingPressure       float32                    `json:"pingpressure"`
		LengthPressure     float32                    `json:"lengthpressure"`
		RepeatPressure     float32                    `json:"repeatpressure"`
		LinePressure       float32                    `json:"linepressure"`
		BasePressure       float32                    `json:"basepressure"`
		PressureDecay      float32                    `json:"pressuredecay"`
		MaxPressure        float32                    `json:"maxpressure"`
		MaxChannelPressure map[DiscordChannel]float32 `json:"maxchannelpressure"`
		MaxRemoveLookback  int                        `json:"MaxSpamRemoveLookback"`
		IgnoreRole         DiscordRole                `json:"ignorerole"`
		RaidTime           int64                      `json:"maxraidtime"`
		RaidSize           int                        `json:"raidsize"`
		RaidSilence        int                        `json:"raidsilence"`
		LockdownDuration   int                        `json:"lockdownduration"`
		SilenceTimeout     int64                      `json:"silencetimeout"`
	} `json:"spam"`
	Users struct {
		TimezoneLocation TimeLocation         `json:"timezonelocation"`
		WelcomeChannel   DiscordChannel       `json:"welcomechannel"`
		JailChannel      DiscordChannel       `json:"jailchannel"`
		WelcomeMessage   string               `json:"welcomemessage"`
		SilenceMessage   string               `json:"silencemessage"`
		Roles            map[DiscordRole]bool `json:"userroles"`
		NotifyChannel    DiscordChannel       `json:"joinchannel"`
		TrackUserLeft    bool                 `json:"trackuserleft"`
		NewUserRole      DiscordRole          `json:"newuserrole"`
		NewUserDuration  int64                `json:"newuserduration"`
	} `json:"users"`
	Bucket struct {
		MaxItems       int             `json:"maxbucket"`
		MaxItemLength  int             `json:"maxbucketlength"`
		MaxFightHP     int             `json:"maxfighthp"`
		MaxFightDamage int             `json:"maxfightdamage"`
		Items          map[string]bool `json:"items"`
	} `json:"bucket"`
	Markov struct {
		MaxPMlines     int  `json:"maxpmlines"`
		MaxLines       int  `json:"maxquotelines"`
		DefaultLines   int  `json:"defaultmarkovlines"`
		UseMemberNames bool `json:"usemembernames"`
	} `json:"markov"`
	Filter struct {
		Filters   map[string]map[string]bool         `json:"filters"`
		Channels  map[string]map[DiscordChannel]bool `json:"channels"`
		Responses map[string]string                  `json:"responses"`
		Templates map[string]string                  `json:"templates"`
		Pressure  map[string]float32                 `json:"pressure"`
	} `json:"filter"`
	Bored struct {
		Cooldown int64           `json:"maxbored"`
		Exponent float64         `json:"exponent"`
		Commands map[string]bool `json:"boredcommands"`
	}
	Information struct {
		Rules             map[int]string `json:"rules"`
		HideNegativeRules bool           `json:"hidenegativerules"`
	} `json:"help"`
	Log struct {
		Cooldown int64          `json:"maxerror"`
		Channel  DiscordChannel `json:"logchannel"`
	} `json:"log"`
	Witty struct {
		Responses map[string]string `json:"witty"`
		Cooldown  int64             `json:"maxwit"`
	} `json:"Wit"`
	Scheduler struct {
		BirthdayRole DiscordRole `json:"birthdayrole"`
	} `json:"scheduler"`
	Miscellaneous struct {
		MaxSearchResults int `json:"maxsearchresults"`
	} `json:"misc"`
	Status struct {
		Cooldown int             `json:"statusdelaytime"`
		Lines    map[string]bool `json:"lines"`
	} `json:"status"`
	Quote struct {
		Quotes map[DiscordUser][]string `json:"quotes"`
	} `json:"quote"`
	Counters struct {
		Map          map[string]int64  `json:"map"`
		Descriptions map[string]string `json:"counterdescriptions"`
	} `json:"counters"`
}

BotConfig lists all bot configuration options, grouped into structs

func DefaultConfig

func DefaultConfig() *BotConfig

DefaultConfig returns a default BotConfig struct. We can't define this as a variable because you can't initialize nested structs in a sane way in Go

func (*BotConfig) FillConfig

func (config *BotConfig) FillConfig()

FillConfig ensures root maps are not nil

func (*BotConfig) GetConfig

func (config *BotConfig) GetConfig(f reflect.Value, state *discordgo.State, guild string) (s []string)

func (*BotConfig) IsCommandDisabled

func (config *BotConfig) IsCommandDisabled(command Command) (str string)

IsCommandDisabled returns a string if a command is disabled

func (*BotConfig) IsModuleDisabled

func (config *BotConfig) IsModuleDisabled(module Module) string

IsModuleDisabled returns a string if a module is disabled

func (*BotConfig) SetConfig

func (config *BotConfig) SetConfig(info *GuildInfo, args []string, indices []int, message string) (string, bool)

SetConfig sets the given config option with the given value along with any extra parameters

type BotDB

type BotDB struct {
	Status AtomicBool
	// contains filtered or unexported fields
}

BotDB contains the database connection and all database Prepared statements exposed as functions

func (*BotDB) AddItem

func (db *BotDB) AddItem(item string) (uint64, error)

AddItem adds an item or just returns the ID if it already exists.

func (*BotDB) AddMember

func (db *BotDB) AddMember(id uint64, guild uint64, firstseen time.Time, nickname string)

AddMember adds or updates guild-specific user information

func (*BotDB) AddMessage

func (db *BotDB) AddMessage(id uint64, author *discordgo.User, message string, channel uint64, guild uint64)

AddMessage logs a message to the chatlog

func (*BotDB) AddSchedule

func (db *BotDB) AddSchedule(guild uint64, date time.Time, ty uint8, data string) error

AddSchedule adds an event to the schedule

func (*BotDB) AddScheduleRepeat

func (db *BotDB) AddScheduleRepeat(guild uint64, date time.Time, repeatinterval uint8, repeat int, ty uint8, data string) error

AddScheduleRepeat adds a repeating event to the schedule

func (*BotDB) AddTag

func (db *BotDB) AddTag(item uint64, tag uint64) error

AddTag adds a tag to an item

func (*BotDB) AddTranscript

func (db *BotDB) AddTranscript(season int, episode int, line int, speaker string, text string) error

AddTranscript is used to construct the markov chain

func (*BotDB) AddUser

func (db *BotDB) AddUser(id uint64, username string, discriminator int, isonline bool)

AddUser adds or updates user information

func (*BotDB) Audit

func (db *BotDB) Audit(ty uint8, user *discordgo.User, message string, guild uint64)

Audit logs an action to the audit log

func (*BotDB) CheckError

func (db *BotDB) CheckError(name string, err error) error

CheckError logs any unknown errors and pings the database to check if it's still there

func (*BotDB) CheckStatus

func (db *BotDB) CheckStatus() bool

CheckStatus checks if the database connection has been lost

func (*BotDB) Close

func (db *BotDB) Close()

Close destroys the database connection

func (*BotDB) CountItems

func (db *BotDB) CountItems(guild uint64) (uint64, error)

CountItems returns the number of unique items for a given server

func (*BotDB) CountNewUsers

func (db *BotDB) CountNewUsers(seconds int64, guild uint64) int

CountNewUsers returns a count of users joined in the given duration

func (*BotDB) CountTag

func (db *BotDB) CountTag(tag uint64) (uint64, error)

CountTag returns the number of items with the given tag

func (*BotDB) CreateTag

func (db *BotDB) CreateTag(tag string, guild uint64) error

CreateTag creates a new tag on the given server

func (*BotDB) DeleteSchedule

func (db *BotDB) DeleteSchedule(id uint64) error

DeleteSchedule deletes the event with the given ID regardless of it's repeat interval or activation time.

func (*BotDB) DeleteTag

func (db *BotDB) DeleteTag(tag string, guild uint64) error

DeleteTag delets a tag from the given server

func (*BotDB) FindEvent

func (db *BotDB) FindEvent(user string, guild uint64, ty uint8) *uint64

FindEvent finds an event in the schedule

func (*BotDB) FindGuildUsers

func (db *BotDB) FindGuildUsers(name string, maxresults uint64, offset uint64, guild uint64) []uint64

FindGuildUsers returns all users in a guild that could satisfy the given name.

func (*BotDB) FindTimeZone

func (db *BotDB) FindTimeZone(s string) []string

FindTimeZone returns all matching timezone locations

func (*BotDB) FindTimeZoneOffset

func (db *BotDB) FindTimeZoneOffset(s string, minutes int) []string

FindTimeZoneOffset finds all timezones with the given offset

func (*BotDB) FindUser

func (db *BotDB) FindUser(name string, discriminator int, maxresults uint64, offset uint64) []uint64

FindUser returns all users with the given name and discriminator (which should be only one but cache errors can happen)

func (*BotDB) GetAliases

func (db *BotDB) GetAliases(user uint64) []string

GetAliases returns all aliases for the given user

func (*BotDB) GetAuditRows

func (db *BotDB) GetAuditRows(start uint64, end uint64, user *uint64, search string, guild uint64) []PingContext

GetAuditRows returns rows from the audit log

func (*BotDB) GetCharacterQuote

func (db *BotDB) GetCharacterQuote(character string) Transcript

GetCharacterQuote gets a random character quote from the transcript

func (*BotDB) GetEvent

func (db *BotDB) GetEvent(guild uint64, id uint64) *ScheduleEvent

GetEvent gets the event data for the given ID

func (*BotDB) GetEvents

func (db *BotDB) GetEvents(guild uint64, maxnum int) []ScheduleEvent

GetEvents gets all events for a guild up to maxnum

func (*BotDB) GetEventsByType

func (db *BotDB) GetEventsByType(guild uint64, ty uint8, maxnum int) []ScheduleEvent

GetEventsByType gets all events for a given type

func (*BotDB) GetItem

func (db *BotDB) GetItem(item string) (uint64, error)

GetItem returns the ID of the item, if it exists

func (*BotDB) GetItemTags

func (db *BotDB) GetItemTags(item uint64, guild uint64) []string

GetItemTags returns all tags an item has on the given server

func (*BotDB) GetMember

func (db *BotDB) GetMember(id uint64, guild uint64) (*discordgo.Member, time.Time, *time.Time)

GetMember gets all information about a user for the given guild

func (*BotDB) GetNewcomers

func (db *BotDB) GetNewcomers(lookback int, guild uint64) []uint64

GetNewcomers returns any users that posted recently

func (*BotDB) GetNewestUsers

func (db *BotDB) GetNewestUsers(maxresults int, guild uint64) []struct {
	User      *discordgo.User
	FirstSeen time.Time
}

GetNewestUsers gets the last maxresults users to join the guild

func (*BotDB) GetNextEvent

func (db *BotDB) GetNextEvent(guild uint64, ty uint8) ScheduleEvent

GetNextEvent gets the next event of the given type

func (*BotDB) GetRandomQuote

func (db *BotDB) GetRandomQuote() Transcript

GetRandomQuote gets a random quote from the transcript

func (*BotDB) GetRecentUsers

func (db *BotDB) GetRecentUsers(since time.Time, guild uint64) []*discordgo.User

GetRecentUsers returns any users whose first message was sent after the given timestamp

func (*BotDB) GetReminders

func (db *BotDB) GetReminders(guild uint64, id string, maxnum int) []ScheduleEvent

GetReminders gets reminders for the given user

func (*BotDB) GetSchedule

func (db *BotDB) GetSchedule(guild uint64) []ScheduleEvent

GetSchedule gets all events for a guild

func (*BotDB) GetScheduleDate

func (db *BotDB) GetScheduleDate(guild uint64, ty uint8, data string) *time.Time

GetScheduleDate returns the date for the given event if it exists

func (*BotDB) GetSpeechQuote

func (db *BotDB) GetSpeechQuote() Transcript

GetSpeechQuote gets a random speech quote from the transcript

func (*BotDB) GetTableCounts

func (db *BotDB) GetTableCounts() string

GetTableCounts returns a debug dump count of the tables

func (*BotDB) GetTag

func (db *BotDB) GetTag(tag string, guild uint64) (uint64, error)

GetTag gets the tag ID for a tag name on the given server

func (*BotDB) GetTags

func (db *BotDB) GetTags(guild uint64) []struct {
	Name  string
	Count int
}

GetTags returns all tags on a server

func (*BotDB) GetTimeZone

func (db *BotDB) GetTimeZone(user uint64) *time.Location

GetTimeZone returns the evaluated timezone for the user

func (*BotDB) GetTranscript

func (db *BotDB) GetTranscript(season int, episode int, start int, end int) []Transcript

GetTranscript gets all lines that satisfy the query from the transcripts

func (*BotDB) GetUser

func (db *BotDB) GetUser(id uint64) (*discordgo.User, time.Time, *time.Location, *uint64)

GetUser gets the guild-independent information about a user (if it exists)

func (*BotDB) GetUserGuilds

func (db *BotDB) GetUserGuilds(user uint64) []uint64

GetUserGuilds returns all guilds a user is on

func (*BotDB) ImportTag

func (db *BotDB) ImportTag(srcTag uint64, destTag uint64) error

ImportTag imports a tag from one server to another

func (*BotDB) LoadStatements

func (db *BotDB) LoadStatements() error

LoadStatements loads all Prepared statements

func (*BotDB) Prepare

func (db *BotDB) Prepare(s string) (*sql.Stmt, error)

Prepare a sql statement and logs an error if it fails

func (*BotDB) RemoveAlias

func (db *BotDB) RemoveAlias(user uint64, alias string) error

RemoveAlias removes an alias from a user, if it exists.

func (*BotDB) RemoveGuild

func (db *BotDB) RemoveGuild(guild uint64) error

RemoveGuild removes the given guild from the database, if it exists

func (*BotDB) RemoveItem

func (db *BotDB) RemoveItem(item uint64, guild uint64) error

RemoveItem removes an item from all tags on the given server

func (*BotDB) RemoveMember

func (db *BotDB) RemoveMember(id uint64, guild uint64) error

RemoveMember removes a user from a guild

func (*BotDB) RemoveSchedule

func (db *BotDB) RemoveSchedule(id uint64) error

RemoveSchedule removes the event with the given ID and creates a new one after the repeat interval

func (*BotDB) RemoveTag

func (db *BotDB) RemoveTag(item uint64, tag uint64) error

RemoveTag removes a tag to an item

func (*BotDB) RemoveTranscript

func (db *BotDB) RemoveTranscript(season int, episode int, line int)

RemoveTranscript removes a line from the transcripts

func (*BotDB) SawUser

func (db *BotDB) SawUser(user uint64, username string) error

SawUser updates a user's lastseen time

func (*BotDB) SentMessage

func (db *BotDB) SentMessage(user uint64, guild uint64) error

SentMessage doesn't log a message, but sets a user's "firstseen" and "lastseen" values if necessary

func (*BotDB) SetDefaultServer

func (db *BotDB) SetDefaultServer(userID uint64, guild uint64) error

SetDefaultServer sets a users default guild

func (*BotDB) SetTimeZone

func (db *BotDB) SetTimeZone(user uint64, tz *time.Location) error

SetTimeZone sets a users timezone location

type BotInstance

type BotInstance struct {
	DG          *DiscordGoSession
	SelfID      string
	SelfAvatar  string
	SelfName    string
	AppID       uint64
	AppName     string
	Token       string `json:"token"`
	MainGuildID uint64 `json:"mainguildid"`
	IsUserMode  bool   `json:"runasuser"` // True if running as a user for some godawful reason
}

BotInstance represents an instance of the bot using a given token that still runs off the same database as all the other instances

type Command

type Command interface {
	Info() *CommandInfo
	Process([]string, *discordgo.Message, []int, *GuildInfo) (string, bool, *discordgo.MessageEmbed)
	Usage(*GuildInfo) *CommandUsage
}

Command is any command that is addressed to the bot, optionally restricted by role.

type CommandID

type CommandID string

type CommandInfo

type CommandInfo struct {
	Name              string
	Usage             string
	ServerIndependent bool
	Sensitive         bool
	Restricted        bool
	Silver            bool
	MainInstance      bool
}

CommandInfo defines the properties of a command

type CommandUsage

type CommandUsage struct {
	Desc   string
	Params []CommandUsageParam
}

CommandUsage defines the help parameters for a command

type CommandUsageParam

type CommandUsageParam struct {
	Name     string
	Desc     string
	Optional bool
	Variadic bool
}

CommandUsageParam describes a single parameter to a command

type ConfigModule

type ConfigModule struct {
}

ConfigModule manages the configuration file

func (*ConfigModule) Commands

func (w *ConfigModule) Commands() []Command

Commands in the module

func (*ConfigModule) Description

func (w *ConfigModule) Description(info *GuildInfo) string

Description of the module

func (*ConfigModule) Name

func (w *ConfigModule) Name() string

Name of the module

type DebugModule

type DebugModule struct {
	// contains filtered or unexported fields
}

DebugModule contains various debugging commands

func (*DebugModule) Commands

func (w *DebugModule) Commands() []Command

Commands in the module

func (*DebugModule) Description

func (w *DebugModule) Description(info *GuildInfo) string

Description of the module

func (*DebugModule) Name

func (w *DebugModule) Name() string

Name of the module

func (*DebugModule) OnTick

func (w *DebugModule) OnTick(info *GuildInfo, t time.Time)

OnTick event hook

type DiscordChannel

type DiscordChannel string

DiscordChannel stores a channel ID

func NewDiscordChannel

func NewDiscordChannel(i uint64) DiscordChannel

NewDiscordChannel constructs a new DiscordChannel from an integer

func ParseChannel

func ParseChannel(s string, guild *discordgo.Guild) (DiscordChannel, error)

ParseChannel resolves multiple different channel tagging formats

func (DiscordChannel) Convert

func (ch DiscordChannel) Convert() (i uint64)

Convert channel to integer

func (DiscordChannel) Display

func (ch DiscordChannel) Display() string

Display channel as a ping

func (DiscordChannel) Equals

func (ch DiscordChannel) Equals(s string) bool

Equals channel id

func (DiscordChannel) Show

func (ch DiscordChannel) Show(info *GuildInfo) string

Show channel name if available, or display ping

func (DiscordChannel) String

func (ch DiscordChannel) String() string

func (*DiscordChannel) UnmarshalJSON

func (ch *DiscordChannel) UnmarshalJSON(d []byte) error

UnmarshalJSON is a custom unmarshal function for JSON

type DiscordGoSession

type DiscordGoSession struct {
	discordgo.Session
}

DiscordGoSession overrides the discordgo session, allowing us to extend it and also lets us mock the base class methods for testing

func (*DiscordGoSession) BulkDeleteBypass

func (s *DiscordGoSession) BulkDeleteBypass(channelID string, messages []string) (err error)

BulkDeleteBypass deletes in batches of 99

func (*DiscordGoSession) ChangeBotName

func (s *DiscordGoSession) ChangeBotName(name string, avatarfile string) error

ChangeBotName changes the username and avatar of the bot

func (*DiscordGoSession) GetMember

func (s *DiscordGoSession) GetMember(userID DiscordUser, guildID string) (*discordgo.Member, error)

GetMember attempts to get a member from the guild by checking the state first before making the REST API call.

func (*DiscordGoSession) GetMemberCreate

func (s *DiscordGoSession) GetMemberCreate(u *discordgo.User, guildID string) *discordgo.Member

GetMemberCreate creates a member if they don't exist, so it is guaranteed to return a Member

func (*DiscordGoSession) RemoveRole

func (s *DiscordGoSession) RemoveRole(guildID string, userID DiscordUser, role DiscordRole) error

RemoveRole removes a role from the state and then sends a request to discord to remove it

func (*DiscordGoSession) ReplaceAllMentions

func (s *DiscordGoSession) ReplaceAllMentions(str string, db *BotDB, guildID string) string

ReplaceAllMentions replaces mentions with usernames

func (*DiscordGoSession) UserHasAnyRole

func (s *DiscordGoSession) UserHasAnyRole(user DiscordUser, guildID string, roles map[DiscordRole]bool) bool

UserHasAnyRole returns true if the user ID (as a string) has any of the role IDs given (as a map of strings)

func (*DiscordGoSession) UserPermissions

func (s *DiscordGoSession) UserPermissions(userID DiscordUser, guildID string) (int64, error)

UserPermissions gets all permissions for a user, ignoring channel specific overrides

type DiscordGuild

type DiscordGuild string

DiscordGuild stores a guild ID

func NewDiscordGuild

func NewDiscordGuild(i uint64) DiscordGuild

NewDiscordGuild constructs a new DiscordGuild from an integer

func (DiscordGuild) Convert

func (g DiscordGuild) Convert() (i uint64)

Convert guild to integer

func (DiscordGuild) Equals

func (g DiscordGuild) Equals(s string) bool

Equals guild id

func (DiscordGuild) String

func (g DiscordGuild) String() string

type DiscordRole

type DiscordRole string

DiscordRole stores a role ID

func NewDiscordRole

func NewDiscordRole(i uint64) DiscordRole

NewDiscordRole constructs a new DiscordRole from an integer

func ParseRole

func ParseRole(s string, guild *discordgo.Guild) (DiscordRole, error)

ParseRole resolves multiple different role tagging formats

func (DiscordRole) Convert

func (r DiscordRole) Convert() (i uint64)

Convert role to integer

func (DiscordRole) Display

func (r DiscordRole) Display() string

Display role as a ping

func (DiscordRole) Equals

func (r DiscordRole) Equals(s string) bool

Equals role id

func (DiscordRole) Show

func (r DiscordRole) Show(info *GuildInfo) string

Show role name if available, or display ping

func (DiscordRole) String

func (r DiscordRole) String() string

func (*DiscordRole) UnmarshalJSON

func (r *DiscordRole) UnmarshalJSON(d []byte) error

UnmarshalJSON is a custom unmarshal function for JSON

type DiscordUser

type DiscordUser string

DiscordUser stores a user ID

func NewDiscordUser

func NewDiscordUser(i uint64) DiscordUser

NewDiscordUser constructs a new DiscordUser from an integer

func ParseUser

func ParseUser(s string, info *GuildInfo) (DiscordUser, error)

ParseUser resolves multiple different user tagging formats

func (DiscordUser) Convert

func (u DiscordUser) Convert() (i uint64)

Convert user to integer

func (DiscordUser) Display

func (u DiscordUser) Display() string

Display user as a ping

func (DiscordUser) Equals

func (u DiscordUser) Equals(s string) bool

Equals user id

func (DiscordUser) String

func (u DiscordUser) String() string

type GuildInfo

type GuildInfo struct {
	ID      string // Cache the ID because it doesn't change
	Name    string // Cache the name to reduce locking
	OwnerID DiscordUser
	BotNick string     // If not empty, the nickname assigned to the bot in this server
	Silver  AtomicBool // Has paid features (always true if selfhosting)

	LastRaid int64 // Last time a raid was recorded by the spam module (or any other module that records raids)

	ConfigLock sync.RWMutex
	Config     BotConfig

	Modules []Module

	Bot *SweetieBot
	// contains filtered or unexported fields
}

GuildInfo Stores state information about a guild

func NewGuildInfo

func NewGuildInfo(sb *SweetieBot, g *discordgo.Guild) *GuildInfo

NewGuildInfo spawns a new GuildInfo object with a default configuration

func (*GuildInfo) AddCommand

func (info *GuildInfo) AddCommand(c Command, m Module)

AddCommand adds a command to the guild

func (*GuildInfo) ApplyTimezone

func (info *GuildInfo) ApplyTimezone(t time.Time, user DiscordUser) time.Time

ApplyTimezone transforms the given UTC time into local time for the given user

func (*GuildInfo) BulkDelete

func (info *GuildInfo) BulkDelete(channel *discordgo.Channel, messages []string) (err error)

BulkDelete Performs a bulk deletion in groups of 100

func (*GuildInfo) ChannelMessageDelete

func (info *GuildInfo) ChannelMessageDelete(channel *discordgo.Channel, messageID string) (err error)

ChannelMessageDelete checks the channel guildID before calling the real ChannelMessageDelete

func (*GuildInfo) ChannelPermissionSet

func (info *GuildInfo) ChannelPermissionSet(channel *discordgo.Channel, targetID string, targetType discordgo.PermissionOverwriteType, allow, deny int64) (err error)

ChannelPermissionSet check the channel guildID before calling the real ChannelPermissionSet

func (*GuildInfo) Clean

func (info *GuildInfo) Clean()

Clean out all commands or modules that no longer exist

func (*GuildInfo) FindChannelID

func (info *GuildInfo) FindChannelID(name string) string

FindChannelID returns the ID of the first channel in this guild with a matching name

func (*GuildInfo) FindUsername

func (info *GuildInfo) FindUsername(arg string) []uint64

FindUsername returns all possible matching IDs for the given username

func (*GuildInfo) FormatUsage

func (info *GuildInfo) FormatUsage(c Command, usage *CommandUsage) *discordgo.MessageEmbed

FormatUsage constructs a help string for the given command based on it's usage

func (*GuildInfo) GetBotName

func (info *GuildInfo) GetBotName() string

func (*GuildInfo) GetChannels

func (info *GuildInfo) GetChannels(command CommandID) string

GetChannels constructs a string describing the allowed channels a command can run on

func (*GuildInfo) GetGuild

func (info *GuildInfo) GetGuild() (*discordgo.Guild, error)

GetGuild returns the guild object associated with this info object

func (*GuildInfo) GetMemberName

func (info *GuildInfo) GetMemberName(m *discordgo.Member) string

GetMemberName gets either the nickname or username of a member

func (*GuildInfo) GetRoles

func (info *GuildInfo) GetRoles(command CommandID) string

GetRoles constructs a string describing the allowed roles for a command

func (*GuildInfo) GetTimezone

func (info *GuildInfo) GetTimezone(user DiscordUser) *time.Location

GetTimezone gets the time.Location of the given user, if it exists, otherwise returns time.UTC

func (*GuildInfo) GetUserName

func (info *GuildInfo) GetUserName(user DiscordUser) string

GetUserName returns a string representation of the user's name if possible, otherwise pings them.

func (*GuildInfo) IDsToUsernames

func (info *GuildInfo) IDsToUsernames(IDs []uint64, discriminator bool) []string

IDsToUsernames converts an array of integer IDs to an array of username strings

func (*GuildInfo) IsDebug

func (info *GuildInfo) IsDebug(channelID DiscordChannel) bool

IsDebug returns true if the channel is a debug channel

func (*GuildInfo) Log

func (info *GuildInfo) Log(args ...interface{})

Log the given arguments to the server and the command line

func (*GuildInfo) LogError

func (info *GuildInfo) LogError(msg string, err error)

LogError logs an error only if it exists

func (*GuildInfo) MigrateSettings

func (guild *GuildInfo) MigrateSettings(config []byte) error

MigrateSettings from earlier config version

func (*GuildInfo) ParseCommonTime

func (info *GuildInfo) ParseCommonTime(s string, user DiscordUser, timestamp time.Time) (time.Time, error)

ParseCommonTime iterates through every single imaginable time format that we could possibly parse

func (*GuildInfo) ProcessMember

func (info *GuildInfo) ProcessMember(u *discordgo.Member)

ProcessMember called ProcessUser and adds additional member information to the database

func (*GuildInfo) ProcessMembers

func (info *GuildInfo) ProcessMembers(m []*discordgo.Member)

ProcessMembers adds a member list to the database

func (*GuildInfo) ProcessModule

func (info *GuildInfo) ProcessModule(channelID DiscordChannel, m Module) bool

ProcessModule returns true if a module should process events on this channel

func (*GuildInfo) RegisterModule

func (info *GuildInfo) RegisterModule(m Module)

RegisterModule registers a module with this guild

func (*GuildInfo) RequestPostWithBuffer

func (info *GuildInfo) RequestPostWithBuffer(urlStr string, data *discordgo.MessageSend, minRemaining int) (response []byte, err error)

RequestPostWithBuffer uses a buffer and a buffer combination function to combine multiple messages if there are fewer than minRequests requests left in the current bucket

func (*GuildInfo) ResolveRoleAddError

func (info *GuildInfo) ResolveRoleAddError(err error) error

func (*GuildInfo) Sanitize

func (info *GuildInfo) Sanitize(s string, flags int) string

Sanitize the input string according to flags

func (*GuildInfo) SaveConfig

func (info *GuildInfo) SaveConfig() (err error)

SaveConfig saves the config file to disk

func (*GuildInfo) SendEmbed

func (info *GuildInfo) SendEmbed(channelID DiscordChannel, embed *discordgo.MessageEmbed) error

SendEmbed sends an embed message to the channel, splitting it into multiple messages if necessary

func (*GuildInfo) SendError

func (info *GuildInfo) SendError(channelID DiscordChannel, message string, t int64)

SendError prints an error message with a saturation limit

func (*GuildInfo) SendMessage

func (info *GuildInfo) SendMessage(channelID DiscordChannel, message string) error

SendMessage sends a message to the given channel, splitting it into multiple messages if necessary, and combining smaller messages if a rate limit is about to be hit

func (*GuildInfo) UserCanUseCommand

func (info *GuildInfo) UserCanUseCommand(userID DiscordUser, command Command, ignore bool) (bypass bool, err error)

UserCanUseCommand returns nil if the user can use the command, or an error explaining why they can't. The boolean marks whether or not they bypass restrictions. Note that even moderators cannot use exclusive commands, only the owner of the bot can.

func (*GuildInfo) UserHasRole

func (info *GuildInfo) UserHasRole(userID DiscordUser, role DiscordRole) bool

UserHasRole returns true if the specified user ID has the given role ID (both in strings)

func (*GuildInfo) UserIsAdmin

func (info *GuildInfo) UserIsAdmin(userID DiscordUser) bool

UserIsAdmin returns true if the user is an admin or the owner of the bot. Always prefers returning false if any kind of error happens.

func (*GuildInfo) UserIsMod

func (info *GuildInfo) UserIsMod(userID DiscordUser) bool

UserIsMod returns true if the user is a mod

type InfoModule

type InfoModule struct {
}

InfoModule contains help and about commands

func (*InfoModule) Commands

func (w *InfoModule) Commands() []Command

Commands in the module

func (*InfoModule) Description

func (w *InfoModule) Description(info *GuildInfo) string

Description of the module

func (*InfoModule) Name

func (w *InfoModule) Name() string

Name of the module

type Module

type Module interface {
	Name() string
	Commands() []Command
	Description(*GuildInfo) string
}

Module monitors all incoming requests depending on what module interfaces they implement

type ModuleID

type ModuleID string

type ModuleOnCommand

type ModuleOnCommand interface {
	Module
	OnCommand(*GuildInfo, *discordgo.Message) bool
}

ModuleOnCommand hook interface

type ModuleOnEvent

type ModuleOnEvent interface {
	Module
	OnEvent(*GuildInfo, *discordgo.Event)
}

ModuleOnEvent hook interface

type ModuleOnGuildBanAdd

type ModuleOnGuildBanAdd interface {
	Module
	OnGuildBanAdd(*GuildInfo, *discordgo.GuildBanAdd)
}

ModuleOnGuildBanAdd hook interface

type ModuleOnGuildBanRemove

type ModuleOnGuildBanRemove interface {
	Module
	OnGuildBanRemove(*GuildInfo, *discordgo.GuildBanRemove)
}

ModuleOnGuildBanRemove hook interface

type ModuleOnGuildMemberAdd

type ModuleOnGuildMemberAdd interface {
	Module
	OnGuildMemberAdd(*GuildInfo, *discordgo.Member, time.Time)
}

ModuleOnGuildMemberAdd hook interface

type ModuleOnGuildMemberRemove

type ModuleOnGuildMemberRemove interface {
	Module
	OnGuildMemberRemove(*GuildInfo, *discordgo.Member, time.Time)
}

ModuleOnGuildMemberRemove hook interface

type ModuleOnGuildMemberUpdate

type ModuleOnGuildMemberUpdate interface {
	Module
	OnGuildMemberUpdate(*GuildInfo, *discordgo.Member, time.Time)
}

ModuleOnGuildMemberUpdate hook interface

type ModuleOnGuildRoleDelete

type ModuleOnGuildRoleDelete interface {
	Module
	OnGuildRoleDelete(*GuildInfo, *discordgo.GuildRoleDelete)
}

ModuleOnGuildRoleDelete hook interface

type ModuleOnGuildUpdate

type ModuleOnGuildUpdate interface {
	Module
	OnGuildUpdate(*GuildInfo, *discordgo.Guild)
}

ModuleOnGuildUpdate hook interface

type ModuleOnMessageCreate

type ModuleOnMessageCreate interface {
	Module
	OnMessageCreate(*GuildInfo, *discordgo.Message)
}

ModuleOnMessageCreate hook interface

type ModuleOnMessageDelete

type ModuleOnMessageDelete interface {
	Module
	OnMessageDelete(*GuildInfo, *discordgo.Message)
}

ModuleOnMessageDelete hook interface

type ModuleOnMessageUpdate

type ModuleOnMessageUpdate interface {
	Module
	OnMessageUpdate(*GuildInfo, *discordgo.Message)
}

ModuleOnMessageUpdate hook interface

type ModuleOnTick

type ModuleOnTick interface {
	Module
	OnTick(*GuildInfo, time.Time)
}

ModuleOnTick hook interface

type ModuleOnVoiceStateUpdate

type ModuleOnVoiceStateUpdate interface {
	Module
	OnVoiceStateUpdate(*GuildInfo, *discordgo.VoiceState)
}

ModuleOnVoiceStateUpdate hook interface

type PingContext

type PingContext struct {
	Author    string
	Message   string
	Timestamp time.Time
}

PingContext contains a simplified context for a message

type SaturationLimit

type SaturationLimit struct {
	// contains filtered or unexported fields
}

SaturationLimit tracks when events occurred and implements a saturation limit on them

type ScheduleEvent

type ScheduleEvent struct {
	ID   uint64
	Date time.Time
	Type uint8
	Data string
}

ScheduleEvent describes an event in the schedule

type Selfhost

type Selfhost struct {
	SelfhostBase

	Donors sync.Map //map[DiscordUser]bool
	// contains filtered or unexported fields
}

Selfhost stores selfhost update state

type SelfhostBase

type SelfhostBase struct {
	Version int
}

func (*SelfhostBase) CheckDonor

func (b *SelfhostBase) CheckDonor(m *discordgo.Member) bool

CheckDonor always returns false because donor status never changes when selfhosting

func (*SelfhostBase) CheckForUpdate

func (b *SelfhostBase) CheckForUpdate(userID DiscordUser, oldversion int) (int8, *UpdateStatus)

CheckForUpdate returns 0 if no update is needed, -1 if you haven't bought selfhosting, and 1 plus a list of files that are needed if oldversion is nonzero.

func (*SelfhostBase) CheckGuilds

func (b *SelfhostBase) CheckGuilds(guilds map[DiscordGuild]*GuildInfo)

CheckGuilds sets all guilds as silver unless there's more than 30

func (*SelfhostBase) ConfigureMux

func (b *SelfhostBase) ConfigureMux(mux *http.ServeMux)

ConfigureMux has nothing to configure for selfhosters

func (*SelfhostBase) DoUpdate

func (b *SelfhostBase) DoUpdate(dbauth string, token string) error

DoUpdate is the function run by updater.exe to perform the actual update

func (*SelfhostBase) GetWebDir

func (b *SelfhostBase) GetWebDir() string

GetWebDir returns the directory where the website is

func (*SelfhostBase) SelfUpdate

func (b *SelfhostBase) SelfUpdate(ownerid DiscordUser) error

SelfUpdate is run by sweetie.exe to to get a new version of updater.exe

func (*SelfhostBase) UpgradeDatabase

func (b *SelfhostBase) UpgradeDatabase(scriptdir string, dbauth string) error

UpgradeDatabase does the database migration portion of the upgrade

type SweetieBot

type SweetieBot struct {
	DB    *BotDB
	DG    *DiscordGoSession
	Debug bool `json:"debug"`

	SelfID        DiscordUser
	SelfAvatar    string
	SelfName      string
	AppID         uint64
	AppName       string
	Owner         DiscordUser
	Token         string                          `json:"token"`
	DBAuth        string                          `json:"dbauth"`
	MainGuildID   DiscordGuild                    `json:"mainguildid"`
	DebugChannels map[DiscordGuild]DiscordChannel `json:"debugchannels"`

	Guilds          map[DiscordGuild]*GuildInfo
	GuildsLock      sync.RWMutex
	LastMessages    map[DiscordChannel]int64
	LastMessageLock sync.RWMutex
	MaxConfigSize   int    `json:"maxconfigsize"`
	MaxUniqueItems  uint64 `json:"maxuniqueitems"`
	StartTime       int64
	MessageCount    uint32 // 32-bit so we can do atomic ops on a 32-bit platform

	Selfhoster *Selfhost
	IsUserMode bool       `json:"runasuser"` // True if running as a user for some godawful reason
	WebSecure  bool       `json:"websecure"`
	WebDomain  string     `json:"webdomain"`
	WebPort    string     `json:"webport"`
	EmptyGuild *GuildInfo // Holds an empty GuildInfo for running server independent commands
	UpdateLock AtomicFlag
	Markov     *markovChain
	// contains filtered or unexported fields
}

SweetieBot is the primary bot object containing the bot state

func New

func New(token string, loader func(*GuildInfo) []Module) *SweetieBot

New creates and initializes a new instance of Sweetiebot that's ready to connect. Returns nil on error.

func (*SweetieBot) AttachToGuild

func (sb *SweetieBot) AttachToGuild(g *discordgo.Guild)

AttachToGuild adds a guild to sweetiebot's state tracking

func (*SweetieBot) ChannelCreate

func (sb *SweetieBot) ChannelCreate(s *discordgo.Session, c *discordgo.ChannelCreate)

ChannelCreate discord hook

func (*SweetieBot) ChannelIsPrivate

func (sb *SweetieBot) ChannelIsPrivate(channelID DiscordChannel) (*discordgo.Channel, bool)

ChannelIsPrivate returns true if channel should be considered private, false otherwise.

func (*SweetieBot) Connect

func (sb *SweetieBot) Connect() int

Connect opens a websocket connection to discord. Only returns after disconnecting.

func (*SweetieBot) FindServers

func (sb *SweetieBot) FindServers(name string, guilds []uint64) []*GuildInfo

FindServers matches server names against a string

func (*SweetieBot) GetDefaultServer

func (sb *SweetieBot) GetDefaultServer(user uint64) *GuildInfo

GetDefaultServer attempts to find the default server for a user

func (*SweetieBot) GetLastMessage

func (sb *SweetieBot) GetLastMessage(id DiscordChannel) (int64, bool)

func (*SweetieBot) GuildBanAdd

func (sb *SweetieBot) GuildBanAdd(s *discordgo.Session, m *discordgo.GuildBanAdd)

GuildBanAdd discord hook

func (*SweetieBot) GuildBanRemove

func (sb *SweetieBot) GuildBanRemove(s *discordgo.Session, m *discordgo.GuildBanRemove)

GuildBanRemove discord hook

func (*SweetieBot) GuildCreate

func (sb *SweetieBot) GuildCreate(s *discordgo.Session, m *discordgo.GuildCreate)

GuildCreate discord hook

func (*SweetieBot) GuildDelete

func (sb *SweetieBot) GuildDelete(s *discordgo.Session, m *discordgo.GuildDelete)

GuildDelete discord hook

func (*SweetieBot) GuildMemberAdd

func (sb *SweetieBot) GuildMemberAdd(s *discordgo.Session, m *discordgo.GuildMemberAdd)

GuildMemberAdd discord hook

func (*SweetieBot) GuildMemberRemove

func (sb *SweetieBot) GuildMemberRemove(s *discordgo.Session, m *discordgo.GuildMemberRemove)

GuildMemberRemove discord hook

func (*SweetieBot) GuildMemberUpdate

func (sb *SweetieBot) GuildMemberUpdate(s *discordgo.Session, m *discordgo.GuildMemberUpdate)

GuildMemberUpdate discord hook

func (*SweetieBot) GuildMembersChunk

func (sb *SweetieBot) GuildMembersChunk(s *discordgo.Session, chunk *discordgo.GuildMembersChunk)

func (*SweetieBot) GuildRoleDelete

func (sb *SweetieBot) GuildRoleDelete(s *discordgo.Session, m *discordgo.GuildRoleDelete)

GuildRoleDelete discord hook

func (*SweetieBot) GuildUpdate

func (sb *SweetieBot) GuildUpdate(s *discordgo.Session, m *discordgo.GuildUpdate)

GuildUpdate discord hook

func (*SweetieBot) IsMainGuild

func (sb *SweetieBot) IsMainGuild(info *GuildInfo) bool

IsMainGuild returns true if that guild is considered the main (default) guild

func (*SweetieBot) MessageCreate

func (sb *SweetieBot) MessageCreate(s *discordgo.Session, m *discordgo.MessageCreate)

MessageCreate discord hook

func (*SweetieBot) MessageDelete

func (sb *SweetieBot) MessageDelete(s *discordgo.Session, m *discordgo.MessageDelete)

MessageDelete discord hook

func (*SweetieBot) MessageUpdate

func (sb *SweetieBot) MessageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate)

MessageUpdate discord hook

func (*SweetieBot) OnReady

func (sb *SweetieBot) OnReady(s *discordgo.Session, r *discordgo.Ready)

OnReady discord hook

func (*SweetieBot) ProcessCommand

func (sb *SweetieBot) ProcessCommand(m *discordgo.Message, info *GuildInfo, t int64, isdebug bool, private bool)

ProcessCommand processes a command given to sweetiebot in the form "!command"

func (*SweetieBot) ProcessUser

func (sb *SweetieBot) ProcessUser(u *discordgo.User) uint64

ProcessUser adds a user to the database

func (*SweetieBot) ServeWeb

func (sb *SweetieBot) ServeWeb() error

ServeWeb starts a webserver on :80 and optionally on :443. If you're doing a reverse-proxy via nginx, SSL terminates at nginx, so use insecure mode.

func (*SweetieBot) UserUpdate

func (sb *SweetieBot) UserUpdate(s *discordgo.Session, u *discordgo.UserUpdate)

UserUpdate discord hook

type TimeLocation

type TimeLocation string

type Transcript

type Transcript struct {
	Season  uint
	Episode uint
	Line    uint
	Speaker string
	Text    string
}

Transcript describes a single line from the transcript

type UpdateStatus

type UpdateStatus struct {
	Version int      `json:"version"`
	Files   []string `json:"files"`
}

UpdateStatus stores the version and additional files to download

type Version

type Version struct {
	// contains filtered or unexported fields
}

Version represents an app version using four sections

func VersionInt

func VersionInt(k int) Version

VersionInt constructs Version object from an integer

func (Version) Integer

func (v Version) Integer() int

Integer gets the integer representation of the version

func (Version) String

func (v Version) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL