137 lines
5.3 KiB
Python
137 lines
5.3 KiB
Python
import asyncio
|
|
|
|
from discord.ext import commands
|
|
import discord
|
|
|
|
loop = asyncio.get_event_loop()
|
|
|
|
|
|
def should_ignore(ctx):
|
|
if ctx.message.guild is None:
|
|
return False
|
|
ignored = ctx.bot.cache.ignored[ctx.guild.id]
|
|
if not ignored:
|
|
return False
|
|
return (
|
|
ctx.message.author.id in ignored["members"]
|
|
or ctx.message.channel.id in ignored["channels"]
|
|
)
|
|
|
|
|
|
async def check_not_restricted(ctx):
|
|
# Return true if this is a private channel, we'll handle that in the registering of the command
|
|
if type(ctx.message.channel) is discord.DMChannel:
|
|
return True
|
|
|
|
# First get all the restrictions
|
|
restrictions = ctx.bot.cache.restrictions[ctx.guild.id]
|
|
# Now lets check the "from" restrictions
|
|
for from_restriction in restrictions.get("from", []):
|
|
# Get the source and destination
|
|
# Source should ALWAYS be a command in this case
|
|
source = from_restriction.get("source")
|
|
destination = from_restriction.get("destination")
|
|
# Special check for what the "disable" command produces
|
|
if destination == "everyone" and ctx.command.qualified_name == source:
|
|
return False
|
|
# If this isn't the command we care about, continue
|
|
if source != ctx.command.qualified_name:
|
|
continue
|
|
|
|
# If the destination isn't everyone, then it's an integer
|
|
destination = int(destination)
|
|
|
|
# This means that the type of restriction we have is `command from channel`
|
|
# Which means we do not want commands to be ran in this channel
|
|
if destination == ctx.channel.id:
|
|
return False
|
|
# This type is `command from Role` meaning anyone with this role can't run this command
|
|
elif discord.utils.get(ctx.author.roles, id=destination):
|
|
return False
|
|
# This is `command from Member` meaning this user specifically cannot run this command
|
|
elif destination == ctx.author.id:
|
|
return False
|
|
|
|
# If we are here, then there are no blacklists stopping this from running
|
|
|
|
# Now for the to restrictions this is a little different, we need to make a whitelist and
|
|
# see if our current channel is in this whitelist, as well as any whitelisted roles are in the author's roles
|
|
# Only if there is no whitelist, do we want to blanket return True
|
|
to_restrictions = restrictions.get("to", [])
|
|
if not to_restrictions:
|
|
return True
|
|
|
|
# If the author has a role that should whitelist them
|
|
whitelisted_role = False
|
|
# If this channel is one that is whitelisted
|
|
whitelisted_channel = False
|
|
# If a whitelist was found for this command
|
|
whitelist_found = False
|
|
|
|
# Otherwise check whitelists
|
|
for to_restriction in to_restrictions:
|
|
# Get the source and destination
|
|
# Source should ALWAYS be a command in this case
|
|
source = to_restriction.get("source")
|
|
destination = int(to_restriction.get("destination"))
|
|
# If this isn't the source we care about, continue
|
|
if source != ctx.command.qualified_name:
|
|
continue
|
|
|
|
# If we've found a whitelist valid for this command, now we can set it
|
|
whitelist_found = True
|
|
# Now check against roles
|
|
if not whitelisted_role and discord.utils.get(ctx.author.roles, id=destination):
|
|
whitelisted_role = True
|
|
if ctx.channel.id == destination:
|
|
whitelisted_channel = True
|
|
|
|
# If we have reached here, then there is a whitelist... so we just need to return if they matched
|
|
# the whitelist
|
|
return whitelisted_role or whitelisted_channel or not whitelist_found
|
|
|
|
|
|
def has_perms(ctx, **perms):
|
|
# Return true if this is a private channel, we'll handle that in the registering of the command
|
|
if type(ctx.message.channel) is discord.DMChannel:
|
|
return True
|
|
|
|
# Get the member permissions so that we can compare
|
|
guild_perms = ctx.message.author.guild_permissions
|
|
channel_perms = ctx.message.author.permissions_in(ctx.message.channel)
|
|
# Currently the library doesn't handle administrator overrides..so lets do this manually
|
|
if guild_perms.administrator:
|
|
return True
|
|
# Next, set the default permissions if one is not used, based on what was passed
|
|
# This will be overriden later, if we have custom permissions
|
|
required_perm = discord.Permissions.none()
|
|
for perm, setting in perms.items():
|
|
setattr(required_perm, perm, setting)
|
|
|
|
required_perm_value = ctx.bot.cache.custom_permissions[ctx.guild.id].get(
|
|
ctx.command.qualified_name
|
|
)
|
|
if required_perm_value:
|
|
required_perm = discord.Permissions(required_perm_value)
|
|
|
|
# Now just check if the person running the command has these permissions
|
|
return guild_perms >= required_perm or channel_perms >= required_perm
|
|
|
|
|
|
def can_run(**kwargs):
|
|
async def predicate(ctx):
|
|
# Next check if it requires any certain permissions
|
|
if kwargs and not has_perms(ctx, **kwargs):
|
|
return False
|
|
# Next...check custom restrictions
|
|
if not await check_not_restricted(ctx):
|
|
return False
|
|
# Then if the user/channel should be ignored
|
|
if should_ignore(ctx):
|
|
return False
|
|
# Otherwise....we're good
|
|
return True
|
|
|
|
predicate.perms = kwargs
|
|
return commands.check(predicate)
|