From 67d8fedef854d8c28a59c62c04260a612209b51c Mon Sep 17 00:00:00 2001 From: phxntxm Date: Tue, 7 Mar 2017 22:28:30 -0600 Subject: [PATCH] Updated for rewrite: Batch 6 --- bot.py | 7 +- cogs/core.py | 3 +- cogs/da.py | 17 +++-- cogs/events.py | 34 +++++----- cogs/interaction.py | 8 +-- cogs/links.py | 15 ++--- cogs/mod.py | 145 ++++++++++++++++++++++------------------ cogs/overwatch.py | 12 ++-- cogs/owner.py | 6 +- cogs/picarto.py | 25 +++---- cogs/raffle.py | 14 ++-- cogs/stats.py | 9 +-- cogs/strawpoll.py | 2 +- cogs/tags.py | 14 ++-- cogs/twitch.py | 25 +++---- cogs/utils/checks.py | 43 +++++++----- cogs/utils/config.py | 71 +++++++++++--------- cogs/utils/utilities.py | 17 ++++- 18 files changed, 242 insertions(+), 225 deletions(-) diff --git a/bot.py b/bot.py index fecf365..22ea832 100644 --- a/bot.py +++ b/bot.py @@ -48,8 +48,7 @@ async def process_command(ctx): server = ctx.message.guild command = ctx.command - r_filter = {'command': command.qualified_name} - command_usage = await utils.get_content('command_usage', r_filter) + command_usage = await utils.get_content('command_usage', key=command.qualified_name) if command_usage is None: command_usage = {'command': command.qualified_name} else: @@ -72,8 +71,8 @@ async def process_command(ctx): command_usage['server_usage'] = total_server_usage # Save all the changes - if not await utils.update_content('command_usage', command_usage, r_filter): - await utils.add_content('command_usage', command_usage, r_filter) + if not await utils.update_content('command_usage', command_usage, command.qualified_name): + await utils.add_content('command_usage', command_usage) @bot.event diff --git a/cogs/core.py b/cogs/core.py index 613841a..1fab504 100644 --- a/cogs/core.py +++ b/cogs/core.py @@ -108,8 +108,7 @@ class Core: await ctx.send(fmt) else: try: - r_filter = pendulum.parse(date) - motd = await utils.get_content('motd', r_filter) + motd = await utils.get_content('motd', str(pendulum.parse(date).date())) date = motd[0]['date'] motd = motd[0]['motd'] fmt = "Message of the day for {}:\n\n{}".format(date, motd) diff --git a/cogs/da.py b/cogs/da.py index 8d74d31..0ea42d5 100644 --- a/cogs/da.py +++ b/cogs/da.py @@ -101,9 +101,8 @@ class Deviantart: await user.send(fmt) # Now we can update the user's last updated for this DA # We want to do this whether or not our last if statement was met - r_filter = {'member_id': user.id} update = {'last_updated': {da_name: result['deviationid']}} - await utils.update_content('deviantart', update, r_filter) + await utils.update_content('deviantart', update, str(user.id)) except Exception as e: tb = traceback.format_exc() fmt = "{1}\n{0.__class__.__name__}: {0}".format(tb, e) @@ -124,13 +123,13 @@ class Deviantart: EXAMPLE: !da sub MyFavoriteArtistEva<3 RESULT: Notifications of amazing pics c:""" - r_filter = {'member_id': ctx.message.author.id} - content = await utils.get_content('deviantart', r_filter) + key = str(ctx.message.author.id) + content = await utils.get_content('deviantart', key) # TODO: Ensure the user provided is a real user if content is None: entry = {'member_id': ctx.message.author.id, 'subbed': [username], 'last_updated': {}} - await utils.add_content('deviantart', entry, r_filter) + await utils.add_content('deviantart', entry) await ctx.send("You have just subscribed to {}!".format(username)) elif content[0]['subbed'] is None or username not in content[0]['subbed']: if content[0]['subbed'] is None: @@ -138,7 +137,7 @@ class Deviantart: else: content[0]['subbed'].append(username) sub_list = content[0]['subbed'] - await utils.update_content('deviantart', {'subbed': sub_list}, r_filter) + await utils.update_content('deviantart', {'subbed': sub_list}, key) await ctx.send("You have just subscribed to {}!".format(username)) else: await ctx.send("You are already subscribed to that user!") @@ -150,14 +149,14 @@ class Deviantart: EXAMPLE: !da unsub TheArtistWhoBetrayedMe RESULT: No more pics from that terrible person!""" - r_filter = {'member_id': ctx.message.author.id} - content = await utils.get_content('deviantart', r_filter) + key = str(ctx.message.author.id) + content = await utils.get_content('deviantart', key) if content is None or content[0]['subbed'] is None: await ctx.send("You are not subscribed to anyone at the moment!") elif username in content[0]['subbed']: content[0]['subbed'].remove(username) - await utils.update_content('deviantart', {'subbed': content[0]['subbed']}, r_filter) + await utils.update_content('deviantart', {'subbed': content[0]['subbed']}, key) await ctx.send("You have just unsubscribed from {}!".format(username)) else: await ctx.send("You are not subscribed to that user!") diff --git a/cogs/events.py b/cogs/events.py index 1e8f86e..8222a6c 100644 --- a/cogs/events.py +++ b/cogs/events.py @@ -54,16 +54,15 @@ class StatsUpdate: async def on_member_join(self, member): guild = member.guild - r_filter = {'server_id': guild.id} - notifications = await config.get_content('user_notifications', r_filter) + server_settings = await config.get_content('server_settings', guild.id) try: - channel_id = notifications[0]['channel_id'] - except TypeError: - return - - # By default, notifications should be off unless explicitly turned on - if not channel_id: + join_leave_on = server_settings[0]['join_leave'] + if join_leave_on: + channel_id = server_settings[0]['notification_channel'] or member.guild.id + else: + return + except (IndexError, TypeError): return channel = guild.get_channel(channel_id) @@ -71,20 +70,19 @@ class StatsUpdate: async def on_member_remove(self, member): guild = member.guild - r_filter = {'server_id': guild.id} - notifications = await config.get_content('user_notifications', r_filter) + server_settings = await config.get_content('server_settings', guild.id) try: - channel_id = notifications[0]['channel_id'] - except TypeError: + join_leave_on = server_settings[0]['join_leave'] + if join_leave_on: + channel_id = server_settings[0]['notification_channel'] or member.guild.id + else: + return + except (IndexError, TypeError): return - # By default, notifications should be off unless explicitly turned on - if not channel_id: - return - - channel = server.get_channel(channel_id) - await channelsend("{0} has left the server, I hope it wasn't because of something I said :c".format(member.display_name)) + channel = guild.get_channel(channel_id) + await channel.send("{0} has left the server, I hope it wasn't because of something I said :c".format(member.display_name)) def setup(bot): diff --git a/cogs/interaction.py b/cogs/interaction.py index ff1cae5..5c938f9 100644 --- a/cogs/interaction.py +++ b/cogs/interaction.py @@ -258,20 +258,20 @@ class Interaction: await ctx.send("Why the heck are you booping me? Get away from me >:c") return - r_filter = {'member_id': booper.id} - boops = await utils.get_content('boops', r_filter) + key = str(booper.id) + boops = await utils.get_content('boops', key) if boops is not None: boops = boops[0]['boops'] # If the booper has never booped the member provided, assure it's 0 amount = boops.get(boopee.id, 0) + 1 boops[boopee.id] = amount - await utils.update_content('boops', {'boops': boops}, r_filter) + await utils.update_content('boops', {'boops': boops}, key) else: entry = {'member_id': booper.id, 'boops': {boopee.id: 1}} - await utils.add_content('boops', entry, r_filter) + await utils.add_content('boops', entry) amount = 1 fmt = "{0.mention} has just booped {1.mention}{3}! That's {2} times now!" diff --git a/cogs/links.py b/cogs/links.py index e8f0b80..60d6b18 100644 --- a/cogs/links.py +++ b/cogs/links.py @@ -29,9 +29,8 @@ class Links: url = "https://www.google.com/search" # Turn safe filter on or off, based on whether or not this is a nsfw channel - r_filter = {'channel_id': ctx.message.channel.id} - nsfw_channels = await utils.get_content("nsfw_channels", r_filter) - safe = 'off' if nsfw_channels else 'on' + nsfw = await utils.channel_is_nsfw(ctx.message.channel) + safe = 'off' if nsfw else 'on' params = {'q': query, 'safe': safe, @@ -191,12 +190,11 @@ class Links: query = ' '.join(value for value in search if not re.search('&?filter_id=[0-9]+', value)) params = {'q': query} - r_filter = {'channel_id': ctx.message.channel.id} - nsfw_channels = await utils.get_content("nsfw_channels", r_filter) + nsfw = await utils.channel_is_nsfw(ctx.message.channel) # If this is a nsfw channel, we just need to tack on 'explicit' to the terms # Also use the custom filter that I have setup, that blocks some certain tags # If the channel is not nsfw, we don't need to do anything, as the default filter blocks explicit - if nsfw_channels is not None: + if nsfw: params['q'] += ", (explicit OR suggestive)" params['filter_id'] = 95938 else: @@ -262,12 +260,11 @@ class Links: params = {'limit': 320, 'tags': tags} - r_filter = {'channel_id': ctx.message.channel.id} - nsfw_channels = await utils.get_content("nsfw_channels", r_filter) + nsfw = await utils.channel_is_nsfw(ctx.message.channel) # e621 by default does not filter explicit content, so tack on # safe/explicit based on if this channel is nsfw or not - params['tags'] += " rating:explicit" if nsfw_channels else " rating:safe" + params['tags'] += " rating:explicit" if nsfw else " rating:safe" data = await utils.request(url, payload=params) diff --git a/cogs/mod.py b/cogs/mod.py index 04e3be2..1bb880c 100644 --- a/cogs/mod.py +++ b/cogs/mod.py @@ -99,19 +99,19 @@ class Mod: except discord.HTTPException: await ctx.send("Sorry, I failed to ban that user!") - @commands.command(no_pm=True) + @commands.command(no_pm=True, aliases=['alerts']) @utils.custom_perms(kick_members=True) - async def alerts(self, ctx, channel: discord.TextChannel): + async def notifications(self, ctx, channel: discord.TextChannel): """This command is used to set a channel as the server's 'notifications' channel Any notifications (like someone going live on Twitch, or Picarto) will go to that channel EXAMPLE: !alerts #alerts RESULT: No more alerts spammed in #general!""" - r_filter = {'server_id': ctx.message.guild.id} + key = ctx.message.guild.id entry = {'server_id': ctx.message.guild.id, - 'channel_id': channel.id} - if not await utils.add_content('server_alerts', entry, r_filter): - await utils.update_content('server_alerts', entry, r_filter) + 'notification_channel': channel.id} + if not await utils.update_content('server_alerts', entry, key): + await utils.add_content('server_alerts', entry) await ctx.send("I have just changed this server's 'notifications' channel" "\nAll notifications will now go to `{}`".format(channel)) @@ -119,7 +119,6 @@ class Mod: @utils.custom_perms(kick_members=True) async def usernotify(self, ctx, on_off: str): """This command can be used to set whether or not you want user notificaitons to show - This will save what channel you run this command in, that will be the channel used to send the notification to Provide on, yes, or true to set it on; otherwise it will be turned off EXAMPLE: !usernotify on @@ -127,12 +126,13 @@ class Mod: # Join/Leave notifications can be kept separate from normal alerts # So we base this channel on it's own and not from alerts # When mod logging becomes available, that will be kept to it's own channel if wanted as well - on_off = ctx.message.channel.id if re.search("(on|yes|true)", on_off.lower()) else None - r_filter = {'server_id': ctx.message.guild.id} + on_off = True if re.search("(on|yes|true)", on_off.lower()) else False + key = ctx.message.guild.id entry = {'server_id': ctx.message.guild.id, - 'channel_id': on_off} - if not await utils.add_content('user_notifications', entry, r_filter): - await utils.update_content('user_notifications', entry, r_filter) + 'join_leave': on_off} + if not await utils.update_content('user_notifications', entry, key): + await utils.add_content('user_notifications', entry) + fmt = "notify" if on_off else "not notify" await ctx.send("This server will now {} if someone has joined or left".format(fmt)) @@ -149,11 +149,20 @@ class Mod: EXAMPLE: !nsfw add RESULT: ;)""" - r_filter = {'channel_id': ctx.message.channel.id} - if await utils.add_content('nsfw_channels', r_filter, r_filter): - await ctx.send("This channel has just been registered as 'nsfw'! Have fun you naughties ;)") + key = ctx.message.guild.id + entry = {'server_id': key, + 'nsfw_channels': [ctx.message.channel.id]} + update = {'nsfw_channels': r.row['nsfw_channels'].append(ctx.message.channel.id)} + + server_settings = await utils.get_content('server_settings', key) + if server_settings and 'nsfw_channels' in server_settings[0].keys(): + await utils.update_content('server_settings', update, key) + elif server_settings: + await utils.update_content('server_settings', entry, key) else: - await ctx.send("This channel is already registered as 'nsfw'!") + await utils.add_content('server_settings', entry, key) + + await ctx.send("This channel has just been registered as 'nsfw'! Have fun you naughties ;)") @nsfw.command(name="remove", aliases=["delete"]) @utils.custom_perms(kick_members=True) @@ -162,11 +171,23 @@ class Mod: EXAMPLE: !nsfw remove RESULT: ;(""" - r_filter = {'channel_id': ctx.message.channel.id} - if await utils.remove_content('nsfw_channels', r_filter): - await ctx.send("This channel has just been unregistered as a nsfw channel") - else: - await ctx.send("This channel is not registered as a ''nsfw' channel!") + + key = ctx.message.guild.id + server_settings = await utils.get_content('server_settings', key) + channel = ctx.message.channel.id + try: + channels = server_settings[0]['nsfw_channels'] + if channel in channels: + channels.remove(channel) + + entry = {'nsfw_channels': channels} + await utils.update_content('server_settings', entry, key) + await ctx.send("This channel has just been unregistered as a nsfw channel") + return + except (TypeError, IndexError): + pass + + await ctx.send("This channel is not registered as a 'nsfw' channel!") @commands.command() @utils.custom_perms(kick_members=True) @@ -195,18 +216,18 @@ class Mod: "Valid permissions are: ```\n{}```".format("\n".join("{}".format(i) for i in valid_perms))) return - r_filter = {'server_id': ctx.message.guild.id} - server_perms = await utils.get_content('custom_permissions', r_filter) - try: - server_perms = server_perms[0] - except TypeError: - server_perms = {} cmd = self.bot.get_command(command) if cmd is None: await ctx.send("That is not a valid command!") return + server_settings = await utils.get_content('server_settings', ctx.message.guild.id) + try: + server_perms = server_settings[0]['permissions'] + except (TypeError, IndexError): + server_perms = {} + perms_value = server_perms.get(cmd.qualified_name) if perms_value is None: # If we don't find custom permissions, get the required permission for a command @@ -257,6 +278,13 @@ class Mod: "`perms add `") return + cmd = self.bot.get_command(command) + + if cmd is None: + await ctx.send( + "That command does not exist! You can't have custom permissions on a non-existant command....") + return + # If a user can run a command, they have to have send_messages permissions; so use this as the base if permissions.lower() == "none": permissions = "send_messages" @@ -272,13 +300,6 @@ class Mod: return perm_value = perm_obj.value - cmd = self.bot.get_command(command) - - if cmd is None: - await ctx.send( - "That command does not exist! You can't have custom permissions on a non-existant command....") - return - # Two cases I use should never have custom permissions setup on them, is_owner for obvious reasons # The other case is if I'm using the default has_permissions case # Which means I do not want to check custom permissions at all @@ -288,19 +309,13 @@ class Mod: await ctx.send("This command cannot have custom permissions setup!") return - r_filter = {'server_id': ctx.message.guild.id} + key = ctx.message.guild.id entry = {'server_id': ctx.message.guild.id, - cmd.qualified_name: perm_value} + 'permissions': {cmd.qualified_name: perm_value}} - # In all other cases, I've used add_content before update_content - # In this case, I'm going the other way around, to make the least queries - # As custom permissions are probably going to be ran multiple times per server - # Whereas in most other cases, the command is probably going to be ran once/few times per server - if not await utils.update_content('custom_permissions', entry, r_filter): - await utils.add_content('custom_permissions', entry, r_filter) + if not await utils.update_content('server_settings', entry, key): + await utils.add_content('server_settings', entry) - # Same case as prefixes, for now, trigger a manual update - self.bot.loop.create_task(utils.cache['custom_permissions'].update()) await ctx.send("I have just added your custom permissions; " "you now need to have `{}` permissions to use the command `{}`".format(permissions, command)) @@ -319,13 +334,10 @@ class Mod: "That command does not exist! You can't have custom permissions on a non-existant command....") return - r_filter = {'server_id': ctx.message.guild.id} - await utils.replace_content('custom_permissions', r.row.without(cmd.qualified_name), r_filter) + update = {'permissions': {cmd.qualified_name: None}} + await utils.update_content('custom_permissions', update, ctx.message.guild.id) await ctx.send("I have just removed the custom permissions for {}!".format(cmd)) - # Same case as prefixes, for now, trigger a manual update - self.bot.loop.create_task(utils.cache['custom_permissions'].update()) - @commands.command(no_pm=True) @utils.custom_perms(manage_guild=True) async def prefix(self, ctx, *, prefix: str): @@ -333,15 +345,15 @@ class Mod: EXAMPLE: !prefix new_prefix RESULT: You probably screwing it up and not realizing you now need to do new_prefixprefix""" - r_filter = {'server_id': ctx.message.guild.id} + key = ctx.message.guild.id if prefix.lower().strip() == "none": prefix = None entry = {'server_id': ctx.message.guild.id, 'prefix': prefix} - if not await utils.add_content('prefixes', entry, r_filter): - await utils.update_content('prefixes', entry, r_filter) + if not await utils.update_content('server_settings', entry, key): + await utils.add_content('prefixes', entry) if prefix is None: fmt = "I have just cleared your custom prefix, the default prefix will have to be used now" @@ -439,16 +451,14 @@ class Mod: EXAMPLE: !rules 5 RESULT: Rule 5 is printed""" - r_filter = {'server_id': ctx.message.guild.id} - rules = await utils.get_content('rules', r_filter) - try: - rules = rules[0]['rules'] - except TypeError: - await ctx.send("This server currently has no rules on it! I see you like to live dangerously...") - return - if len(rules) == 0: + server_settings = await utils.get_content('server_settings', ctx.message.guild.id) + rules = server_settings['rules'] + + if not rules or len(rules) == 0: await ctx.send("This server currently has no rules on it! I see you like to live dangerously...") return + else: + rules = rules[0] if rule is None: try: @@ -472,12 +482,18 @@ class Mod: EXAMPLE: !rules add No fun allowed in this server >:c RESULT: No more fun...unless they break the rules!""" - r_filter = {'server_id': ctx.message.guild.id} + key = ctx.message.guild.id entry = {'server_id': ctx.message.guild.id, 'rules': [rule]} update = {'rules': r.row['rules'].append(rule)} - if not await utils.update_content('rules', update, r_filter): - await utils.add_content('rules', entry, r_filter) + + server_settings = await utils.get_content('server_settings', key) + if server_settings and 'rules' in server_settings[0].keys(): + await utils.update_content('server_settings', update, key) + elif server_settings: + await utils.update_content('server_settings', entry, key) + else: + await utils.add_content('server_settings', entry) await ctx.send("I have just saved your new rule, use the rules command to view this server's current rules") @@ -489,9 +505,8 @@ class Mod: EXAMPLE: !rules delete 5 RESULT: Freedom from opression!""" - r_filter = {'server_id': ctx.message.guild.id} update = {'rules': r.row['rules'].delete_at(rule - 1)} - if not await utils.update_content('rules', update, r_filter): + if not await utils.update_content('server_settings', update, ctx.message.guild.id): await ctx.send("That is not a valid rule number, try running the command again.") else: await ctx.send("I have just removed that rule from your list of rules!") diff --git a/cogs/overwatch.py b/cogs/overwatch.py index 926a8fd..689f64b 100644 --- a/cogs/overwatch.py +++ b/cogs/overwatch.py @@ -38,8 +38,7 @@ class Overwatch: await ctx.message.channel.trigger_typing() user = user or ctx.message.author - r_filter = {'member_id': user.id} - ow_stats = await utils.get_content('overwatch', r_filter) + ow_stats = await utils.get_content('overwatch', user.id) if ow_stats is None: await ctx.send("I do not have this user's battletag saved!") @@ -96,7 +95,7 @@ class Overwatch: # Battletags are normally provided like name#id # However the API needs this to be a -, so repliace # with - if it exists bt = bt.replace("#", "-") - r_filter = {'member_id': ctx.message.author.id} + key = ctx.message.author.id # This API sometimes takes a while to look up information, so send a message saying we're processing await ctx.send("Looking up your profile information....") @@ -113,8 +112,8 @@ class Overwatch: entry = {'member_id': ctx.message.author.id, 'battletag': bt} update = {'battletag': bt} # Try adding this first, if that fails, update the saved entry - if not await utils.add_content('overwatch', entry, r_filter): - await utils.update_content('overwatch', update, r_filter) + if not await utils.add_content('overwatch', entry): + await utils.update_content('overwatch', update, key) await ctx.send("I have just saved your battletag {}".format(ctx.message.author.mention)) @ow.command(pass_context=True, name="delete", aliases=['remove']) @@ -124,8 +123,7 @@ class Overwatch: EXAMPLE: !ow delete RESULT: Your battletag is no longer saved""" - r_filter = {'member_id': ctx.message.author.id} - if await utils.remove_content('overwatch', r_filter): + if await utils.remove_content('overwatch', ctx.message.author.id): await ctx.send("I no longer have your battletag saved {}".format(ctx.message.author.mention)) else: await ctx.send("I don't even have your battletag saved {}".format(ctx.message.author.mention)) diff --git a/cogs/owner.py b/cogs/owner.py index 1afe1d0..9eaf326 100644 --- a/cogs/owner.py +++ b/cogs/owner.py @@ -22,12 +22,12 @@ class Owner: async def motd_push(self, ctx, *, message): """Used to push a new message to the message of the day""" date = pendulum.utcnow().to_date_string() - r_filter = {'date': date} + key = date entry = {'motd': message, 'date': date} # Try to add this, if there's an entry for that date, lets update it to make sure only one motd is sent a day # I should be managing this myself, more than one should not be sent in a day - if await utils.add_content('motd', entry, r_filter): - await utils.update_content('motd', entry, r_filter) + if await utils.add_content('motd', entry): + await utils.update_content('motd', entry, key) await ctx.send("New motd update for {}!".format(date)) @commands.command() diff --git a/cogs/picarto.py b/cogs/picarto.py index fd86146..728e905 100644 --- a/cogs/picarto.py +++ b/cogs/picarto.py @@ -51,7 +51,7 @@ class Picarto: try: while not self.bot.is_closed: r_filter = {'notifications_on': 1} - picarto = await utils.get_content('picarto', r_filter) + picarto = await utils.filter_content('picarto', r_filter) # Get all online users before looping, so that only one request is needed online_users_list = await online_users() old_online_users = {data['member_id']: data for data in picarto if data['live']} @@ -123,8 +123,7 @@ class Picarto: RESULT: Info about their picarto stream""" # If member is not given, base information on the author member = member or ctx.message.author - r_filter = {'member_id': member.id} - picarto_entry = await utils.get_content('picarto', r_filter) + picarto_entry = await utils.get_content('picarto', member.id) if picarto_entry is None: await ctx.send("That user does not have a picarto url setup!") return @@ -184,26 +183,25 @@ class Picarto: "user? Silly") return - r_filter = {'member_id': ctx.message.author.id} + key = ctx.message.author.id entry = {'picarto_url': url, 'servers': [ctx.message.guild.id], 'notifications_on': 1, 'live': 0, 'member_id': ctx.message.author.id} - if await utils.add_content('picarto', entry, r_filter): + if await utils.add_content('picarto', entry): await ctx.send( "I have just saved your Picarto URL {}, this guild will now be notified when you go live".format( ctx.message.author.mention)) else: - await utils.update_content('picarto', {'picarto_url': url}, r_filter) + await utils.update_content('picarto', {'picarto_url': url}, key) await ctx.send("I have just updated your Picarto URL") @picarto.command(name='remove', aliases=['delete'], no_pm=True) @utils.custom_perms(send_messages=True) async def remove_picarto_url(self, ctx): """Removes your picarto URL""" - r_filter = {'member_id': ctx.message.author.id} - if await utils.remove_content('picarto', r_filter): + if await utils.remove_content('picarto', ctx.message.author.id): await ctx.send("I am no longer saving your picarto URL {}".format(ctx.message.author.mention)) else: await ctx.send( @@ -218,8 +216,7 @@ class Picarto: EXAMPLE: !picarto notify RESULT: This guild will now be notified of you going live""" - r_filter = {'member_id': ctx.message.author.id} - result = await utils.get_content('picarto', r_filter) + result = await utils.get_content('picarto', ctx.message.author.id) # Check if this user is saved at all if result is None: await ctx.send( @@ -230,7 +227,7 @@ class Picarto: await ctx.send("I am already set to notify in this guild...") else: await utils.update_content('picarto', {'servers': r.row['servers'].append(ctx.message.guild.id)}, - r_filter) + ctx.message.author.id) @notify.command(name='on', aliases=['start,yes'], no_pm=True) @utils.custom_perms(send_messages=True) @@ -239,8 +236,7 @@ class Picarto: EXAMPLE: !picarto notify on RESULT: Notifications are sent when you go live""" - r_filter = {'member_id': ctx.message.author.id} - await utils.update_content('picarto', {'notifications_on': 1}, r_filter) + await utils.update_content('picarto', {'notifications_on': 1}, ctx.message.author.id) await ctx.send("I will notify if you go live {}, you'll get a bajillion followers I promise c:".format( ctx.message.author.mention)) @@ -251,8 +247,7 @@ class Picarto: EXAMPLE: !picarto notify off RESULT: No more notifications sent when you go live""" - r_filter = {'member_id': ctx.message.author.id} - await utils.update_content('picarto', {'notifications_on': 0}, r_filter) + await utils.update_content('picarto', {'notifications_on': 0}, ctx.message.author.id) await ctx.send( "I will not notify if you go live anymore {}, " "are you going to stream some lewd stuff you don't want people to see?~".format( diff --git a/cogs/raffle.py b/cogs/raffle.py index 6a30db6..bf555a3 100644 --- a/cogs/raffle.py +++ b/cogs/raffle.py @@ -74,8 +74,7 @@ class Raffle: # No matter which one of these matches were met, the raffle has ended and we want to remove it # We don't have to wait for it however, so create a task for it - r_filter = {'id': raffle_id} - self.bot.loop.create_task(utils.remove_content('raffles', r_filter)) + self.bot.loop.create_task(utils.remove_content('raffles', raffle_id)) try: await server.send(fmt) except discord.Forbidden: @@ -89,7 +88,7 @@ class Raffle: EXAMPLE: !raffles RESULT: A list of the raffles setup on this server""" r_filter = {'server_id': ctx.message.guild.id} - raffles = await utils.get_content('raffles', r_filter) + raffles = await utils.filter_content('raffles', r_filter) if raffles is None: await ctx.send("There are currently no raffles setup on this server!") return @@ -114,7 +113,7 @@ class Raffle: r_filter = {'server_id': ctx.message.guild.id} author = ctx.message.author - raffles = await utils.get_content('raffles', r_filter) + raffles = await utils.filter_content('raffles', r_filter) if raffles is None: await ctx.send("There are currently no raffles setup on this server!") return @@ -130,10 +129,8 @@ class Raffle: return entrants.append(author.id) - # Since we have no good thing to filter things off of, lets use the internal rethinkdb id - r_filter = {'id': raffles[0]['id']} update = {'entrants': entrants} - await utils.update_content('raffles', update, r_filter) + await utils.update_content('raffles', update, raffles[0]['id']) await ctx.send("{} you have just entered the raffle!".format(author.mention)) # Otherwise, make sure the author gave a valid raffle_id elif raffle_id in range(raffle_count - 1): @@ -146,9 +143,8 @@ class Raffle: entrants.append(author.id) # Since we have no good thing to filter things off of, lets use the internal rethinkdb id - r_filter = {'id': raffles[raffle_id]['id']} update = {'entrants': entrants} - await utils.update_content('raffles', update, r_filter) + await utils.update_content('raffles', update, raffles[raffle_id]['id']) await ctx.send("{} you have just entered the raffle!".format(author.mention)) else: fmt = "Please provide a valid raffle ID, as there are more than one setup on the server! " \ diff --git a/cogs/stats.py b/cogs/stats.py index 8269349..53a448c 100644 --- a/cogs/stats.py +++ b/cogs/stats.py @@ -61,8 +61,7 @@ class Stats: await ctx.send("`{}` is not a valid command".format(command)) return - r_filter = {'command': cmd.qualified_name} - command_stats = await utils.get_content('command_usage', r_filter) + command_stats = await utils.get_content('command_usage', cmd.qualified_name) try: command_stats = command_stats[0] except TypeError: @@ -140,8 +139,7 @@ class Stats: EXAMPLE: !mostboops RESULT: You've booped @OtherPerson 351253897120935712093572193057310298 times!""" - r_filter = {'member_id': ctx.message.author.id} - boops = await utils.get_content('boops', r_filter) + boops = await utils.get_content('boops', ctx.message.author.id) if boops is None: await ctx.send("You have not booped anyone {} Why the heck not...?".format(ctx.message.author.mention)) return @@ -171,8 +169,7 @@ class Stats: EXAMPLE: !listboops RESULT: The list of your booped members!""" - r_filter = {'member_id': ctx.message.author.id} - boops = await utils.get_content('boops', r_filter) + boops = await utils.get_content('boops', ctx.message.author.id) if boops is None: await ctx.send("You have not booped anyone {} Why the heck not...?".format(ctx.message.author.mention)) return diff --git a/cogs/strawpoll.py b/cogs/strawpoll.py index f121ce8..1b038f1 100644 --- a/cogs/strawpoll.py +++ b/cogs/strawpoll.py @@ -131,7 +131,7 @@ class Strawpoll: 'polls': [sub_entry]} update = {'polls': r.row['polls'].append(sub_entry)} if not await config.update_content('strawpolls', update, r_filter): - await config.add_content('strawpolls', entry, {'poll_id': poll_id}) + await config.add_content('strawpolls', entry) await ctx.send("Link for your new strawpoll: https://strawpoll.me/{}".format(poll_id)) @strawpolls.command(name='delete', aliases=['remove', 'stop'], pass_context=True, no_pm=True) diff --git a/cogs/tags.py b/cogs/tags.py index 4b10471..01f9961 100644 --- a/cogs/tags.py +++ b/cogs/tags.py @@ -35,7 +35,7 @@ class Tags: EXAMPLE: !tag butts RESULT: Whatever you setup for the butts tag!!""" r_filter = lambda row: (row['server_id'] == ctx.message.guild.id) & (row['tag'] == tag) - tags = await utils.get_content('tags', r_filter) + tags = await utils.filter_content('tags', r_filter) if tags is None: await ctx.send('That tag does not exist!') return @@ -73,13 +73,11 @@ class Tags: entry = {'server_id': ctx.message.guild.id, 'tag': tag, 'result': tag_result} r_filter = lambda row: (row['server_id'] == ctx.message.guild.id) & (row['tag'] == tag) # Try to create new entry first, if that fails (it already exists) then we update it - if await utils.add_content('tags', entry, r_filter): + if await utils.filter_content('tags', entry, r_filter): await ctx.send( "I have just added the tag `{0}`! You can call this tag by entering !tag {0}".format(tag)) else: - await utils.update_content('tags', entry, r_filter) - await ctx.send( - "I have just updated the tag `{0}`! You can call this tag by entering !tag {0}".format(tag)) + await ctx.send("That tag already exists!") @tag.command(name='delete', aliases=['remove', 'stop'], no_pm=True) @utils.custom_perms(kick_members=True) @@ -89,12 +87,14 @@ class Tags: EXAMPLE: !tag delete stupid_tag RESULT: Deletes that stupid tag""" - r_filter = lambda row: (row['server_id'] == ctx.message.guild.id) & (row['tag'] == tag) + await ctx.send("Temporarily disabled") + // TODO: Fix tags, this will inherently fix this method + """r_filter = lambda row: (row['server_id'] == ctx.message.guild.id) & (row['tag'] == tag) if await utils.remove_content('tags', r_filter): await ctx.send('I have just removed the tag `{}`'.format(tag)) else: await ctx.send( - "The tag {} does not exist! You can't remove something if it doesn't exist...".format(tag)) + "The tag {} does not exist! You can't remove something if it doesn't exist...".format(tag))""" def setup(bot): diff --git a/cogs/twitch.py b/cogs/twitch.py index 365cc23..1b441eb 100644 --- a/cogs/twitch.py +++ b/cogs/twitch.py @@ -45,7 +45,7 @@ class Twitch: # Loop through as long as the bot is connected try: while not self.bot.is_closed: - twitch = await utils.get_content('twitch', {'notifications_on': 1}) + twitch = await utils.filter_content('twitch', {'notifications_on': 1}) # Online/offline is based on whether they are set to such, in the utils file # This means they were detected as online/offline before and we check for a change online_users = {data['member_id']: data for data in twitch if data['live']} @@ -61,7 +61,7 @@ class Twitch: server = self.bot.get_server(server_id) if server is None: continue - server_alerts = await utils.get_content('server_alerts', {'server_id': server_id}) + server_alerts = await utils.get_content('server_alerts', server_id) try: channel_id = server_alerts[0]['channel_id'] except (IndexError, TypeError): @@ -161,7 +161,7 @@ class Twitch: "What would be the point of adding a nonexistant twitch user? Silly") return - r_filter = {'member_id': ctx.message.author.id} + key = ctx.message.author.id entry = {'twitch_url': url, 'servers': [ctx.message.guild.id], 'notifications_on': 1, @@ -172,8 +172,8 @@ class Twitch: # Check to see if this user has already saved a twitch URL # If they have, update the URL, otherwise create a new entry # Assuming they're not live, and notifications should be on - if not await utils.add_content('twitch', entry, r_filter): - await utils.update_content('twitch', update, r_filter) + if not await utils.add_content('twitch', entry): + await utils.update_content('twitch', update, key) await ctx.send("I have just saved your twitch url {}".format(ctx.message.author.mention)) @twitch.command(name='remove', aliases=['delete'], no_pm=True) @@ -184,8 +184,7 @@ class Twitch: EXAMPLE: !twitch remove RESULT: I stop saving your twitch URL""" # Just try to remove it, if it doesn't exist, nothing is going to happen - r_filter = {'member_id': ctx.message.author.id} - await utils.remove_content('twitch', r_filter) + await utils.remove_content('twitch', ctx.message.author.id) await ctx.send("I am no longer saving your twitch URL {}".format(ctx.message.author.mention)) @twitch.group(no_pm=True, invoke_without_command=True) @@ -196,8 +195,8 @@ class Twitch: EXAMPLE: !twitch notify RESULT: This server will now be notified when you go live""" - r_filter = {'member_id': ctx.message.author.id} - result = await utils.get_content('twitch', r_filter) + key = ctx.message.author.id + result = await utils.get_content('twitch', key) # Check if this user is saved at all if result is None: await ctx.send( @@ -207,7 +206,7 @@ class Twitch: elif ctx.message.guild.id in result[0]['servers']: await ctx.send("I am already set to notify in this server...") else: - await utils.update_content('twitch', {'servers': r.row['servers'].append(ctx.message.guild.id)}, r_filter) + await utils.update_content('twitch', {'servers': r.row['servers'].append(ctx.message.guild.id)}, key) await ctx.send("This server will now be notified if you go live") @notify.command(name='on', aliases=['start,yes'], no_pm=True) @@ -217,8 +216,7 @@ class Twitch: EXAMPLE: !twitch notify on RESULT: Notifications will be sent when you go live""" - r_filter = {'member_id': ctx.message.author.id} - if await utils.update_content('twitch', {"notifications_on": 1}, r_filter): + if await utils.update_content('twitch', {"notifications_on": 1}, ctx.message.author.id): await ctx.send("I will notify if you go live {}, you'll get a bajillion followers I promise c:".format( ctx.message.author.mention)) else: @@ -231,8 +229,7 @@ class Twitch: EXAMPLE: !twitch notify off RESULT: Notifications will not be sent when you go live""" - r_filter = {'member_id': ctx.message.author.id} - if await utils.update_content('twitch', {"notifications_on": 1}, r_filter): + if await utils.update_content('twitch', {"notifications_on": 1}, ctx.message.author.id): await ctx.send( "I will not notify if you go live anymore {}, " "are you going to stream some lewd stuff you don't want people to see?~".format( diff --git a/cogs/utils/checks.py b/cogs/utils/checks.py index 8b32c92..69f5c0a 100644 --- a/cogs/utils/checks.py +++ b/cogs/utils/checks.py @@ -7,10 +7,22 @@ from . import config loop = asyncio.get_event_loop() -# The list of tables needed for the database -table_list = ['battle_records', 'battling', 'boops', 'bot_data', 'command_usage', 'custom_permissions', - 'deviantart', 'motd', 'nsfw_channels', 'overwatch', 'picarto', 'prefixes', 'raffles', - 'rules', 'server_alerts', 'strawpolls', 'tags', 'tictactoe', 'twitch', 'user_notifications'] +# The tables needed for the database, as well as their primary keys +required_tables = { + 'battle_records': 'member_id', + 'boops': 'member_id', + 'command_usage': 'command', + 'deviantart': 'member_id', + 'motd': 'date', + 'overwatch': 'member_id', + 'picarto': 'member_id', + 'server_settings': 'guild_id', + 'raffles': 'id', + 'strawpolls': 'guild_id', + 'tags': 'guild_id', + 'tictactoe': 'member_id', + 'twitch': 'member_id' +} async def db_check(): @@ -36,17 +48,17 @@ async def db_check(): print('Couldn\'t find database {}...creating now'.format(db_opts['db'])) await r.db_create(db_opts['db']).run(conn) # Then add all the tables - for table in table_list: + for table, key in required_tables.items(): print("Creating table {}...".format(table)) - await r.table_create(table).run(conn) + await r.table_create(table, primary_key=key).run(conn) print("Done!") else: # Otherwise, if the database is setup, make sure all the required tables are there tables = await r.table_list().run(conn) - for table in table_list: + for table, key in required_tables.items(): if table not in tables: print("Creating table {}...".format(table)) - await r.table_create(table).run(conn) + await r.table_create(table, primary_key=key).run(conn) print("Done checking tables!") @@ -68,15 +80,12 @@ def custom_perms(**perms): for perm, setting in perms.items(): setattr(required_perm, perm, setting) - perm_values = config.cache.get('custom_permissions').values - - # Loop through and find this server's entry for custom permissions - # Find the command we're using, if it exists, then overwrite - # The required permissions, based on the value saved - if perm_values: - for x in perm_values: - if x['server_id'] == ctx.message.guild.id and x.get(ctx.command.qualified_name): - required_perm = discord.Permissions(x[ctx.command.qualified_name]) + server_settings = config.cache.get('server_settings').values[ctx.message.guild.id] + try: + required_perm_value = server_settings['permissions'][ctx.command.qualified_name] + required_perm = discord.Permissions(required_perm_value) + except (TypeError, IndexError): + pass # Now just check if the person running the command has these permissions return member_perms >= required_perm diff --git a/cogs/utils/config.py b/cogs/utils/config.py index 4270626..4978dc4 100644 --- a/cogs/utils/config.py +++ b/cogs/utils/config.py @@ -106,7 +106,7 @@ cache = {} # We still need 'cache' for prefixes and custom permissions however, so for now, just include that cache['prefixes'] = Cache('prefixes') -cache['custom_permissions'] = Cache('custom_permissions') +cache['server_settings'] = Cache('server_settings') async def update_cache(): for value in cache.values(): @@ -119,56 +119,45 @@ def command_prefix(bot, message): # If the prefix does exist in the database and isn't in our cache; too bad, something has messed up # But it is not worth a query for every single message the bot detects, to fix try: - values = cache['prefixes'].values - prefix = [data['prefix'] for data in values if message.guild.id == data['server_id']][0] + prefix = cache['server_settings'].values[message.guild.id]['prefix'] return prefix or default_prefix except (KeyError, TypeError, IndexError, AttributeError): return default_prefix -async def add_content(table, content, r_filter=None): +async def add_content(table, content): r.set_loop_type("asyncio") conn = await r.connect(**db_opts) # First we need to make sure that this entry doesn't exist # For all rethinkDB cares, multiple entries can exist with the same content # For our purposes however, we do not want this try: - if r_filter is not None: - cursor = await r.table(table).filter(r_filter).run(conn) - cur_content = await _convert_to_list(cursor) - if len(cur_content) > 0: - await conn.close() - return False - await r.table(table).insert(content).run(conn) + result = await r.table(table).insert(content).run(conn) await conn.close() - return True except r.ReqlOpFailedError: # This means the table does not exist await r.table_create(table).run(conn) await r.table(table).insert(content).run(conn) await conn.close() - return True + result = {} + return result.get('inserted', 0) > 0 -async def remove_content(table, r_filter=None): - if r_filter is None: - r_filter = {} +async def remove_content(table, key): r.set_loop_type("asyncio") conn = await r.connect(**db_opts) try: - result = await r.table(table).filter(r_filter).delete().run(conn) + result = await r.table(table).get(key).delete().run(conn) except r.ReqlOpFailedError: result = {} pass await conn.close() - if table == 'prefixes' or table == 'custom_permissions': + if table == 'prefixes' or table == 'server_settings': loop.create_task(cache[table].update()) return result.get('deleted', 0) > 0 -async def update_content(table, content, r_filter=None): - if r_filter is None: - r_filter = {} +async def update_content(table, content, key): r.set_loop_type("asyncio") conn = await r.connect(**db_opts) # This method is only for updating content, so if we find that it doesn't exist, just return false @@ -176,36 +165,54 @@ async def update_content(table, content, r_filter=None): # Update based on the content and filter passed to us # rethinkdb allows you to do many many things inside of update # This is why we're accepting a variable and using it, whatever it may be, as the query - result = await r.table(table).filter(r_filter).update(content).run(conn) + result = await r.table(table).get(key).update(content).run(conn) except r.ReqlOpFailedError: await conn.close() result = {} await conn.close() - if table == 'prefixes' or table == 'custom_permissions': + if table == 'prefixes' or table == 'server_settings': loop.create_task(cache[table].update()) return result.get('replaced', 0) > 0 or result.get('unchanged', 0) > 0 -async def replace_content(table, content, r_filter=None): +async def replace_content(table, content, key): # This method is here because .replace and .update can have some different functionalities - if r_filter is None: - r_filter = {} r.set_loop_type("asyncio") conn = await r.connect(**db_opts) try: - result = await r.table(table).filter(r_filter).replace(content).run(conn) + result = await r.table(table).get(key).replace(content).run(conn) except r.ReqlOpFailedError: await conn.close() result = {} await conn.close() - if table == 'prefixes' or table == 'custom_permissions': + if table == 'prefixes' or table == 'server_settings': loop.create_task(cache[table].update()) return result.get('replaced', 0) > 0 or result.get('unchanged', 0) > 0 -async def get_content(table: str, r_filter=None): - if r_filter is None: - r_filter = {} +async def get_content(table, key=None): + r.set_loop_type("asyncio") + conn = await r.connect(**db_opts) + + try: + if key: + cursor = await r.table(table).get(key).run(conn) + else: + cursor = await r.table(table).run() + if cursor is None: + content = None + else: + content = await _convert_to_list(cursor) + if len(content) == 0: + content = None + except (IndexError, r.ReqlOpFailedError): + content = None + await conn.close() + if table == 'prefixes' or table == 'server_settings': + loop.create_task(cache[table].update()) + return content + +async def filter_content(table: str, r_filter): r.set_loop_type("asyncio") conn = await r.connect(**db_opts) try: @@ -216,7 +223,7 @@ async def get_content(table: str, r_filter=None): except (IndexError, r.ReqlOpFailedError): content = None await conn.close() - if table == 'prefixes' or table == 'custom_permissions': + if table == 'prefixes' or table == 'server_settings': loop.create_task(cache[table].update()) return content diff --git a/cogs/utils/utilities.py b/cogs/utils/utilities.py index c9a442c..bc35bcf 100644 --- a/cogs/utils/utilities.py +++ b/cogs/utils/utilities.py @@ -43,6 +43,17 @@ def get_subcommands(command): except AttributeError: pass +async def channel_is_nsfw(channel): + server = channel.guild.id + channel = channel.id + + server_settings = await config.get_content('server_settings', server) + + try: + return channel in server_settings[0]['nsfw_channels'] + except (TypeError, IndexError): + return False + async def download_image(url): """Returns a file-like object based on the URL provided""" @@ -98,7 +109,7 @@ async def update_records(key, winner, loser): # We're using the Harkness scale to rate # http://opnetchessclub.wikidot.com/harkness-rating-system r_filter = lambda row: (row['member_id'] == winner.id) | (row['member_id'] == loser.id) - matches = await config.get_content(key, r_filter) + matches = await config.filter_content(key, r_filter) winner_stats = {} loser_stats = {} @@ -148,7 +159,7 @@ async def update_records(key, winner, loser): if not await config.update_content(key, winner_stats, {'member_id': winner.id}): winner_stats['member_id'] = winner.id - await config.add_content(key, winner_stats, {'member_id': winner.id}) + await config.add_content(key, winner_stats) if not await config.update_content(key, loser_stats, {'member_id': loser.id}): loser_stats['member_id'] = loser.id - await config.add_content(key, loser_stats, {'member_id': loser.id}) + await config.add_content(key, loser_stats)