def test_parse_command(): assert parse_command("+test") == Command("test") assert parse_command("+test 123") == Command("test", "123") assert parse_command("+test 1 2 3") == Command("test", "1", "2", "3") assert not parse_command("123") assert not parse_command("+ test") assert not parse_command("++test") assert not parse_command("123 +test")
def test_prefix_custom(): command = Command("test", context=MockMessage( channel=MockChannel(_id=6, guild=MockGuild(_id=7)))) set_prefix(guild_id=7, prefix="&") assert command.prefix() == "&" set_prefix(guild_id=7, prefix=None) assert command.prefix() == DEFAULT_PREFIX
def on_reaction_remove(reaction, user): if user == client.user: return if reaction.emoji == '🎁': Command.leaveInvisibleFriend(reaction.message.id, user) if reaction.emoji == '🔫': Command.shootRusseRoulette(reaction.message.id, user) # From here random reactions if reaction.message.author == client.user: return if random.randint(0, 50) == 0: yield from reaction.message.add_reaction(reaction.emoji)
def parse_command(content: str, context: Message=None, client: Client=None) -> Command: """Returns the given content string as a command, if it's formatted as one, else None. Optionally with the given message as context.""" match = regex.search(r"^" + regex.escape(get_prefix(context)) + r"([A-Za-z]+) ?(.+)?", content) if match: name = match.group(1) args = match.group(2) if args: args_respecting_quotes = [unescape(arg) for arg, _ in split_unescaped(args, (" ",))] return Command(name, *args_respecting_quotes, context=context, client=client) return Command(name, context=context, client=client) return None
async def cmd_disable(command: Command, commands_str: str): if not command.guild_id(): await command.respond_err("Cannot change permissions in DM channels.") return command_wrappers = get_command_wrappers(commands_str) for command_wrapper in command_wrappers: permissions.set_permission_filter(guild_id=command.guild_id(), command_wrapper=command_wrapper, permission_filter=None) await command.respond(response="✓ Command permissions changed.", embed=permissions_embed( guild_id=command.guild_id(), command_wrappers=command_wrappers))
def test_can_execute_admin(): mock_message = MockMessage(channel=MockChannel(_id=44, guild=MockGuild(_id=3)), author=MockUser(_id=2, is_admin=True)) command = Command(name="test2", context=mock_message) assert permissions.can_execute(command)
async def receive_command(command: Command) -> bool: """Returns whether the received command was recognized and executed.""" if command.name not in registered_aliases: return False name = registered_aliases[command.name] func_wrapper = registered_commands[name] # Let the user know the command was recognized, and that a response should follow. await command.trigger_typing() if not permissions.can_execute(command): await command.respond( response = f"✗ Lacking permission.", embed = permissions_embed( # Can only lack permission in a guild. guild_id = command.guild_id(), command_wrappers = [func_wrapper] ) ) return False if len(func_wrapper.required_args) > len(command.args): missing_args = func_wrapper.required_args[len(command.args):] missing_arg_str = "`<" + "`>, <`".join(missing_args) + ">`" await command.respond_err(f"Missing required argument(s) {missing_arg_str}.") return False parsed_args = parse_args(command.args, arg_count=len(func_wrapper.required_args) + len(func_wrapper.optional_args)) await func_wrapper.execute(command, *parsed_args) return True
async def test_validate_filter_complex(): command = Command(name="test", context=MockMessage(channel=MockChannel())) assert await validate_filter( command = command, _filter = "type:(nom or qual or reset or dq) and not user:(banchobot or peppy)", filter_context = filter_context )
async def test_receive_command_without_optional_arg(): mock_channel = MockChannel() mock_message = MockMessage("+greet someone", channel=mock_channel) assert await receive_command( Command("greet", "someone", context=mock_message)) assert mock_channel.messages[0].content == "hi someone"
async def cmd_help(command: Command, name: str = None): if name: # Clean up the argument so that `+help +ping` works, as the user would expect. name = name.replace("+", "") embed = help_embed(name, prefix=command.prefix()) content = f"Type `{command.prefix()}help` for a list of commands." else: embed = general_help_embed(prefix=command.prefix()) content = f"Type `{command.prefix()}help <command>` for usage." if not embed: await command.respond_err(f"No command `{name}` exists.") return await command.respond(content, embed=embed)
async def test_receive_command_lacking_permission(): mock_channel = MockChannel(guild=MockGuild(_id=3)) mock_message = MockMessage("+test", channel=mock_channel, author=MockUser(is_admin=False)) assert not await receive_command(Command("test", context=mock_message)) assert mock_channel.typing_triggered assert "✗ lacking permission" in mock_channel.messages[0].content.lower()
async def test_receive_command_missing_arg(): mock_channel = MockChannel() mock_message = MockMessage("+greet", channel=mock_channel) assert not await receive_command(Command("greet", context=mock_message)) assert mock_channel.messages[0].content.startswith("✗") assert "missing required argument" in mock_channel.messages[ 0].content.lower() assert "`<name>`" in mock_channel.messages[0].content.lower()
async def cmd_prefix(command: Command, symbol: str): if not command.guild_id(): await command.respond_err("Cannot change prefix in DM channels.") return if " " in symbol: await command.respond_err("`<symbol>` cannot include whitespace.") return # The discord message character limit is 2000. # Need enough characters to write `{prefix}prefix +` to reset it. len_limit = 2000 - len("prefix +") if len(symbol) > len_limit: await command.respond_err(f"`<symbol>` cannot exceed {len_limit} characters.") return old_prefix = command.prefix() set_prefix(command.guild_id(), symbol) await command.respond(f"✓ Command prefix changed from `{old_prefix}` to `{command.prefix()}`.")
async def test_command_respond(): mock_channel = MockChannel() mock_message = MockMessage("+test 1 2 3", channel=mock_channel) command = Command("test", "1", "2", "3", context=mock_message) assert await command.respond("success") assert command.response == "success" assert command.response_embed is None assert mock_channel.messages[0].content == "success" assert mock_channel.messages[0].embed is None
def on_message(message): command = message.content.lower() if message.author == client.user: return elif command == '!': yield from client.send_message( message.channel, '<@{0}>, No command has been passed.'.format(message.author.id)) elif command.startswith('!leet'): response = Command.leet_speak(command.replace('!leet', '')) yield from client.send_message(message.channel, '{0}'.format(response))
def test_can_execute_user_perm_fail(): command_wrapper = get_wrapper(name="test1") mock_message = MockMessage(channel=MockChannel(_id=44, guild=MockGuild(_id=3)), author=MockUser(_id=2, is_admin=False)) command = Command(name="test2", context=mock_message) set_permission_filter(guild_id=3, command_wrapper=command_wrapper, permission_filter="user:<@88>") assert not permissions.can_execute(command)
def test_parse_command_custom_prefix(): context = MockMessage(channel=MockChannel(guild=MockGuild(_id=3))) set_prefix(guild_id=3, prefix="&") assert not parse_command("+test", context=context) assert parse_command("&test", context=context) == Command("test", context=context) assert parse_command("&test 123", context=context) == Command("test", "123", context=context) assert parse_command("&test 1 2 3", context=context) == Command("test", "1", "2", "3", context=context) assert not parse_command("123", context=context) assert not parse_command("& test", context=context) assert not parse_command("&&test", context=context) assert not parse_command("123 &test", context=context)
async def test_command_respond_forbidden(): mock_error = Forbidden(MockResponse(status=403, reason="forbidden"), "lacking permissions") mock_channel = MockErrorChannel(raise_on_send=mock_error) mock_message = MockMessage("+test 1 2 3", channel=mock_channel) command = Command("test", "1", "2", "3", context=mock_message) assert not await command.respond( "e.g. lacking send message permissions in the channel") assert command.response is None assert command.response_embed is None assert not mock_channel.messages
async def test_command_respond_embed(): mock_channel = MockChannel() mock_message = MockMessage("+test 1 2 3", channel=mock_channel) command = Command("test", "1", "2", "3", context=mock_message) embed = Embed() embed.add_field(name="test", value="success") assert await command.respond("", embed=embed) assert command.response == "" assert command.response_embed == embed assert mock_channel.messages[0].content == "" assert mock_channel.messages[0].embed == embed
async def test_validate_filter_invalid_key(): command = Command(name="test", context=MockMessage(channel=MockChannel())) assert not await validate_filter(command=command, _filter="undefined:undefined", filter_context=filter_context) assert "✗" in command.response assert "invalid key" in command.response.lower() embed = filters_embed(filter_context=filter_context) assert command.response_embed.title == embed.title assert command.response_embed.description == embed.description assert command.response_embed.fields[0].name == embed.fields[0].name assert command.response_embed.fields[0].value == embed.fields[0].value assert command.response_embed.fields[1].name == embed.fields[1].name assert command.response_embed.fields[1].value == embed.fields[1].value
async def test_validate_filter_invalid_value(): command = Command(name="test", context=MockMessage(channel=MockChannel())) assert not await validate_filter(command=command, _filter="type:undefined", filter_context=filter_context) assert "✗" in command.response assert "invalid value" in command.response.lower() embed = filter_embed(key="type", filter_context=filter_context) assert command.response_embed.fields[0].name == embed.fields[0].name assert command.response_embed.fields[0].value == embed.fields[0].value assert command.response_embed.fields[1].name == embed.fields[1].name assert command.response_embed.fields[1].value == embed.fields[1].value assert command.response_embed.fields[2].name == embed.fields[2].name assert command.response_embed.fields[2].value == embed.fields[2].value
async def test_command_respond_httpexception(): mock_error = HTTPException(MockResponse(status=404, reason="not found"), "e.g. some channel doesn't exist") mock_channel = MockErrorChannel(raise_on_send=mock_error) mock_message = MockMessage("+test 1 2 3", channel=mock_channel) command = Command("test", "1", "2", "3", context=mock_message) with pytest.raises(HTTPException): await command.respond("e.g. API did not respond with 200: OK") assert command.response is None assert command.response_embed is None assert not mock_channel.messages
def on_reaction_add(reaction, user): if user == client.user: return if reaction.emoji == '🎁': Command.joinInvisibleFriend(reaction.message.id, user) if reaction.emoji == '▶️': Command.startInvisibleFriend(reaction.message.id, user) if reaction.emoji == '⚙️': Command.sendSettingsInvisibleFriend(reaction.message.id, user) if reaction.emoji == '🔫': Command.shootRusseRoulette(reaction.message.id, user) if user.bot: kakeraType = re.findall('^<:(kakera.?):', str(reaction.emoji)) if len(kakeraType) > 0: Command.kakeraBroadcast(reaction.message.channel, kakeraType[0]) # From here random reactions if reaction.message.author == client.user: return if random.randint(0, 100) == 0: yield from reaction.message.add_reaction(reaction.emoji)
async def test_validate_filter_invalid_word(): command = Command(name="test", context=MockMessage(channel=MockChannel())) assert not await validate_filter(command=command, _filter="user:sometwo annd type:qualify", filter_context=filter_context) assert "✗" in command.response assert "invalid word" in command.response.lower() embed = filters_embed(filter_context=filter_context) assert command.response_embed.title == embed.title assert command.response_embed.description == embed.description assert command.response_embed.fields[0].name == embed.fields[0].name assert command.response_embed.fields[0].value == embed.fields[0].value assert command.response_embed.fields[1].name == embed.fields[1].name assert command.response_embed.fields[1].value == embed.fields[1].value
def can_execute(command: Command) -> bool: """Returns whether the given command has permissions to execute within its current context (channel/author/roles of that guild). Administrators bypass any permission.""" command_wrapper = commands.get_wrapper(command.name) perm_filter = get_permission_filter(command.guild_id(), command_wrapper) has_permission = filter_context.test( perm_filter, command.context) if perm_filter else False caller = command.context.author # The `guild_permissions` attribute is only available in guilds, for DM channels we skip this. is_admin_or_dm = not hasattr( caller, "guild_permissions") or caller.guild_permissions.administrator return has_permission or is_admin_or_dm
def test_can_execute_role_perm(): command_wrapper = get_wrapper(name="test1") mock_message = MockMessage(channel=MockChannel(_id=44, guild=MockGuild(_id=3)), author=MockUser(_id=2, roles=[MockRole(_id=66)], is_admin=False)) command = Command(name="test2", context=mock_message) set_permission_filter(guild_id=3, command_wrapper=command_wrapper, permission_filter="role:<@&66>") assert permissions.can_execute(command)
async def test_validate_filter_missing_gate(): command = Command(name="test", context=MockMessage(channel=MockChannel())) assert not await validate_filter(command=command, _filter="user:sometwo type:qualify", filter_context=filter_context) assert "✗" in command.response assert "missing gate" in command.response.lower() assert "between `user:sometwo` and `type:qualify`" in command.response.lower() embed = filters_embed(filter_context=filter_context) assert command.response_embed.title == embed.title assert command.response_embed.description == embed.description assert command.response_embed.fields[0].name == embed.fields[0].name assert command.response_embed.fields[0].value == embed.fields[0].value assert command.response_embed.fields[1].name == embed.fields[1].name assert command.response_embed.fields[1].value == embed.fields[1].value
async def cmd_enable(command: Command, commands_str: str, perms_filter: Optional[str]=None): if not command.guild_id(): await command.respond_err("Cannot change permissions in DM channels.") return if perms_filter and not await validate_filter(command, perms_filter, filter_context): # `validate_filter` responds for us. return command_wrappers = get_command_wrappers(commands_str) for command_wrapper in command_wrappers: permissions.set_permission_filter( guild_id = command.guild_id(), command_wrapper = command_wrapper, permission_filter = perms_filter or f"role:<@&{command.context.guild.default_role.id}>" ) await command.respond( response = "✓ Command permissions changed.", embed = permissions_embed( guild_id = command.guild_id(), command_wrappers = command_wrappers ) )
def test_command_help_embed(): register( category="Some Category", names=["test"], required_args=["one", "two"], optional_args=["three"], description= "A command that uses `<one>`, `<two>`, and `[three]` to do stuff.", example_args=["one two", "1 2 3", "\"o n e\" two three"])(None) embed1 = Command("test").help_embed() embed2 = help_embed("test") assert embed1.fields[0].name == embed2.fields[0].name assert embed1.fields[0].value == embed2.fields[0].value
def on_reaction_add(reaction, user): if user == client.user: return if reaction.emoji == '🎁': Command.joinInvisibleFriend(reaction.message.id, user) if reaction.emoji == '▶️': Command.startInvisibleFriend(reaction.message.id, user) if reaction.emoji == '⚙️': Command.sendSettingsInvisibleFriend(reaction.message.id, user) if reaction.emoji == '🔫': Command.shootRusseRoulette(reaction.message.id, user) # From here random reactions if reaction.message.author == client.user: return if random.randint(0, 100) == 0: yield from reaction.message.add_reaction(reaction.emoji)
def testSetCmd(self): user = User(_admin_sender) user.makeAdmin() Command.dispatch(self.admin_msg)
def testNoCmd(self): Command.dispatch(self.msg)
def testSetCmd(self): Command.dispatch(self.user_msg) user = User(_user_sender) val = user.getVariable(_var) self.assertEqual(val, None)
def testEchoCmd(self): Command.dispatch(self.user_msg)
def testSetCmd(self): user = User(_admin_sender) user.makeAdmin() Command.dispatch(self.admin_msg) self.assertEqual(user.getAdminVariable(_var), _val)
def testHeLLoCmd(self): Command.dispatch(self.user_msg)
def post(self): message = xmpp.Message(self.request.POST) Command.dispatch(message)
def testSetCmd(self): Command.dispatch(self.admin_msg) self.assertEqual(self.var.get(), None)
def testSetCmdAgain(self): Command.dispatch(self.admin_msg) self.assertEqual(User(_user_sender).getAdminVariable(_var), None)