build: | |||||
image: latest | |||||
python: | |||||
version: 3.6 | |||||
requirements_file: requirements.txt |
# Sets up Logging | # Sets up Logging | ||||
logger = logging.getLogger('discord') | logger = logging.getLogger('discord') | ||||
logger.setLevel(logging.INFO) | logger.setLevel(logging.INFO) | ||||
handler = logging.FileHandler(filename='roxbot.log', encoding='utf-8', mode='w') | |||||
handler = logging.FileHandler(filename='roxbot.log', encoding='utf-8', mode='a') | |||||
handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) | handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s:%(name)s: %(message)s')) | ||||
logger.addHandler(handler) | logger.addHandler(handler) | ||||
bot.load_extension("roxbot.core") | bot.load_extension("roxbot.core") | ||||
print("core.py Loaded") | print("core.py Loaded") | ||||
bot.load_extension("roxbot.err_handle") | |||||
print("err_handle.py Loaded") | |||||
bot.load_extension("roxbot.logging") | |||||
print("logging.py Loaded") | |||||
print("") | print("") | ||||
print("Discord.py version: " + discord.__version__) | print("Discord.py version: " + discord.__version__) | ||||
print("Client logged in\n") | print("Client logged in\n") |
from roxbot import checks, http, guild_settings, converters, utils, roxbotfacts | from roxbot import checks, http, guild_settings, converters, utils, roxbotfacts | ||||
from roxbot.exceptions import * | from roxbot.exceptions import * | ||||
from roxbot.enums import EmbedColours | from roxbot.enums import EmbedColours | ||||
from roxbot.logging import log | |||||
from roxbot.utils import blacklisted | |||||
from roxbot.utils import blacklisted, log | |||||
import configparser | import configparser | ||||
dev_mode = False | dev_mode = False | ||||
settings = configparser.ConfigParser() | |||||
settings.read("roxbot/settings/preferences.ini") | |||||
config = configparser.ConfigParser() | |||||
config.read("roxbot/settings/preferences.ini") | |||||
command_prefix = settings["Roxbot"]["Command_Prefix"] | |||||
owner = int(settings["Roxbot"]["OwnerID"]) | |||||
command_prefix = config["Roxbot"]["Command_Prefix"] | |||||
owner = int(config["Roxbot"]["OwnerID"]) | |||||
token = settings["Tokens"]["Discord"] | |||||
tat_token = settings["Tokens"]["Tatsumaki"] | |||||
imgur_token = settings["Tokens"]["Imgur"] | |||||
token = config["Tokens"]["Discord"] | |||||
imgur_token = config["Tokens"]["Imgur"] | |||||
__description__ = """RoxBot, A Discord Bot made by a filthy Mercy Main. Built with love (and discord.py) by Roxxers#7443. | __description__ = """RoxBot, A Discord Bot made by a filthy Mercy Main. Built with love (and discord.py) by Roxxers#7443. | ||||
[Found a bug or need to report an issue? Report it here](https://gitlab.roxxers.xyz/roxxers/roxbot/issues/new?issue) | [Found a bug or need to report an issue? Report it here](https://gitlab.roxxers.xyz/roxxers/roxbot/issues/new?issue) | ||||
[Say Thanks](https://saythanks.io/to/Roxxers)""" | [Say Thanks](https://saythanks.io/to/Roxxers)""" | ||||
__author__ = "Roxanne Gibson" | __author__ = "Roxanne Gibson" | ||||
__version__ = "2.0.0a" | |||||
__version__ = "2.0.0" | |||||
datetime_formatting = "{:%a %Y/%m/%d %H:%M:%S} UTC" | datetime_formatting = "{:%a %Y/%m/%d %H:%M:%S} UTC" | ||||
selfieperms = 394939389823811584 | selfieperms = 394939389823811584 | ||||
nsfwimageperms = 394941004043649036 | nsfwimageperms = 394941004043649036 | ||||
newbie = 450042170112475136 | newbie = 450042170112475136 | ||||
tat_token = roxbot.config["Tokens"]["Tatsumaki"] | |||||
def is_ags(): | def is_ags(): | ||||
async def tatsumaki_api_call(member, guild): | async def tatsumaki_api_call(member, guild): | ||||
base = "https://api.tatsumaki.xyz/" | base = "https://api.tatsumaki.xyz/" | ||||
url = base + "guilds/" + str(guild.id) + "/members/" + str(member.id) + "/stats" | url = base + "guilds/" + str(guild.id) + "/members/" + str(member.id) + "/stats" | ||||
return await roxbot.http.api_request(url, headers={"Authorization": roxbot.tat_token}) | |||||
return await roxbot.http.api_request(url, headers={"Authorization": tat_token}) | |||||
class AsortedGenderSounds: | class AsortedGenderSounds: |
import os | import os | ||||
import string | |||||
import typing | |||||
import logging | |||||
import asyncio | import asyncio | ||||
import datetime | import datetime | ||||
import youtube_dl | |||||
import roxbot | import roxbot | ||||
from discord.ext import commands | from discord.ext import commands | ||||
class Core: | |||||
"""Cog for commands that change the bot account and bot running.""" | |||||
class ErrorHandling: | |||||
COMMANDNOTFOUND = "That Command doesn't exist." | |||||
COMMANDONCOOLDOWN = "This command is on cooldown, please wait {:.2f} seconds before trying again." | |||||
CHECKFAILURE = "You do not have permission to do this. Back off, thot!" | |||||
TOOMANYARGS = "Too many arguments given." | |||||
DISABLEDCOMMAND = "This command is disabled." | |||||
COGSETTINGDISABLED = "{} is disabled on this server." | |||||
NODMS = "This command cannot be used in private messages." | |||||
YTDLDOWNLOADERROR = "Video could not be downloaded: {}" | |||||
def __init__(self, bot_client): | |||||
self.bot = bot_client | |||||
self.dev = roxbot.dev_mode | |||||
async def on_command_error(self, ctx, error): | |||||
if self.dev: | |||||
raise error | |||||
else: | |||||
# UserError warning section | |||||
user_errors = (commands.MissingRequiredArgument, commands.BadArgument, | |||||
commands.TooManyArguments, roxbot.UserError) | |||||
if isinstance(error, user_errors): | |||||
embed = discord.Embed(colour=roxbot.EmbedColours.orange) | |||||
if isinstance(error, (commands.MissingRequiredArgument, commands.BadArgument, roxbot.UserError)): | |||||
embed.description = error.args[0] | |||||
elif isinstance(error, commands.TooManyArguments): | |||||
embed.description = self.TOOMANYARGS | |||||
return await ctx.send(embed=embed) | |||||
# ActualErrorHandling | |||||
embed = discord.Embed() | |||||
if isinstance(error, commands.NoPrivateMessage): | |||||
embed.description = self.NODMS | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.DisabledCommand): | |||||
embed.description = self.DISABLEDCOMMAND | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, roxbot.CogSettingDisabled): | |||||
embed.description = self.COGSETTINGDISABLED.format(error.args[0]) | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.CommandNotFound): | |||||
try: | |||||
# Sadly this is the only part that makes a cog not modular. I have tried my best though to make it usable without the cog. | |||||
cc = roxbot.guild_settings.get(ctx.guild)["custom_commands"] | |||||
is_custom_command = bool(ctx.invoked_with in cc["1"] or ctx.invoked_with in cc["2"]) | |||||
is_emoticon_face = bool(any(x in string.punctuation for x in ctx.message.content.strip(ctx.prefix)[0])) | |||||
is_too_short = bool(len(ctx.message.content) <= 2) | |||||
if is_custom_command or is_emoticon_face or is_too_short: | |||||
embed = None | |||||
else: | |||||
embed.description = self.COMMANDNOTFOUND | |||||
logging.INFO(embed.description) | |||||
except (KeyError, AttributeError): | |||||
# KeyError for cog missing, AttributeError if a command invoked via DM | |||||
embed.description = self.COMMANDNOTFOUND | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.BotMissingPermissions): | |||||
embed.description = "{}".format(error.args[0].replace("Bot", "Roxbot")) | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.MissingPermissions): | |||||
embed.description = "{}".format(error.args[0]) | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.CommandOnCooldown): | |||||
embed.description = self.COMMANDONCOOLDOWN.format(error.retry_after) | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, (commands.CheckFailure, commands.NotOwner)): | |||||
embed.description = self.CHECKFAILURE | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.CommandInvokeError): | |||||
# YOUTUBE_DL ERROR HANDLING | |||||
if isinstance(error.original, youtube_dl.utils.GeoRestrictedError): | |||||
embed.description = self.YTDLDOWNLOADERROR.format("Video is GeoRestricted.") | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error.original, youtube_dl.utils.DownloadError): | |||||
embed.description = self.YTDLDOWNLOADERROR.format(error.original.exc_info[1]) | |||||
logging.INFO(embed.description) | |||||
# Final catches for errors undocumented. | |||||
else: | |||||
logging.ERROR(str(error)) | |||||
embed = discord.Embed(title='Command Error', colour=roxbot.EmbedColours.dark_red) | |||||
embed.description = str(error) | |||||
embed.add_field(name='User', value=ctx.author) | |||||
embed.add_field(name='Message', value=ctx.message.content) | |||||
embed.timestamp = datetime.datetime.utcnow() | |||||
elif isinstance(error, commands.CommandError): | |||||
embed.description = "Error: {}".format(error.args[0]) | |||||
logging.ERROR(embed.description) | |||||
else: | |||||
logging.ERROR(str(error)) | |||||
if embed: | |||||
embed.colour = roxbot.EmbedColours.dark_red | |||||
await ctx.send(embed=embed) | |||||
class Logging: | |||||
"""Cog that deals with internal logging with Roxbot that is posted in Discord.""" | |||||
def __init__(self, bot_client): | |||||
self.bot = bot_client | |||||
self.settings = { | |||||
"logging": { | |||||
"enabled": 0, | |||||
"convert": {"enabled": "bool", "channel": "channel"}, | |||||
"channel": 0 | |||||
} | |||||
} | |||||
self.bot.add_listener(self.cleanup_logging_settings, "on_guild_channel_delete") | |||||
self.bot.add_listener(self.log_member_join, "on_member_join") | |||||
self.bot.add_listener(self.log_member_remove, "on_member_remove") | |||||
@staticmethod | |||||
async def cleanup_logging_settings(channel): | |||||
"""Cleans up settings on removal of stored IDs.""" | |||||
settings = roxbot.guild_settings.get(channel.guild) | |||||
r_logging = settings["logging"] | |||||
if channel.id == r_logging["channel"]: | |||||
r_logging["channel"] = 0 | |||||
settings.update(r_logging, "logging") | |||||
async def log_member_join(self, member): | |||||
r_logging = roxbot.guild_settings.get(member.guild)["logging"] | |||||
if r_logging["enabled"]: | |||||
channel = self.bot.get_channel(r_logging["channel"]) | |||||
embed = discord.Embed(title="{} joined the server".format(member), colour=roxbot.EmbedColours.pink) | |||||
embed.add_field(name="ID", value=member.id) | |||||
embed.add_field(name="Mention", value=member.mention) | |||||
embed.add_field(name="Date Account Created", value=roxbot.datetime_formatting.format(member.created_at)) | |||||
embed.add_field(name="Date Joined", value=roxbot.datetime_formatting.format(member.joined_at)) | |||||
embed.set_thumbnail(url=member.avatar_url) | |||||
return await channel.send(embed=embed) | |||||
async def log_member_remove(self, member): | |||||
# TODO: Add some way of detecting whether a user left/was kicked or was banned. | |||||
r_logging = roxbot.guild_settings.get(member.guild)["logging"] | |||||
if r_logging["enabled"]: | |||||
channel = self.bot.get_channel(r_logging["channel"]) | |||||
embed = discord.Embed(description="{} left the server".format(member), colour=roxbot.EmbedColours.pink) | |||||
return await channel.send(embed=embed) | |||||
@commands.has_permissions(manage_channels=True) | |||||
@commands.guild_only() | |||||
@commands.command(aliases=["log"]) | |||||
async def logging(self, ctx, setting, *, channel: typing.Optional[discord.TextChannel] = None): | |||||
"""Edits the logging settings. | |||||
Options: | |||||
enable/disable: Enable/disables logging. | |||||
channel: sets the channel. | |||||
""" | |||||
setting = setting.lower() | |||||
settings = roxbot.guild_settings.get(ctx.guild) | |||||
if setting == "enable": | |||||
settings["logging"]["enabled"] = 1 | |||||
await ctx.send("'logging' was enabled!") | |||||
elif setting == "disable": | |||||
settings["logging"]["enabled"] = 0 | |||||
await ctx.send("'logging' was disabled :cry:") | |||||
elif setting == "channel": | |||||
if not channel: | |||||
channel = ctx.channel | |||||
settings["logging"]["channel"] = channel.id | |||||
await ctx.send("{} has been set as the logging channel!".format(channel.mention)) | |||||
else: | |||||
return await ctx.send("No valid option given.") | |||||
return settings.update(settings["logging"], "logging") | |||||
class Core(ErrorHandling, Logging): | |||||
"""Core bot cog. Includes management commands, logging, error handling, and backups.""" | |||||
def __init__(self, bot_client): | def __init__(self, bot_client): | ||||
self.bot = bot_client | self.bot = bot_client | ||||
super().__init__(self.bot) | |||||
# Backup setup | |||||
self.backup_task = self.bot.loop.create_task(self.auto_backups()) | self.backup_task = self.bot.loop.create_task(self.auto_backups()) | ||||
############# | |||||
# Backups # | |||||
############# | |||||
async def auto_backups(self): | async def auto_backups(self): | ||||
await self.bot.wait_until_ready() | await self.bot.wait_until_ready() | ||||
raw_settings = {} | raw_settings = {} | ||||
for guild in self.bot.guilds: | for guild in self.bot.guilds: | ||||
raw_settings = {**raw_settings, **roxbot.guild_settings._open_config(guild, os.listdir('roxbot/settings/servers/{}'.format(guild.id)))} | |||||
directory = os.listdir('roxbot/settings/servers/{}'.format(guild.id)) | |||||
raw_settings = {**raw_settings, **roxbot.guild_settings._open_config(guild, directory)} | |||||
while not self.bot.is_closed(): | while not self.bot.is_closed(): | ||||
current_settings = {} | current_settings = {} | ||||
for guild in self.bot.guilds: | for guild in self.bot.guilds: | ||||
current_settings = {**current_settings, **roxbot.guild_settings._open_config(guild, os.listdir('roxbot/settings/servers/{}'.format(guild.id)))} | |||||
directory = os.listdir('roxbot/settings/servers/{}'.format(guild.id)) | |||||
current_settings = {**current_settings, **roxbot.guild_settings._open_config(guild, directory)} | |||||
if raw_settings != current_settings: | if raw_settings != current_settings: | ||||
raw_settings = current_settings | raw_settings = current_settings | ||||
time = datetime.datetime.now() | time = datetime.datetime.now() | ||||
roxbot.guild_settings.backup(filename) | roxbot.guild_settings.backup(filename) | ||||
return await ctx.send("Settings file backed up as a folder named '{}".format(filename)) | return await ctx.send("Settings file backed up as a folder named '{}".format(filename)) | ||||
############################ | |||||
# Bot Managment Commands # | |||||
############################ | |||||
@commands.command() | @commands.command() | ||||
@commands.is_owner() | @commands.is_owner() | ||||
async def blacklist(self, ctx, option): | async def blacklist(self, ctx, option): |
# -*- coding: utf-8 -*- | |||||
# MIT License | |||||
# | |||||
# Copyright (c) 2017-2018 Roxanne Gibson | |||||
# | |||||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
# of this software and associated documentation files (the "Software"), to deal | |||||
# in the Software without restriction, including without limitation the rights | |||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
# copies of the Software, and to permit persons to whom the Software is | |||||
# furnished to do so, subject to the following conditions: | |||||
# | |||||
# The above copyright notice and this permission notice shall be included in all | |||||
# copies or substantial portions of the Software. | |||||
# | |||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
# SOFTWARE. | |||||
import string | |||||
import logging | |||||
import datetime | |||||
import youtube_dl | |||||
import discord | |||||
from discord.ext import commands | |||||
import roxbot | |||||
from roxbot import guild_settings | |||||
class ErrHandle: | |||||
COMMANDNOTFOUND = "That Command doesn't exist." | |||||
COMMANDONCOOLDOWN = "This command is on cooldown, please wait {:.2f} seconds before trying again." | |||||
CHECKFAILURE = "You do not have permission to do this. Back off, thot!" | |||||
TOOMANYARGS = "Too many arguments given." | |||||
DISABLEDCOMMAND = "This command is disabled." | |||||
COGSETTINGDISABLED = "{} is disabled on this server." | |||||
NODMS = "This command cannot be used in private messages." | |||||
YTDLDOWNLOADERROR = "Video could not be downloaded: {}" | |||||
def __init__(self, bot_client): | |||||
self.bot = bot_client | |||||
self.dev = roxbot.dev_mode | |||||
async def on_command_error(self, ctx, error): | |||||
if self.dev: | |||||
raise error | |||||
else: | |||||
# UserError warning section | |||||
user_errors = (commands.MissingRequiredArgument, commands.BadArgument, | |||||
commands.TooManyArguments, roxbot.UserError) | |||||
if isinstance(error, user_errors): | |||||
embed = discord.Embed(colour=roxbot.EmbedColours.orange) | |||||
if isinstance(error, (commands.MissingRequiredArgument, commands.BadArgument, roxbot.UserError)): | |||||
embed.description = error.args[0] | |||||
elif isinstance(error, commands.TooManyArguments): | |||||
embed.description = self.TOOMANYARGS | |||||
return await ctx.send(embed=embed) | |||||
# ActualErrorHandling | |||||
embed = discord.Embed() | |||||
if isinstance(error, commands.NoPrivateMessage): | |||||
embed.description = self.NODMS | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.DisabledCommand): | |||||
embed.description = self.DISABLEDCOMMAND | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, roxbot.CogSettingDisabled): | |||||
embed.description = self.COGSETTINGDISABLED.format(error.args[0]) | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.CommandNotFound): | |||||
try: | |||||
# Sadly this is the only part that makes a cog not modular. I have tried my best though to make it usable without the cog. | |||||
cc = guild_settings.get(ctx.guild)["custom_commands"] | |||||
is_custom_command = bool(ctx.invoked_with in cc["1"] or ctx.invoked_with in cc["2"]) | |||||
is_emoticon_face = bool(any(x in string.punctuation for x in ctx.message.content.strip(ctx.prefix)[0])) | |||||
is_too_short = bool(len(ctx.message.content) <= 2) | |||||
if is_custom_command or is_emoticon_face or is_too_short: | |||||
embed = None | |||||
else: | |||||
embed.description = self.COMMANDNOTFOUND | |||||
logging.INFO(embed.description) | |||||
except (KeyError, AttributeError): | |||||
# KeyError for cog missing, AttributeError if a command invoked via DM | |||||
embed.description = self.COMMANDNOTFOUND | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.BotMissingPermissions): | |||||
embed.description = "{}".format(error.args[0].replace("Bot", "Roxbot")) | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.MissingPermissions): | |||||
embed.description = "{}".format(error.args[0]) | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.CommandOnCooldown): | |||||
embed.description = self.COMMANDONCOOLDOWN.format(error.retry_after) | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, (commands.CheckFailure, commands.NotOwner)): | |||||
embed.description = self.CHECKFAILURE | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error, commands.CommandInvokeError): | |||||
# YOUTUBE_DL ERROR HANDLING | |||||
if isinstance(error.original, youtube_dl.utils.GeoRestrictedError): | |||||
embed.description = self.YTDLDOWNLOADERROR.format("Video is GeoRestricted.") | |||||
logging.INFO(embed.description) | |||||
elif isinstance(error.original, youtube_dl.utils.DownloadError): | |||||
embed.description = self.YTDLDOWNLOADERROR.format(error.original.exc_info[1]) | |||||
logging.INFO(embed.description) | |||||
# Final catches for errors undocumented. | |||||
else: | |||||
logging.ERROR(str(error)) | |||||
embed = discord.Embed(title='Command Error', colour=roxbot.EmbedColours.dark_red) | |||||
embed.description = str(error) | |||||
embed.add_field(name='User', value=ctx.author) | |||||
embed.add_field(name='Message', value=ctx.message.content) | |||||
embed.timestamp = datetime.datetime.utcnow() | |||||
elif isinstance(error, commands.CommandError): | |||||
embed.description = "Error: {}".format(error.args[0]) | |||||
logging.ERROR(embed.description) | |||||
else: | |||||
logging.ERROR(str(error)) | |||||
if embed: | |||||
embed.colour = roxbot.EmbedColours.dark_red | |||||
await ctx.send(embed=embed) | |||||
def setup(bot_client): | |||||
bot_client.add_cog(ErrHandle(bot_client)) |
# -*- coding: utf-8 -*- | |||||
# MIT License | |||||
# | |||||
# Copyright (c) 2017-2018 Roxanne Gibson | |||||
# | |||||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
# of this software and associated documentation files (the "Software"), to deal | |||||
# in the Software without restriction, including without limitation the rights | |||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
# copies of the Software, and to permit persons to whom the Software is | |||||
# furnished to do so, subject to the following conditions: | |||||
# | |||||
# The above copyright notice and this permission notice shall be included in all | |||||
# copies or substantial portions of the Software. | |||||
# | |||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
# SOFTWARE. | |||||
import typing | |||||
import discord | |||||
from discord.ext import commands | |||||
import roxbot | |||||
from roxbot import guild_settings | |||||
async def log(guild, channel, command_name, **kwargs): | |||||
"""Logs activity internally for Roxbot. Will only do anything if the server enables internal logging. | |||||
This is mostly used for logging when certain commands are used that can be an issue for admins. Esp when Roxbot outputs | |||||
something that could break the rules, then deletes their message. | |||||
Params | |||||
======= | |||||
guild: discord.Guild | |||||
Used to check if the guild has logging enabled | |||||
channel: discord.TextChannel | |||||
command_name: str | |||||
kwargs: dict | |||||
All kwargs and two other params will be added to the logging embed as fields, allowing you to customise the output | |||||
""" | |||||
logging = guild_settings.get(guild)["logging"] | |||||
if logging["enabled"]: | |||||
embed = discord.Embed(title="{} command logging".format(command_name), colour=roxbot.EmbedColours.pink) | |||||
for key, value in kwargs.items(): | |||||
embed.add_field(name=key, value=value) | |||||
return await channel.send(embed=embed) | |||||
class Logging: | |||||
def __init__(self, bot_client): | |||||
self.bot = bot_client | |||||
self.settings = { | |||||
"logging": { | |||||
"enabled": 0, | |||||
"convert": {"enabled": "bool", "channel": "channel"}, | |||||
"channel": 0 | |||||
} | |||||
} | |||||
async def on_guild_channel_delete(self, channel): | |||||
"""Cleans up settings on removal of stored IDs.""" | |||||
settings = roxbot.guild_settings.get(channel.guild) | |||||
logging = settings["logging"] | |||||
if channel.id == logging["channel"]: | |||||
logging["channel"] = 0 | |||||
settings.update(logging, "logging") | |||||
async def on_member_join(self, member): | |||||
logging = guild_settings.get(member.guild)["logging"] | |||||
if logging["enabled"]: | |||||
channel = self.bot.get_channel(logging["channel"]) | |||||
embed = discord.Embed(title="{} joined the server".format(member), colour=roxbot.EmbedColours.pink) | |||||
embed.add_field(name="ID", value=member.id) | |||||
embed.add_field(name="Mention", value=member.mention) | |||||
embed.add_field(name="Date Account Created", value=roxbot.datetime_formatting.format(member.created_at)) | |||||
embed.add_field(name="Date Joined", value=roxbot.datetime_formatting.format(member.joined_at)) | |||||
embed.set_thumbnail(url=member.avatar_url) | |||||
return await channel.send(embed=embed) | |||||
async def on_member_remove(self, member): | |||||
# TODO: Add some way of detecting whether a user left/was kicked or was banned. | |||||
logging = guild_settings.get(member.guild)["logging"] | |||||
if logging["enabled"]: | |||||
channel = self.bot.get_channel(logging["channel"]) | |||||
embed = discord.Embed(description="{} left the server".format(member), colour=roxbot.EmbedColours.pink) | |||||
return await channel.send(embed=embed) | |||||
@commands.has_permissions(manage_channels=True) | |||||
@commands.guild_only() | |||||
@commands.command(aliases=["log"]) | |||||
async def logging(self, ctx, setting, *, channel: typing.Optional[discord.TextChannel] = None): | |||||
"""Edits the logging settings. | |||||
Options: | |||||
enable/disable: Enable/disables logging. | |||||
channel: sets the channel. | |||||
""" | |||||
setting = setting.lower() | |||||
settings = guild_settings.get(ctx.guild) | |||||
if setting == "enable": | |||||
settings["logging"]["enabled"] = 1 | |||||
await ctx.send("'logging' was enabled!") | |||||
elif setting == "disable": | |||||
settings["logging"]["enabled"] = 0 | |||||
await ctx.send("'logging' was disabled :cry:") | |||||
elif setting == "channel": | |||||
if not channel: | |||||
channel = ctx.channel | |||||
settings["logging"]["channel"] = channel.id | |||||
await ctx.send("{} has been set as the logging channel!".format(channel.mention)) | |||||
else: | |||||
return await ctx.send("No valid option given.") | |||||
return settings.update(settings["logging"], "logging") | |||||
def setup(bot_client): | |||||
bot_client.add_cog(Logging(bot_client)) |
Tatsumaki=TokenHere | Tatsumaki=TokenHere | ||||
[Backups] | [Backups] | ||||
; Settings for the servers.json backups. | |||||
; Settings for the server settings backups. | |||||
; This is the file that contains all settings for all servers the bot is in. | ; This is the file that contains all settings for all servers the bot is in. | ||||
; Explaintion: | ; Explaintion: | ||||
; enabled: Whether or not backups should be enabled. This is heavily recommened to be kept on. | ; enabled: Whether or not backups should be enabled. This is heavily recommened to be kept on. | ||||
; rate: The amount of time in seconds that the bot will check for changes in the settings file to backup. Default: 300 # 5 Minutes | |||||
; rate: The amount of time in minutes that the bot will check for changes in the settings file to backup. Default: 5 minutes | |||||
enabled=True | enabled=True | ||||
rate=300 | |||||
rate=5 |
import discord | import discord | ||||
import argparse | import argparse | ||||
from roxbot import guild_settings | |||||
from roxbot.enums import EmbedColours | |||||
class ArgParser(argparse.ArgumentParser): | class ArgParser(argparse.ArgumentParser): | ||||
"""Create Roxbot's own version of ArgumentParser that doesn't exit the program on error.""" | """Create Roxbot's own version of ArgumentParser that doesn't exit the program on error.""" | ||||
if str(user.id)+"\n" == line: | if str(user.id)+"\n" == line: | ||||
return True | return True | ||||
return False | return False | ||||
async def log(guild, channel, command_name, **kwargs): | |||||
"""Logs activity internally for Roxbot. Will only do anything if the server enables internal logging. | |||||
This is mostly used for logging when certain commands are used that can be an issue for admins. Esp when Roxbot outputs | |||||
something that could break the rules, then deletes their message. | |||||
Params | |||||
======= | |||||
guild: discord.Guild | |||||
Used to check if the guild has logging enabled | |||||
channel: discord.TextChannel | |||||
command_name: str | |||||
kwargs: dict | |||||
All kwargs and two other params will be added to the logging embed as fields, allowing you to customise the output | |||||
""" | |||||
logging = guild_settings.get(guild)["logging"] | |||||
if logging["enabled"]: | |||||
embed = discord.Embed(title="{} command logging".format(command_name), colour=EmbedColours.pink) | |||||
for key, value in kwargs.items(): | |||||
embed.add_field(name=key, value=value) | |||||
return await channel.send(embed=embed) |