async def recent(self, ctx, filter: Option( str, "The first event matching this will be sent in the channel.", required=False, default=None)): """Returns the most recent event gathered, optionally matching `filter`.""" if filter and not await validate_filter(ctx, filter, filter_context): return # `validate_filter` will respond for us. await ctx.defer(ephemeral=False) matching_filter_str = f" matching `{filter}`" if filter else "" filter_query, filter_values = filter_to_sql(filter) database = Database(SCRAPER_DB_NAME) try: event = await database.retrieve_event( where=filter_query, where_values=filter_values, order_by="time DESC", extensive=True if filter else False) except TimeoutError: await ctx.followup.send( f"✗ Took too long to find an event{matching_filter_str}.") return if not event: await ctx.followup.send( f"✗ No event{matching_filter_str} could be found.") return await ctx.followup.send( f"✓ Most recent event{matching_filter_str}:\r\n{format_link(event)}", embed=await format_embed(event))
async def cmd_recent(command: Command, _filter: str = None): if _filter and not await validate_filter(command, _filter, filter_context): return # `validate_filter` will respond for us. filter_query, filter_values = filter_to_sql(_filter) database = Database(SCRAPER_DB_NAME) event = await database.retrieve_event(where=f""" {filter_query} ORDER BY time DESC """, where_values=filter_values, extensive=True) matching_filter_str = f" matching `{_filter}`" if _filter else "" if not event: await command.respond_err( f"No event{matching_filter_str} could be found.") return await command.respond( response= f"✓ Most recent event{matching_filter_str}\r\n{format_link(event)}", embed=await format_embed(event))
def test_filter_to_sql_none(): assert filter_to_sql(None) == ("TRUE", ())
def test_filter_to_sql_malicious(): # Database drivers should take care of escaping anything within the second portion of the tuple, so # that's where we want the attacking string. assert filter_to_sql("user:\"%s; DROP TABLE events; \"\"=\"\"") == ( "user.name LIKE %s", ("%s; DROP TABLE events; ", ))
def test_filter_to_sql_content_wildcards(): assert filter_to_sql("content:\"%hello there%\"") == ( "events.content LIKE %s", ("%hello there%", ))
def test_filter_to_sql_content_multiple_aliases(): assert filter_to_sql("group:bn") == ("(group_id=%s OR group_id=%s)", ("28", "32"))
def test_filter_to_sql_invalid_words(): with pytest.raises(ValueError) as err: filter_to_sql("user:someone and nothing else") assert "invalid" in str(err)
def test_filter_to_sql_invalid_value(): with pytest.raises(ValueError) as err: filter_to_sql("user:someone and type:undefined") assert "invalid" in str(err)
def test_filter_to_sql_invalid_key(): with pytest.raises(ValueError) as err: filter_to_sql("user:someone and undefined:nominate") assert "invalid" in str(err)
def test_filter_to_sql_quotations(): assert filter_to_sql("user:\"space in name\"") == ("user.name LIKE %s", ("space in name", ))
def test_filter_to_sql(): assert filter_to_sql("type:nominate and not user:someone") == ( "events.type=%s AND NOT user.name LIKE %s", ("nominate", "someone"))