@@ -5,7 +5,9 @@ | |||
- easy setup and get that wiki going | |||
### Big Changes | |||
- All settings have been decentralised between servers and cogs. All changes to the settings have been moved to independant commands. This doesn't effect custom commands or warnings. | |||
- All settings have been decentralised between servers and cogs. All changes to the settings have been moved to independant commands. This doesn't effect custom commands or warnings. | |||
- is_anal setting is now depreciated.`;suck` and `;spank` now only work in channels marked NSFW. | |||
- perm_roles setting is now depreciated. All commands will work of Discord's permission system. | |||
### Regular Updates | |||
#### New Features |
@@ -40,22 +40,6 @@ from roxbot import guild_settings as gs | |||
# REMEMBER TO UNCOMMENT THE GSS LINE, ROXIE | |||
# DO NOT UNCOMMENT GSS IF YOU ARE NOT ROXIE | |||
cogs = [ | |||
"roxbot.cogs.admin", | |||
"roxbot.cogs.customcommands", | |||
"roxbot.cogs.fun", | |||
"roxbot.cogs.image", | |||
"roxbot.cogs.joinleave", | |||
"roxbot.cogs.nsfw", | |||
"roxbot.cogs.reddit", | |||
"roxbot.cogs.selfassign", | |||
"roxbot.cogs.trivia", | |||
"roxbot.cogs.twitch", | |||
"roxbot.cogs.util", | |||
"roxbot.cogs.voice", | |||
#"roxbot.cogs.gss" | |||
] | |||
# Sets up Logging that discord.py does on its own | |||
logger = logging.getLogger('discord') | |||
@@ -81,9 +65,6 @@ async def on_ready(): | |||
bot.load_extension("roxbot.system") | |||
print("system.py Loaded") | |||
bot.load_extension("roxbot.settings.settings") | |||
print("settings.py Loaded") | |||
bot.load_extension("roxbot.err_handle") | |||
print("err_handle.py Loaded") | |||
@@ -96,7 +77,7 @@ async def on_ready(): | |||
# Load Extension Cogs | |||
print("Cogs Loaded:") | |||
for cog in cogs: | |||
for cog in roxbot.cogs: | |||
try: | |||
bot.load_extension(cog) | |||
print(cog.split(".")[2]) |
@@ -55,3 +55,19 @@ __author__ = "Roxanne Gibson" | |||
__version__ = "2.0.0a" | |||
datetime_formatting = "{:%a %Y/%m/%d %H:%M:%S} UTC" | |||
cogs = [ | |||
"roxbot.cogs.admin", | |||
"roxbot.cogs.customcommands", | |||
"roxbot.cogs.fun", | |||
"roxbot.cogs.image", | |||
"roxbot.cogs.joinleave", | |||
"roxbot.cogs.nsfw", | |||
"roxbot.cogs.reddit", | |||
"roxbot.cogs.selfassign", | |||
"roxbot.cogs.trivia", | |||
"roxbot.cogs.twitch", | |||
"roxbot.cogs.util", | |||
"roxbot.cogs.voice", | |||
#"roxbot.cogs.gss" | |||
] |
@@ -33,38 +33,15 @@ from roxbot import guild_settings as gs | |||
# TODO: Clean up this file. | |||
def is_owner_or_admin(): | |||
def has_permission_or_owner(**perms): | |||
def predicate(ctx): | |||
if ctx.author.id == roxbot.owner: | |||
return True | |||
elif isinstance(ctx.channel, discord.DMChannel): | |||
return False | |||
else: | |||
for role in ctx.author.roles: | |||
if role.id in gs.get(ctx.guild)["admin"]["admin_roles"]: | |||
return True | |||
return False | |||
return commands.has_permissions(**perms) | |||
return commands.check(predicate) | |||
def _is_admin_or_mod(ctx): | |||
if ctx.message.author.id == roxbot.owner: | |||
return True | |||
elif isinstance(ctx.channel, discord.DMChannel): | |||
return False | |||
else: | |||
admin_roles = gs.get(ctx.guild)["admin"]["admin_roles"] | |||
mod_roles = gs.get(ctx.guild)["admin"]["mod_roles"] | |||
for role in ctx.author.roles: | |||
if role.id in mod_roles or role.id in admin_roles: | |||
return True | |||
return False | |||
def is_admin_or_mod(): | |||
return commands.check(_is_admin_or_mod) | |||
def nsfw_predicate(ctx): | |||
if isinstance(ctx.channel, discord.DMChannel): | |||
return False | |||
@@ -79,15 +56,3 @@ def nsfw_predicate(ctx): | |||
def is_nfsw_enabled(): | |||
return commands.check(lambda ctx: nsfw_predicate(ctx)) | |||
def isnt_anal(): | |||
def predicate(ctx): | |||
if isinstance(ctx.channel, discord.DMChannel): | |||
return False | |||
anal = gs.get(ctx.guild)["admin"]["is_anal"] | |||
if not anal or (nsfw_predicate(ctx) and gs.get(ctx.guild).is_anal["y/n"]): | |||
return True | |||
else: | |||
return False | |||
return commands.check(predicate) |
@@ -78,16 +78,11 @@ class Admin: | |||
self.bot = bot_client | |||
self.settings = { | |||
"admin": { | |||
"convert": {"admin_roles": "role", "mod_roles": "role"}, | |||
"convert": {"warnings": "hide"}, | |||
"admin_roles": [], | |||
"mod_roles": [], | |||
"is_anal": 0, | |||
"warnings": {}, | |||
}, | |||
"logging": { | |||
"enabled": 0, | |||
"convert": {"enabled": "bool", "channel": "channel"}, | |||
"channel": 0 | |||
} | |||
} | |||
self.slow_mode = False | |||
@@ -115,11 +110,11 @@ class Admin: | |||
pass | |||
@commands.guild_only() | |||
@roxbot.checks.is_admin_or_mod() | |||
@commands.has_permissions(manage_messages=True) | |||
@commands.bot_has_permissions(manage_messages=True) | |||
@commands.command() | |||
async def slowmode(self, ctx, seconds): | |||
"""Puts the current channel in slowmode. | |||
"""Puts the current channel in slowmode. Requires the Manage Messages permission. | |||
Usage: | |||
;slowmode [time/"off"] | |||
seconds = number of seconds for the cooldown between messages a user has. | |||
@@ -148,7 +143,7 @@ class Admin: | |||
@commands.cooldown(1, 5) | |||
@commands.command() | |||
async def purge(self, ctx, limit=0, *, author: roxbot.converters.User=None): | |||
"""Purges messages from the text channel. | |||
"""Purges messages from the text channel. Requires the Manage Messages permission. | |||
Limit = Limit of messages to be deleted | |||
Author (optional) = If given, roxbot will selectively only delete this user's messages.""" | |||
# TODO: To sort out the limit == how many to delete for the author, and not just a limit. | |||
@@ -160,10 +155,10 @@ class Admin: | |||
return await ctx.send(self.OK_PURGE_CONFIRMATION.format(len(messages))) | |||
@commands.guild_only() | |||
@roxbot.checks.is_admin_or_mod() | |||
@commands.has_permissions(kick_members=True) | |||
@commands.group(case_insensitive=True) | |||
async def warn(self, ctx): | |||
"""Group of commands handling warnings""" | |||
"""Group of commands handling . Requires the Kick Members permission.""" | |||
if ctx.invoked_subcommand is None: | |||
return await ctx.send('Missing Argument') | |||
@@ -172,6 +167,7 @@ class Admin: | |||
"""Adds a warning to a user.""" | |||
# Warning in the settings is a dictionary of user ids. The user ids are equal to a list of dictionaries. | |||
settings = gs.get(ctx.guild) | |||
warnings = settings["admin"]["warnings"] | |||
warning_limit = 2 | |||
warning_dict = { | |||
"warned-by": ctx.author.id, | |||
@@ -180,17 +176,18 @@ class Admin: | |||
} | |||
user_id = str(user.id) | |||
if user_id not in settings.warnings: | |||
settings.warnings[user_id] = [] | |||
if user_id not in warnings: | |||
warnings[user_id] = [] | |||
warn_limit = 10 | |||
if len(settings.warnings[user_id]) > warn_limit: | |||
if len(warnings[user_id]) > warn_limit: | |||
return await ctx.send(self.WARN_WARN_ADD_LIMIT_REACHED.format(warn_limit)) | |||
settings.warnings[user_id].append(warning_dict) | |||
settings.update(settings.warnings, "warnings") | |||
warnings[user_id].append(warning_dict) | |||
settings["admin"]["warnings"] = warnings | |||
settings.update(settings["admin"], "admin") | |||
amount_warnings = len(settings.warnings[user_id]) | |||
amount_warnings = len(warnings[user_id]) | |||
if amount_warnings > warning_limit: | |||
await ctx.author.send(self.OK_WARN_ADD_USER_LIMIT_DM.format(str(user), amount_warnings, warning_limit)) | |||
@@ -200,19 +197,22 @@ class Admin: | |||
async def list(self, ctx, *, user: roxbot.converters.User=None): | |||
"""Lists all or just the warnings for one user.""" | |||
settings = gs.get(ctx.guild) | |||
warnings = settings["admin"]["warnings"] | |||
if user is None: | |||
paginator = commands.Paginator() | |||
for member in settings.warnings: | |||
for member in warnings: | |||
# Remove users with no warning here instead of remove cause im lazy | |||
if not settings.warnings[member]: | |||
settings.warnings.pop(member) | |||
if not warnings[member]: | |||
warnings.pop(member) | |||
else: | |||
member_obj = discord.utils.get(ctx.guild.members, id=int(member)) | |||
if member_obj: | |||
paginator.add_line("{}: {} Warning(s)".format(str(member_obj), len(settings.warnings[member]))) | |||
paginator.add_line("{}: {} Warning(s)".format(str(member_obj), len(warnings[member]))) | |||
else: | |||
paginator.add_line("{}: {} Warning(s)".format(member, len(settings.warnings[member]))) | |||
paginator.add_line("{}: {} Warning(s)".format(member, len(warnings[member]))) | |||
settings["admin"]["warnings"] = warnings | |||
settings.update(settings["admin"], "admin") | |||
if len(paginator.pages) <= 0: | |||
return await ctx.send(self.OK_WARN_LIST_NO_WARNINGS) | |||
for page in paginator.pages: | |||
@@ -220,18 +220,14 @@ class Admin: | |||
else: | |||
user_id = str(user.id) | |||
if not settings.warnings.get(user_id): | |||
if not warnings.get(user_id): | |||
return await ctx.send(self.OK_WARN_LIST_USER_NO_WARNINGS) | |||
if not settings.warnings[user_id]: | |||
settings.warnings.pop(user_id) | |||
settings.update(settings.warnings, "warnings") | |||
em = discord.Embed(title="Warnings for {}".format(str(user)), colour=roxbot.EmbedColours.pink) | |||
em.set_thumbnail(url=user.avatar_url) | |||
x = 1 | |||
userlist = settings.warnings[user_id] | |||
userlist = warnings[user_id] | |||
for warning in userlist: | |||
try: | |||
warned_by = str(await self.bot.get_user_info(warning["warned-by"])) | |||
@@ -248,21 +244,23 @@ class Admin: | |||
"""Removes one or all of the warnings for a user.""" | |||
user_id = str(user.id) | |||
settings = gs.get(ctx.guild) | |||
warnings = settings["admin"]["warnings"] | |||
if index: | |||
try: | |||
index = int(index) | |||
index -= 1 | |||
settings.warnings[user_id].pop(index) | |||
if not settings.warnings[user_id]: | |||
settings.warnings.pop(user_id) | |||
warnings[user_id].pop(index) | |||
if not warnings[user_id]: | |||
warnings.pop(user_id) | |||
settings.update(settings.warnings, "warnings") | |||
settings["admin"]["warnings"] = warnings | |||
settings.update(settings["admin"], "admin") | |||
return await ctx.send(self.OK_WARN_REMOVE_REMOVED_WARNING.format(index+1, str(user))) | |||
except Exception as e: | |||
if isinstance(e, IndexError): | |||
return await ctx.send(self.ERROR_WARN_REMOVE_INDEXERROR.format(len(settings.warnings[user_id]))) | |||
return await ctx.send(self.ERROR_WARN_REMOVE_INDEXERROR.format(len(settings["warnings"][user_id]))) | |||
elif isinstance(e, KeyError): | |||
return await ctx.send(self.WARN_WARN_REMOVE_USER_NOT_FOUND.format(str(user))) | |||
elif isinstance(e, ValueError): | |||
@@ -271,8 +269,9 @@ class Admin: | |||
raise e | |||
else: | |||
try: | |||
settings.warnings.pop(user_id) | |||
settings.update(settings.warnings, "warnings") | |||
warnings.pop(user_id) | |||
settings["admin"]["warnings"] = warnings | |||
settings.update(settings["admin"], "admin") | |||
return await ctx.send(self.OK_WARN_REMOVE_REMOVED_WARNINGS.format(str(user))) | |||
except KeyError: | |||
return await ctx.send(self.WARN_WARN_REMOVE_USER_NOT_FOUND.format(str(user))) | |||
@@ -282,15 +281,15 @@ class Admin: | |||
async def prune(self, ctx, dry_run=0): | |||
"""Purges banned users from the warn list. Add a 1 at the end to do a dry run.""" | |||
settings = gs.get(ctx.guild) | |||
warnings = settings.warnings.copy() | |||
warnings = settings["admin"]["warnings"].copy() | |||
count = 0 | |||
for ban in await ctx.guild.bans(): | |||
for user in warnings: | |||
if int(user) == ban.user.id: | |||
if dry_run == 0: | |||
settings.warnings.pop(user) | |||
settings["admin"]["warnings"].pop(user) | |||
count += 1 | |||
settings.update(settings.warnings, "warnings") | |||
settings.update(settings["admin"], "admin") | |||
return await ctx.send(self.OK_WARN_PRUNE_PRUNED.format(count)) | |||
@commands.guild_only() | |||
@@ -298,7 +297,7 @@ class Admin: | |||
@commands.bot_has_permissions(kick_members=True) | |||
@commands.command() | |||
async def kick(self, ctx, member: discord.Member, *, reason=""): | |||
"""Kicks mentioned user. Allows you to give a reason.""" | |||
"""Kicks mentioned user. Allows you to give a reason. Requires the Kick Members permission.""" | |||
try: | |||
await member.kick(reason=reason) | |||
return await ctx.send(self.OK_MOD_ACTION.format("Kicked", member, reason)) | |||
@@ -310,7 +309,7 @@ class Admin: | |||
@commands.bot_has_permissions(ban_members=True) | |||
@commands.command() | |||
async def ban(self, ctx, member: discord.Member, *, reason=""): | |||
"""Bans mentioned user. Allows you to give a reason.""" | |||
"""Bans mentioned user. Allows you to give a reason. Requires the Ban Members permission.""" | |||
try: | |||
await member.ban(reason=reason, delete_message_days=0) | |||
return await ctx.send(self.OK_MOD_ACTION.format("Banned", member, reason)) | |||
@@ -322,11 +321,10 @@ class Admin: | |||
@commands.bot_has_permissions(ban_members=True) | |||
@commands.command() | |||
async def unban(self, ctx, member: roxbot.converters.User, *, reason=""): | |||
"""Unbans user with given ID. Allows you to give a reason.""" | |||
"""Unbans user with given ID. Allows you to give a reason. Requires the Ban Members permission.""" | |||
ban = await ctx.guild.get_ban(member) | |||
mem = ban.user | |||
if mem is None: | |||
# TODO: For issues like this, make BadArgument a negative response embed not an error | |||
return await ctx.send(self.WARN_UNBAN_NOTFOUND) | |||
try: | |||
await ctx.guild.unban(mem, reason=reason) |
@@ -52,7 +52,8 @@ class CustomCommands: | |||
"custom_commands": { | |||
"0": {}, | |||
"1": {}, | |||
"2": {} | |||
"2": {}, | |||
"convert": {"0": "hide", "1": "hide", "2": "hide"} | |||
} | |||
} | |||
@@ -129,11 +130,14 @@ class CustomCommands: | |||
command_output = self._get_output(settings["custom_commands"]["0"][command]) | |||
return await channel.send(command_output) | |||
@commands.has_permissions(manage_messages=True) | |||
@commands.guild_only() | |||
@commands.group(aliases=["cc"]) | |||
@roxbot.checks.is_owner_or_admin() | |||
async def custom(self, ctx): | |||
""""A group of commands to manage custom commands for your server.""" | |||
"""" | |||
A group of commands to manage custom commands for your server. | |||
Requires the Manage Messages permission. | |||
""" | |||
if ctx.invoked_subcommand is None: | |||
return await ctx.send('Missing Argument') | |||
@@ -188,7 +188,7 @@ class Fun: | |||
response += '\n' | |||
return await ctx.send(response) | |||
@roxbot.checks.isnt_anal() | |||
@commands.is_nsfw() | |||
@commands.command() | |||
async def spank(self, ctx, *, user: discord.User = None): | |||
""" | |||
@@ -201,7 +201,7 @@ class Fun: | |||
return await ctx.send("You didn't mention someone for me to spank") | |||
return await ctx.send(":peach: :wave: *{} spanks {}*".format(self.bot.user.name, user.name)) | |||
@roxbot.checks.isnt_anal() | |||
@commands.is_nsfw() | |||
@commands.command(aliases=["succ"]) | |||
async def suck(self, ctx, *, user: discord.User = None): | |||
""" |
@@ -133,6 +133,30 @@ class GaySoundsShitposts: | |||
return ctx.send("Error, message roxie thanks.") | |||
return await ctx.invoke(self.perms, role=arg) | |||
@commands.command() | |||
async def gss(self, ctx, selection=None, *, changes=None): | |||
"""Custom Cog for the GaySoundsShitposts Discord Server.""" | |||
selection = selection.lower() | |||
settings = roxbot.guild_settings.get(ctx.guild) | |||
gss = settings["gss"] | |||
if selection == "loggingchannel": | |||
if ctx.message.channel_mentions: | |||
channel = ctx.channel_mentions[0] | |||
else: | |||
channel = self.bot.get_channel(changes) | |||
gss["log_channel"] = channel.id | |||
await ctx.send("Logging Channel set to '{}'".format(channel.name)) | |||
elif selection == "requireddays": | |||
gss["required_days"] = int(changes) | |||
await ctx.send("Required days set to '{}'".format(str(changes))) | |||
elif selection == "requiredscore": | |||
gss["required_score"] = int(changes) | |||
await ctx.send("Required score set to '{}'".format(str(changes))) | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return settings.update(gss, "gss") | |||
def setup(bot_client): | |||
bot_client.add_cog(GaySoundsShitposts(bot_client)) |
@@ -25,7 +25,10 @@ SOFTWARE. | |||
""" | |||
import typing | |||
import discord | |||
from discord.ext import commands | |||
import roxbot | |||
from roxbot import guild_settings | |||
@@ -83,6 +86,63 @@ class JoinLeave(): | |||
return await channel.send(embed=discord.Embed( | |||
description="{}#{} has left or been beaned.".format(member.name, member.discriminator), colour=roxbot.EmbedColours.pink)) | |||
@commands.has_permissions(manage_messages=True) | |||
@commands.command() | |||
async def greets(self, ctx, setting, channel: typing.Optional[discord.TextChannel] = None, *, text: str): | |||
"""Edits settings for the Welcome Messages | |||
Options: | |||
enable/disable: Enable/disables parts of the cog. Needs to specify which part. | |||
channel: Sets the channels for either option. Must be a ID or mention. | |||
message: specifies a custom message for the greet messages. | |||
""" | |||
setting = setting.lower() | |||
settings = guild_settings.get(ctx.guild) | |||
greets = settings["greets"] | |||
if setting == "enable": | |||
greets["enabled"] = 1 | |||
await ctx.send("'greets' was enabled!") | |||
elif setting == "disable": | |||
greets["enabled"] = 0 | |||
await ctx.send("'greets' was disabled :cry:") | |||
elif setting == "channel": | |||
if channel is None: | |||
channel = ctx.channel | |||
greets["welcome-channel"] = channel.id | |||
elif setting == "custommessage": | |||
greets["custom-message"] = text | |||
await ctx.send("Custom message set to '{}'".format(text)) | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return settings.update(greets, "greets") | |||
@commands.has_permissions(manage_messages=True) | |||
@commands.command() | |||
async def goodbyes(self, ctx, setting, *, channel: typing.Optional[discord.TextChannel] = None): | |||
"""Edits settings for the Welcome Messages | |||
Options: | |||
enable/disable: Enable/disables parts of the cog. Needs to specify which part. | |||
channel: Sets the channels for either option. Must be a ID or mention. | |||
message: specifies a custom message for the greet messages. | |||
""" | |||
setting = setting.lower() | |||
settings = guild_settings.get(ctx.guild) | |||
goodbyes = settings["goodbyes"] | |||
if setting == "enable": | |||
goodbyes["enabled"] = 1 | |||
await ctx.send("'goodbyes' was enabled!") | |||
elif setting == "disable": | |||
goodbyes["enabled"] = 0 | |||
await ctx.send("'goodbyes' was disabled :cry:") | |||
elif setting == "channel": | |||
if channel is None: | |||
channel = ctx.channel | |||
goodbyes["goodbye-channel"] = channel.id | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return settings.update(goodbyes, "goodbyes") | |||
def setup(Bot): | |||
Bot.add_cog(JoinLeave(Bot)) |
@@ -25,6 +25,7 @@ SOFTWARE. | |||
""" | |||
import typing | |||
import random | |||
import discord | |||
from discord.ext import commands | |||
@@ -44,6 +45,14 @@ class NFSW(): | |||
def __init__(self, bot_client): | |||
self.bot = bot_client | |||
self.cache = {} | |||
self.settings = { | |||
"nsfw": { | |||
"enabled": 0, | |||
"channels": [], | |||
"convert": {"enabled": "bool", "channels": "channel"}, | |||
"blacklist": [] | |||
} | |||
} | |||
@roxbot.checks.is_nfsw_enabled() | |||
@commands.command(hidden=True) | |||
@@ -112,6 +121,59 @@ class NFSW(): | |||
post_url = "https://simg3.gelbooru.com/images/" | |||
return await ctx.invoke(self.gelbooru_clone, base_url=base_url, post_url=post_url, tags=tags) | |||
@commands.command() | |||
async def nsfw(self, ctx, setting, channel: typing.Optional[discord.TextChannel] = None, *, changes=None): | |||
"""Edits settings for the nsfw cog and other nsfw commands. | |||
If nsfw is enabled and nsfw channels are added, the bot will only allow nsfw commands in the specified channels. | |||
Options: | |||
enable/disable: Enable/disables nsfw commands. | |||
addchannel/removechannel: Adds/Removes a nsfw channel. | |||
addbadtag/removebadtag: Add/Removes blacklisted tags so that you can avoid em with the commands. | |||
Example: | |||
;settings nsfw addchannel #nsfw_stuff | |||
""" | |||
setting = setting.lower() | |||
settings = roxbot.guild_settings.get(ctx.guild) | |||
nsfw = settings["nsfw"] | |||
if setting == "enable": | |||
nsfw["enabled"] = 1 | |||
await ctx.send("'nsfw' was enabled!") | |||
elif setting == "disable": | |||
nsfw["enabled"] = 0 | |||
await ctx.send("'nsfw' was disabled :cry:") | |||
elif setting == "addchannel": | |||
if not channel and not changes: | |||
channel = ctx.channel | |||
if channel.id not in nsfw["channels"]: | |||
nsfw["channels"].append(channel.id) | |||
await ctx.send("'{}' has been added to the nsfw channel list.".format(channel.name)) | |||
else: | |||
return await ctx.send("'{}' is already in the list.".format(channel.name)) | |||
elif setting == "removechannel": | |||
if not channel and not changes: | |||
channel = ctx.channel | |||
try: | |||
nsfw["channels"].remove(channel.id) | |||
await ctx.send("'{}' has been removed from the nsfw channel list.".format(channel.name)) | |||
except ValueError: | |||
return await ctx.send("That role was not in the list.") | |||
elif setting == "addbadtag": | |||
if changes not in nsfw["blacklist"]: | |||
nsfw["blacklist"].append(changes) | |||
await ctx.send("'{}' has been added to the blacklisted tag list.".format(changes)) | |||
else: | |||
return await ctx.send("'{}' is already in the list.".format(changes)) | |||
elif setting == "removebadtag": | |||
try: | |||
nsfw["blacklist"].remove(changes) | |||
await ctx.send("'{}' has been removed from the blacklisted tag list.".format(changes)) | |||
except ValueError: | |||
return await ctx.send("That tag was not in the blacklisted tag list.") | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return settings.update(nsfw, "nsfw") | |||
def setup(bot_client): | |||
bot_client.add_cog(NFSW(bot_client)) |
@@ -24,7 +24,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||
SOFTWARE. | |||
""" | |||
import discord | |||
from discord.ext import commands | |||
@@ -51,6 +50,48 @@ class SelfAssign(): | |||
sa["roles"].remove(role.id) | |||
return settings.update(sa, "self_assign") | |||
@commands.has_permissions(manage_roles=True) | |||
@commands.guild_only() | |||
@commands.command(aliases=["sa"]) | |||
async def selfassign(self, ctx, setting, *, role: discord.Role): | |||
"""Edits settings for self assign cog. Requires Manage Roles permission. | |||
Options: | |||
enable/disable: Enable/disables the cog. | |||
add/remove: adds or removes a role that can be self assigned in the server. | |||
""" | |||
settings = roxbot.guild_settings.get(ctx.guild) | |||
self_assign = settings["self_assign"] | |||
setting = setting.lower() | |||
if setting == "enable": | |||
self_assign["enabled"] = 1 | |||
await ctx.send("'self_assign' was enabled!") | |||
elif setting == "disable": | |||
self_assign["enabled"] = 0 | |||
await ctx.send("'self_assign' was disabled :cry:") | |||
elif setting == "add": | |||
try: | |||
if role.id in self_assign["roles"]: | |||
return await ctx.send("{} is already a self-assignable role.".format(role.name)) | |||
self_assign["roles"].append(role.id) | |||
await ctx.send('Role "{}" added'.format(str(role))) | |||
except AttributeError: | |||
raise commands.BadArgument("Could not find that role.") | |||
elif setting == "remove": | |||
try: | |||
if role.id in self_assign["roles"]: | |||
self_assign["roles"].remove(role.id) | |||
await ctx.send('"{}" has been removed from the self-assignable roles.'.format(str(role))) | |||
else: | |||
return await ctx.send("That role was not in the list.") | |||
except AttributeError: | |||
raise commands.BadArgument("Could not find that role.") | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return settings.update(self_assign, "self_assign") | |||
@commands.guild_only() | |||
@commands.command(pass_context=True) | |||
async def listroles(self, ctx): |
@@ -419,10 +419,10 @@ class Trivia: | |||
else: | |||
await ctx.send(embed=discord.Embed(description="Game isn't being played here.", colour=self.error_colour)) | |||
@checks.is_admin_or_mod() | |||
@commands.has_permissions(manage_channels=True) | |||
@trivia.command() | |||
async def kick(self, ctx, user: discord.Member): | |||
"""Mod command to kick users out of the game. Useful if a user is AFK.""" | |||
"""Mod command to kick users out of the game. Useful if a user is AFK. Requires Manage Channels permission.""" | |||
channel = ctx.channel | |||
player = user | |||
if channel.id in self.games: |
@@ -25,7 +25,8 @@ SOFTWARE. | |||
""" | |||
from discord import ActivityType | |||
import typing | |||
import discord | |||
from discord.ext import commands | |||
import roxbot | |||
@@ -54,14 +55,14 @@ class Twitch(): | |||
return | |||
if member_a.activitiy: | |||
if member_a.activity.type == ActivityType.streaming and member_b.activity.type != ActivityType.streaming: | |||
if member_a.activity.type == discord.ActivityType.streaming and member_b.activity.type != discord.ActivityType.streaming: | |||
if not twitch["whitelist"]["enabled"] or member_a.id in twitch["whitelist"]["list"]: | |||
channel = self.bot.get_channel(twitch["channel"]) | |||
return await channel.send(":video_game:** {} is live!** :video_game:\n{}\n{}".format( | |||
member_a.name, member_a.game.name, member_a.game.url)) | |||
@commands.group() | |||
@roxbot.checks.is_admin_or_mod() | |||
@commands.group(aliases=["wl"]) | |||
@commands.has_permissions(manage_channels=True) | |||
async def whitelist(self, ctx): | |||
"""Command group that handles the twitch cog's whitelist.""" | |||
if ctx.invoked_subcommand is None: | |||
@@ -115,6 +116,33 @@ class Twitch(): | |||
elif option == 'list': | |||
return await ctx.send(settings["twitch"]["whitelist"]["list"]) | |||
@commands.has_permissions(manage_channels=True) | |||
@commands.command() | |||
async def twitch(self, ctx, setting, *, channel: discord.TextChannel = None): | |||
"""Edits settings for self assign cog. | |||
Options: | |||
enable/disable: Enable/disables the cog. | |||
channel: Sets the channel to shill in. | |||
""" | |||
setting = setting.lower() | |||
settings = roxbot.guild_settings.get(ctx.guild) | |||
twitch = settings["twitch"] | |||
if setting == "enable": | |||
twitch["enabled"] = 1 | |||
await ctx.send("'twitch' was enabled!") | |||
elif setting == "disable": | |||
twitch["enabled"] = 0 | |||
await ctx.send("'twitch' was disabled :cry:") | |||
elif setting == "channel": | |||
twitch["channel"] = channel.id | |||
await ctx.send("{} has been set as the twitch shilling channel!".format(channel.mention)) | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return settings.update(twitch, "twitch") | |||
def setup(bot_client): | |||
bot_client.add_cog(Twitch(bot_client)) |
@@ -34,7 +34,6 @@ from math import ceil | |||
from discord.ext import commands | |||
import roxbot | |||
from roxbot import guild_settings | |||
def _clear_cache(): | |||
@@ -61,7 +60,7 @@ def _format_duration(duration): | |||
def volume_perms(): | |||
def predicate(ctx): | |||
gs = guild_settings.get(ctx.guild) | |||
gs = roxbot.guild_settings.get(ctx.guild) | |||
if gs["voice"]["need_perms"]: # Had to copy the admin or mod code cause it wouldn't work ;-; | |||
if ctx.message.author.id == roxbot.owner: | |||
return True | |||
@@ -212,7 +211,7 @@ class Voice: | |||
embed.set_footer(text="{}/{} | Volume: {}%".format(time_played, duration, int(self.now_playing[guild.id].volume*100))) | |||
return embed | |||
@roxbot.checks.is_admin_or_mod() | |||
@roxbot.checks.has_permission_or_owner(manage_channels=True) | |||
@commands.guild_only() | |||
@commands.command() | |||
async def join(self, ctx, *, channel: discord.VoiceChannel = None): | |||
@@ -237,7 +236,7 @@ class Voice: | |||
async def play(self, ctx, *, url, stream=False, from_queue=False, queued_by=None): | |||
"""Plays from a url or search query (almost anything youtube_dl supports)""" | |||
guild = ctx.guild | |||
voice = guild_settings.get(guild).get("voice") | |||
voice = roxbot.guild_settings.get(guild).get("voice") | |||
# Checks if invoker is in voice with the bot. Skips admins and mods and owner and if the song was queued previously. | |||
if not (roxbot.checks._is_admin_or_mod(ctx) or from_queue): | |||
@@ -377,10 +376,10 @@ class Voice: | |||
@commands.guild_only() | |||
@commands.command() | |||
async def skip(self, ctx, option=""): | |||
"""Skips or votes to skip the current video. Use option "--force" if your an admin and """ | |||
voice = guild_settings.get(ctx.guild)["voice"] | |||
"""Skips or votes to skip the current video. Can use option "--force" if you have manage_channels permission. """ | |||
voice = roxbot.guild_settings.get(ctx.guild)["voice"] | |||
if ctx.voice_client.is_playing(): | |||
if voice["skip_voting"] and not (option == "--force" and roxbot.checks._is_admin_or_mod(ctx)): # Admin force skipping | |||
if voice["skip_voting"] and not (option == "--force" and ctx.author.guild_permissions.manage_channels): # Admin force skipping | |||
if ctx.author in self.skip_votes[ctx.guild.id]: | |||
return await ctx.send("You have already voted to skip the current track.") | |||
else: | |||
@@ -443,10 +442,10 @@ class Voice: | |||
await ctx.send(embed=page) | |||
@commands.guild_only() | |||
@roxbot.checks.is_admin_or_mod() | |||
@commands.has_permissions(manage_channels=True) | |||
@commands.command() | |||
async def remove(self, ctx, index): | |||
"""Removes a item from the queue with the given index. Can also input all to delete all queued items.""" | |||
"""Removes a item from the queue with the given index. Can also input all to delete all queued items. Requires the Manage Channels permission""" | |||
# Try and convert index into an into. If not possible, just move forward | |||
try: | |||
index = int(index) | |||
@@ -470,10 +469,10 @@ class Voice: | |||
raise commands.CommandError("Valid Index not given.") | |||
@commands.guild_only() | |||
@roxbot.checks.is_admin_or_mod() | |||
@commands.has_permissions(manage_channels=True) | |||
@commands.command(alaises=["disconnect"]) | |||
async def stop(self, ctx): | |||
"""Stops and disconnects the bot from voice.""" | |||
"""Stops and disconnects the bot from voice. Requires the Manage Channels permission""" | |||
if ctx.voice_client is None: | |||
raise commands.CommandError("Roxbot is not in a voice channel.") | |||
else: | |||
@@ -484,6 +483,64 @@ class Voice: | |||
await ctx.voice_client.disconnect() | |||
return await ctx.send(":wave:") | |||
@commands.has_permissions(manage_channels=True) | |||
@commands.command() | |||
async def voice(self, ctx, setting=None, change=None): | |||
"""Edits settings for the voice cog. Requires the Manage Channels permission | |||
Options: | |||
enable/disable: Enable/disables specified change. | |||
skipratio: Specify what the ratio should be for skip voting if enabled. Example: 0.6 for 60% | |||
maxlength/duration: Specify (in seconds) the max duration of a video that can be played. Ignored if staff of the server/bot owner. | |||
Possible settings to enable/disable: | |||
needperms: specifies whether volume controls and other bot functions need mod/admin perms. | |||
skipvoting: specifies whether skipping should need over half of voice users to vote to skip. Bypassed by mods. | |||
Example: | |||
;settings voice enable skipvoting | |||
""" | |||
setting = setting.lower() | |||
change = change.lower() | |||
settings = roxbot.guild_settings.get(ctx.guild) | |||
voice = settings["voice"] | |||
if setting == "enable": | |||
if change == "needperms": | |||
voice["need_perms"] = 1 | |||
await ctx.send("'{}' has been enabled!".format(change)) | |||
elif change == "skipvoting": | |||
voice["skip_voting"] = 1 | |||
await ctx.send("'{}' has been enabled!".format(change)) | |||
else: | |||
return await ctx.send("Not a valid change.") | |||
elif setting == "disable": | |||
if change == "needperms": | |||
voice["need_perms"] = 1 | |||
await ctx.send("'{}' was disabled :cry:".format(change)) | |||
elif change == "skipvoting": | |||
voice["skip_voting"] = 1 | |||
await ctx.send("'{}' was disabled :cry:".format(change)) | |||
else: | |||
return await ctx.send("Not a valid change.") | |||
elif setting == "skipratio": | |||
change = float(change) | |||
if 1 > change > 0: | |||
voice["skip_ratio"] = change | |||
elif 0 < change <= 100: | |||
change = change/10 | |||
voice["skip_ratio"] = change | |||
else: | |||
return await ctx.send("Valid ratio not given.") | |||
await ctx.send("Skip Ratio was set to {}".format(change)) | |||
elif setting == "maxlength" or setting == "maxduration": | |||
change = int(change) | |||
if change >= 1: | |||
voice["skip_ratio"] = change | |||
else: | |||
return await ctx.send("Valid max duration not given.") | |||
await ctx.send("Max Duration was set to {}".format(change)) | |||
else: | |||
return await ctx.send("Valid option not given.") | |||
return settings.update(voice, "voice") | |||
def setup(bot_client): | |||
bot_client.add_cog(Voice(bot_client)) |
@@ -179,7 +179,7 @@ class GuildSettings(object): | |||
for key, setting in settings.items(): | |||
if setting.get("convert"): | |||
for x in setting["convert"].keys(): | |||
if setting["convert"][x] != "bool": | |||
if setting["convert"][x] not in ("bool", "hide"): | |||
if isinstance(setting[x], list): | |||
for y, value in enumerate(setting[x]): | |||
if option == "str": | |||
@@ -207,14 +207,20 @@ class GuildSettings(object): | |||
""" | |||
Get latest settings, and update them with a change. | |||
:param changed_dict: | |||
:param setting: Setting should be a str of the setting key. If nothing is passed, it is assumed changed_dict is the settings file for the whole server. | |||
:param setting: Setting should be a str of the setting key. | |||
If nothing is passed, it is assumed changed_dict is the settings file for the whole server. | |||
THIS IS NOT RECOMMENED. Always try and just pass the cogs settings and not a whole settings file. | |||
:return: | |||
""" | |||
self.settings = self.refresh() | |||
settings = self.settings.copy() | |||
if setting is not None: | |||
self.settings[setting] = changed_dict | |||
settings[setting] = changed_dict | |||
elif isinstance(changed_dict, dict): | |||
settings = changed_dict | |||
elif isinstance(changed_dict, GuildSettings): | |||
settings = changed_dict.settings | |||
else: | |||
self.settings = changed_dict | |||
settings = self.settings.copy() | |||
self._convert(settings, "str") | |||
raise TypeError("changed_dict can only be a dict or GuildSettings object.") | |||
settings = self._convert(settings, "str") | |||
_write_changes(self.id, self.cogs, settings) |
@@ -24,8 +24,9 @@ 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 | |||
@@ -58,6 +59,13 @@ async def log(guild, channel, command_name, **kwargs): | |||
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_member_join(self, member): | |||
logging = guild_settings.get(member.guild)["logging"] | |||
@@ -79,6 +87,34 @@ class Logging: | |||
embed = discord.Embed(description="{} left the server".format(member), colour=roxbot.EmbedColours.pink) | |||
return await channel.send(embed=embed) | |||
@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)) |
@@ -1,4 +0,0 @@ | |||
# Ignore everything in this directory | |||
* | |||
# Except this file | |||
!.gitignore |
@@ -1,491 +0,0 @@ | |||
# -*- 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 discord | |||
from discord.ext import commands | |||
from roxbot import checks, guild_settings, EmbedColours | |||
class Settings: | |||
""" | |||
Settings is a mix of settings and admin stuff for the bot. OWNER OR ADMIN ONLY. | |||
""" | |||
def __init__(self, bot_client): | |||
self.bot = bot_client | |||
def get_channel(self, ctx, channel): | |||
if ctx.message.channel_mentions: | |||
return ctx.message.channel_mentions[0] | |||
else: | |||
return self.bot.get_channel(channel) | |||
def parse_setting(self, ctx, settings_to_copy, raw=False): | |||
settingcontent = "" | |||
setting = settings_to_copy.copy() | |||
convert = setting.get("convert", None) | |||
if convert is not None and not raw: | |||
for x in convert.keys(): | |||
if convert[x] == "bool": | |||
if setting[x] == 0: | |||
setting[x] = "False" | |||
else: | |||
setting[x] = "True" | |||
elif convert[x] == "channel": | |||
if isinstance(setting[x], list): | |||
if len(setting[x]) >= 60: | |||
setting[x] = "There is too many channels to display." | |||
else: | |||
new_channels = [] | |||
for channel in setting[x]: | |||
try: | |||
new_channels.append(self.bot.get_channel(channel).mention) | |||
except AttributeError: | |||
new_channels.append(channel) | |||
setting[x] = new_channels | |||
else: | |||
try: | |||
setting[x] = self.bot.get_channel(setting[x]).mention | |||
except AttributeError: | |||
pass | |||
elif convert[x] == "role": | |||
if isinstance(setting[x], list): | |||
if len(setting[x]) >= 60: | |||
setting[x] = "There is too many roles to display." | |||
else: | |||
new_roles = [] | |||
for role_id in setting[x]: | |||
try: | |||
new_roles.append(discord.utils.get(ctx.guild.roles, id=role_id).name) | |||
except AttributeError: | |||
new_roles.append(role_id) | |||
setting[x] = new_roles | |||
else: | |||
try: | |||
setting[x] = discord.utils.get(ctx.guild.roles, id=setting[x]).name | |||
except AttributeError: | |||
pass | |||
elif convert[x] == "user": | |||
if isinstance(setting[x], list): | |||
if len(setting[x]) >= 60: | |||
setting[x] = "There is too many users to display." | |||
else: | |||
new_users = [] | |||
for user_id in setting[x]: | |||
user = self.bot.get_user(user_id) | |||
if user is None: | |||
new_users.append(str(user_id)) | |||
else: | |||
new_users.append(str(user)) | |||
setting[x] = new_users | |||
else: | |||
user = self.bot.get_user(setting[x]) | |||
if user is None: | |||
setting[x] = str(setting[x]) | |||
else: | |||
setting[x] = str(user) | |||
elif convert[x] == "hide": | |||
setting[x] = "This is hidden. Please use other commands to get this data." | |||
for x in setting.items(): | |||
if x[0] != "convert": | |||
settingcontent += str(x).strip("()") + "\n" | |||
return settingcontent | |||
@commands.command(aliases=["printsettingsraw"]) | |||
@checks.is_admin_or_mod() | |||
async def printsettings(self, ctx, option=None): | |||
"""OWNER OR ADMIN ONLY: Prints the servers settings file.""" | |||
# TODO: Use paginator to make the output here not break all the time. | |||
config = guild_settings.get(ctx.guild) | |||
settings = dict(config.settings.copy()) # Make a copy of settings so we don't change the actual settings. | |||
paginator = commands.Paginator(prefix="```md") | |||
paginator.add_line("{} settings for {}.\n".format(self.bot.user.name, ctx.message.guild.name)) | |||
if option in settings: | |||
raw = bool(ctx.invoked_with == "printsettingsraw") | |||
settingcontent = self.parse_setting(ctx, settings[option], raw=raw) | |||
paginator.add_line("**{}**".format(option)) | |||
paginator.add_line(settingcontent) | |||
for page in paginator.pages: | |||
await ctx.send(page) | |||
else: | |||
for setting in settings: | |||
if setting != "custom_commands" and setting != "warnings": | |||
raw = bool(ctx.invoked_with == "printsettingsraw") | |||
settingcontent = self.parse_setting(ctx, settings[setting], raw=raw) | |||
paginator.add_line("**{}**".format(setting)) | |||
paginator.add_line(settingcontent) | |||
for page in paginator.pages: | |||
await ctx.send(page) | |||
@commands.group(case_insensitive=True) | |||
@checks.is_admin_or_mod() | |||
async def settings(self, ctx): | |||
self.guild_settings = guild_settings.get(ctx.guild) | |||
@settings.command(aliases=["log"]) | |||
async def logging(self, ctx, selection=None, *, changes=None): | |||
"""Edits the logging settings. | |||
Options: | |||
enable/disable: Enable/disables logging. | |||
channel: sets the channel. | |||
""" | |||
selection = selection.lower() | |||
settings = guild_settings.get(ctx.guild) | |||
if selection == "enable": | |||
settings.logging["enabled"] = 1 | |||
await ctx.send("'logging' was enabled!") | |||
elif selection == "disable": | |||
settings.logging["enabled"] = 0 | |||
await ctx.send("'logging' was disabled :cry:") | |||
elif selection == "channel": | |||
channel = self.get_channel(ctx, changes) | |||
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 self.guild_settings.update(settings.logging, "logging") | |||
@settings.command(aliases=["sa"]) | |||
async def selfassign(self, ctx, selection=None, *, changes=None): | |||
"""Edits settings for self assign cog. | |||
Options: | |||
enable/disable: Enable/disables the cog. | |||
addrole/removerole: adds or removes a role that can be self assigned in the server. | |||
""" | |||
selection = selection.lower() | |||
role = discord.utils.find(lambda u: u.name == changes, ctx.message.guild.roles) | |||
self_assign = self.guild_settings.self_assign | |||
if selection == "enable": | |||
self_assign["enabled"] = 1 | |||
await ctx.send("'self_assign' was enabled!") | |||
elif selection == "disable": | |||
self_assign["enabled"] = 0 | |||
await ctx.send("'self_assign' was disabled :cry:") | |||
elif selection == "addrole": | |||
try: | |||
if role.id in self_assign["roles"]: | |||
return await ctx.send("{} is already a self-assignable role.".format(role.name)) | |||
self_assign["roles"].append(role.id) | |||
await ctx.send('Role "{}" added'.format(str(role))) | |||
except AttributeError: | |||
return await ctx.send("Role param incorrect. Check you spelt it correctly") | |||
elif selection == "removerole": | |||
try: | |||
if role.id in self_assign["roles"]: | |||
self_assign["roles"].remove(role.id) | |||
await ctx.send('"{}" has been removed from the self-assignable roles.'.format(str(role))) | |||
else: | |||
return await ctx.send("That role was not in the list.") | |||
except AttributeError: | |||
return await ctx.send("Role param incorrect. Check you spelt it correctly") | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return self.guild_settings.update(self_assign, "self_assign") | |||
@settings.command(aliases=["jl"]) | |||
async def joinleave(self, ctx, selection=None, *, changes=None): | |||
"""Edits settings for joinleave cog. | |||
Options: | |||
enable/disable: Enable/disables parts of the cog. Needs to specify which part. | |||
Example: | |||
;settings joinleave enable greets|goodbyes | |||
greetschannel/goodbyeschannel: Sets the channels for either option. Must be a ID or mention. | |||
custommessage: specifies a custom message for the greet messages. | |||
""" | |||
selection = selection.lower() | |||
channel = self.get_channel(ctx, changes) | |||
greets = self.guild_settings.greets | |||
goodbyes = self.guild_settings.goodbyes | |||
if selection == "greets": | |||
if changes == "enable": | |||
greets["enabled"] = 1 | |||
await ctx.send("'greets' was enabled!") | |||
elif changes == "disable": | |||
greets["enabled"] = 0 | |||
await ctx.send("'greets' was disabled :cry:") | |||
elif selection == "goodbyes": | |||
if changes == "enable": | |||
goodbyes["enabled"] = 1 | |||
await ctx.send("'goodbyes' was enabled!") | |||
elif changes == "disable": | |||
goodbyes["enabled"] = 0 | |||
await ctx.send("'goodbyes' was disabled :cry:") | |||
else: | |||
if selection == "greetschannel": | |||
greets["welcome-channel"] = channel.id | |||
changes = "greets" | |||
await ctx.send("{} has been set as the welcome channel!".format(channel.mention)) | |||
elif selection == "goodbyeschannel": | |||
goodbyes["goodbye-channel"] = channel.id | |||
changes = "goodbyes" | |||
await ctx.send("{} has been set as the goodbye channel!".format(channel.mention)) | |||
elif selection == "custommessage": | |||
greets["custom-message"] = changes | |||
await ctx.send("Custom message set to '{}'".format(changes)) | |||
changes = "greets" | |||
else: | |||
return await ctx.send("No valid option given.") | |||
if changes == "greets": | |||
return self.guild_settings.update(greets, "greets") | |||
elif changes == "goodbyes": | |||
return self.guild_settings.update(goodbyes, "goodbyes") | |||
@settings.command() | |||
async def twitch(self, ctx, selection=None, *, changes=None): | |||
"""Edits settings for self assign cog. | |||
Options: | |||
enable/disable: Enable/disables the cog. | |||
channel: Sets the channel to shill in. | |||
""" | |||
# TODO: Menu also needs editing since I edited the twitch backend | |||
selection = selection.lower() | |||
twitch = self.guild_settings.twitch | |||
if selection == "enable": | |||
twitch["enabled"] = 1 | |||
await ctx.send("'twitch' was enabled!") | |||
elif selection == "disable": | |||
twitch["enabled"] = 0 | |||
await ctx.send("'twitch' was disabled :cry:") | |||
elif selection == "channel": | |||
channel = self.get_channel(ctx, changes) | |||
twitch["channel"] = channel.id | |||
await ctx.send("{} has been set as the twitch shilling channel!".format(channel.mention)) | |||
# Is lacking whitelist options. Might be added or might be depreciated. | |||
# Turns out this is handled in the cog and I don't think it needs changing but may be confusing. | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return self.guild_settings.update(twitch, "twitch") | |||
@settings.command(aliases=["perms"]) | |||
async def permrole(self, ctx, selection=None, *, changes=None): | |||
"""Edits settings for permission roles. | |||
Options: | |||
addadmin/removeadmin: Adds/Removes admin role. | |||
addmod/removemod: Adds/Removes mod role. | |||
Example: | |||
;settings permrole addadmin Admin | |||
""" | |||
selection = selection.lower() | |||
role = discord.utils.find(lambda u: u.name == changes, ctx.message.guild.roles) | |||
perm_roles = self.guild_settings.perm_roles | |||
if selection == "addadmin": | |||
if role.id not in perm_roles["admin"]: | |||
perm_roles["admin"].append(role.id) | |||
await ctx.send("'{}' has been added to the Admin role list.".format(role.name)) | |||
else: | |||
return await ctx.send("'{}' is already in the list.".format(role.name)) | |||
elif selection == "addmod": | |||
if role.id not in perm_roles["mod"]: | |||
perm_roles["mod"].append(role.id) | |||
await ctx.send("'{}' has been added to the Mod role list.".format(role.name)) | |||
else: | |||
return await ctx.send("'{}' is already in the list.".format(role.name)) | |||
elif selection == "removeadmin": | |||
try: | |||
perm_roles["admin"].remove(role.id) | |||
await ctx.send("'{}' has been removed from the Admin role list.".format(role.name)) | |||
except ValueError: | |||
return await ctx.send("That role was not in the list.") | |||
elif selection == "removemod": | |||
try: | |||
perm_roles["mod"].remove(role.id) | |||
await ctx.send("'{}' has been removed from the Mod role list.".format(role.name)) | |||
except ValueError: | |||
return await ctx.send("That role was not in the list.") | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return self.guild_settings.update(perm_roles, "perm_roles") | |||
@settings.command() | |||
async def gss(self, ctx, selection=None, *, changes=None): | |||
"""Custom Cog for the GaySoundsShitposts Discord Server.""" | |||
# TODO: Menu | |||
selection = selection.lower() | |||
gss = self.guild_settings.gss | |||
if selection == "loggingchannel": | |||
channel = self.get_channel(ctx, changes) | |||
gss["log_channel"] = channel.id | |||
await ctx.send("Logging Channel set to '{}'".format(channel.name)) | |||
elif selection == "requireddays": | |||
gss["required_days"] = int(changes) | |||
await ctx.send("Required days set to '{}'".format(str(changes))) | |||
elif selection == "requiredscore": | |||
gss["required_score"] = int(changes) | |||
await ctx.send("Required score set to '{}'".format(str(changes))) | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return self.guild_settings.update(gss, "gss") | |||
@settings.command() | |||
async def nsfw(self, ctx, selection=None, *, changes=None): | |||
"""Edits settings for the nsfw cog and other nsfw commands. | |||
If nsfw is enabled and nsfw channels are added, the bot will only allow nsfw commands in the specified channels. | |||
Options: | |||
enable/disable: Enable/disables nsfw commands. | |||
addchannel/removechannel: Adds/Removes a nsfw channel. | |||
addbadtag/removebadtag: Add/Removes blacklisted tags so that you can avoid em with the commands. | |||
Example: | |||
;settings nsfw addchannel #nsfw_stuff | |||
""" | |||
#menu = Menu.nsfw(ctx.guild) | |||
#print(menu.content) | |||
selection = selection.lower() | |||
nsfw = self.guild_settings.nsfw | |||
if selection == "enable": | |||
nsfw["enabled"] = 1 | |||
await ctx.send("'nsfw' was enabled!") | |||
elif selection == "disable": | |||
nsfw["enabled"] = 0 | |||
await ctx.send("'nsfw' was disabled :cry:") | |||
elif selection == "addchannel": | |||
channel = self.get_channel(ctx, changes) | |||
if channel.id not in nsfw["channels"]: | |||
nsfw["channels"].append(channel.id) | |||
await ctx.send("'{}' has been added to the nsfw channel list.".format(channel.name)) | |||
else: | |||
return await ctx.send("'{}' is already in the list.".format(channel.name)) | |||
elif selection == "removechannel": | |||
channel = self.get_channel(ctx, changes) | |||
try: | |||
nsfw["channels"].remove(channel.id) | |||
await ctx.send("'{}' has been removed from the nsfw channel list.".format(channel.name)) | |||
except ValueError: | |||
return await ctx.send("That role was not in the list.") | |||
elif selection == "addbadtag": | |||
if changes not in nsfw["blacklist"]: | |||
nsfw["blacklist"].append(changes) | |||
await ctx.send("'{}' has been added to the blacklisted tag list.".format(changes)) | |||
else: | |||
return await ctx.send("'{}' is already in the list.".format(changes)) | |||
elif selection == "removebadtag": | |||
try: | |||
nsfw["blacklist"].remove(changes) | |||
await ctx.send("'{}' has been removed from the blacklisted tag list.".format(changes)) | |||
except ValueError: | |||
return await ctx.send("That tag was not in the blacklisted tag list.") | |||
else: | |||
return await ctx.send("No valid option given.") | |||
return self.guild_settings.update(nsfw, "nsfw") | |||
@settings.command() | |||
async def voice(self, ctx, setting=None, change=None): | |||
"""Edits settings for the voice cog. | |||
Options: | |||
enable/disable: Enable/disables specified change. | |||
skipratio: Specify what the ratio should be for skip voting if enabled. Example: 0.6 for 60% | |||
maxlength/duration: Specify (in seconds) the max duration of a video that can be played. Ignored if staff of the server/bot owner. | |||
Possible settings to enable/disable: | |||
needperms: specifies whether volume controls and other bot functions need mod/admin perms. | |||
skipvoting: specifies whether skipping should need over half of voice users to vote to skip. Bypassed by mods. | |||
Example: | |||
;settings voice enable skipvoting | |||
""" | |||
setting = setting.lower() | |||
change = change.lower() | |||
voice = self.guild_settings.voice | |||
if setting == "enable": | |||
if change == "needperms": | |||
voice["need_perms"] = 1 | |||
await ctx.send("'{}' has been enabled!".format(change)) | |||
elif change == "skipvoting": | |||
voice["skip_voting"] = 1 | |||
await ctx.send("'{}' has been enabled!".format(change)) | |||
else: | |||
return await ctx.send("Not a valid change.") | |||
elif setting == "disable": | |||
if change == "needperms": | |||
voice["need_perms"] = 1 | |||
await ctx.send("'{}' was disabled :cry:".format(change)) | |||
elif change == "skipvoting": | |||
voice["skip_voting"] = 1 | |||
await ctx.send("'{}' was disabled :cry:".format(change)) | |||
else: | |||
return await ctx.send("Not a valid change.") | |||
elif setting == "skipratio": | |||
change = float(change) | |||
if 1 > change > 0: | |||
voice["skip_ratio"] = change | |||
elif 0 < change <= 100: | |||
change = change/10 | |||
voice["skip_ratio"] = change | |||
else: | |||
return await ctx.send("Valid ratio not given.") | |||
await ctx.send("Skip Ratio was set to {}".format(change)) | |||
elif setting == "maxlength" or setting == "maxduration": | |||
change = int(change) | |||
if change >= 1: | |||
voice["skip_ratio"] = change | |||
else: | |||
return await ctx.send("Valid max duration not given.") | |||
await ctx.send("Max Duration was set to {}".format(change)) | |||
else: | |||
return await ctx.send("Valid option not given.") | |||
return self.guild_settings.update(voice, "voice") | |||
@commands.guild_only() | |||
@checks.is_admin_or_mod() | |||
@commands.command() | |||
async def serverisanal(self, ctx): | |||
"""Tells the bot where the server is anal or not. | |||
This only changes if roxbot can do the suck and spank commands outside of the specified nsfw channels.""" | |||
gs = guild_settings.get(ctx.guild) | |||
is_anal = gs.is_anal | |||
if is_anal["y/n"] == 0: | |||
is_anal["y/n"] = 1 | |||
gs.update(is_anal, "is_anal") | |||
await ctx.send("I now know this server is anal") | |||
else: | |||
is_anal["y/n"] = 0 | |||
gs.update(is_anal, "is_anal") | |||
await ctx.send("I now know this server is NOT anal") | |||
def setup(bot_client): | |||
bot_client.add_cog(Settings(bot_client)) |
@@ -180,6 +180,102 @@ class System: | |||
await self.bot.change_presence(status=discord_status) | |||
await ctx.send("**:ok:** Status set to {}".format(discord_status)) | |||
def parse_setting(self, ctx, settings_to_copy, raw=False): | |||
settingcontent = "" | |||
setting = settings_to_copy.copy() | |||
convert = setting.get("convert", None) | |||
if convert is not None and not raw: | |||
for x in convert.keys(): | |||
if convert[x] == "bool": | |||
if setting[x] == 0: | |||
setting[x] = "False" | |||
else: | |||
setting[x] = "True" | |||
elif convert[x] == "channel": | |||
if isinstance(setting[x], list): | |||
if len(setting[x]) >= 60: | |||
setting[x] = "There is too many channels to display." | |||
else: | |||
new_channels = [] | |||
for channel in setting[x]: | |||
try: | |||
new_channels.append(self.bot.get_channel(channel).mention) | |||
except AttributeError: | |||
new_channels.append(channel) | |||
setting[x] = new_channels | |||
else: | |||
try: | |||
setting[x] = self.bot.get_channel(setting[x]).mention | |||
except AttributeError: | |||
pass | |||
elif convert[x] == "role": | |||
if isinstance(setting[x], list): | |||
if len(setting[x]) >= 60: | |||
setting[x] = "There is too many roles to display." | |||
else: | |||
new_roles = [] | |||
for role_id in setting[x]: | |||
try: | |||
new_roles.append(discord.utils.get(ctx.guild.roles, id=role_id).name) | |||
except AttributeError: | |||
new_roles.append(role_id) | |||
setting[x] = new_roles | |||
else: | |||
try: | |||
setting[x] = discord.utils.get(ctx.guild.roles, id=setting[x]).name | |||
except AttributeError: | |||
pass | |||
elif convert[x] == "user": | |||
if isinstance(setting[x], list): | |||
if len(setting[x]) >= 60: | |||
setting[x] = "There is too many users to display." | |||
else: | |||
new_users = [] | |||
for user_id in setting[x]: | |||
user = self.bot.get_user(user_id) | |||
if user is None: | |||
new_users.append(str(user_id)) | |||
else: | |||
new_users.append(str(user)) | |||
setting[x] = new_users | |||
else: | |||
user = self.bot.get_user(setting[x]) | |||
if user is None: | |||
setting[x] = str(setting[x]) | |||
else: | |||
setting[x] = str(user) | |||
elif convert[x] == "hide": | |||
setting[x] = "This is hidden. Please use other commands to get this data." | |||
for x in setting.items(): | |||
if x[0] != "convert": | |||
settingcontent += str(x).strip("()") + "\n" | |||
return settingcontent | |||
@commands.command(aliases=["printsettingsraw"]) | |||
@commands.has_permissions(manage_guild=True) | |||
async def printsettings(self, ctx, option=None): | |||
"""OWNER OR ADMIN ONLY: Prints the servers settings file.""" | |||
config = roxbot.guild_settings.get(ctx.guild) | |||
settings = dict(config.settings.copy()) # Make a copy of settings so we don't change the actual settings. | |||
paginator = commands.Paginator(prefix="```md") | |||
paginator.add_line("{} settings for {}.\n".format(self.bot.user.name, ctx.message.guild.name)) | |||
if option in settings: | |||
raw = bool(ctx.invoked_with == "printsettingsraw") | |||
settingcontent = self.parse_setting(ctx, settings[option], raw=raw) | |||
paginator.add_line("**{}**".format(option)) | |||
paginator.add_line(settingcontent) | |||
for page in paginator.pages: | |||
await ctx.send(page) | |||
else: | |||
for setting in settings: | |||
raw = bool(ctx.invoked_with == "printsettingsraw") | |||
settingcontent = self.parse_setting(ctx, settings[setting], raw=raw) | |||
paginator.add_line("**{}**".format(setting)) | |||
paginator.add_line(settingcontent) | |||
for page in paginator.pages: | |||
await ctx.send(page) | |||
@commands.command() | |||
@commands.is_owner() | |||
async def shutdown(self, ctx): |