Exemple #1
0
def set_prefix(guild_id: int, prefix: str):
    """Sets the command prefix for this guild id to the given prefix.
    Instead deletes if prefix is None."""
    if prefix is None:
        Database(DEFAULT_DB_NAME).delete_prefix(guild_id)
    else:
        Database(DEFAULT_DB_NAME).insert_prefix(Prefix(guild_id, prefix))
    load()
Exemple #2
0
def test_set_prefix_none():
    assert not prefixes.cache
    set_prefix(3, "&")
    assert Database(BOT_TEST_DB_NAME).retrieve_prefix("guild_id=%s",
                                                      (3, )) == Prefix(3, "&")
    assert prefixes.cache[3] == "&"
    set_prefix(3, None)
    assert Database(BOT_TEST_DB_NAME).retrieve_prefix("guild_id=%s",
                                                      (3, )) is None
    assert not prefixes.cache
Exemple #3
0
def set_permission_filter(guild_id: int, command_wrapper: FunctionWrapper,
                          permission_filter: str) -> None:
    """Updates the permission filter in this guild for this command to the given value.
    If given `None`, the permission entry is deleted."""
    if permission_filter is None:
        Database(DEFAULT_DB_NAME).delete_permission(guild_id,
                                                    command_wrapper.names[0])
    else:
        Database(DEFAULT_DB_NAME).insert_permission(
            CommandPermission(guild_id, command_wrapper.names[0],
                              permission_filter))
    load()
Exemple #4
0
    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))
Exemple #5
0
async def test_unsub():
    subs = [
        Subscription(guild_id=2, channel_id=6, _filter="type:nominate"),
        Subscription(guild_id=2, channel_id=4, _filter="user:someone"),
        Subscription(guild_id=1, channel_id=6, _filter="type:nominate")
    ]
    database = Database(BOT_TEST_DB_NAME)
    for sub in subs:
        database.insert_subscription(sub)
    subscriber.load()

    mock_message = MockMessage(
        channel=MockChannel(_id=6, guild=MockGuild(_id=2)))
    mock_command = MockCommand("unsub", context=mock_message)

    assert all(sub in subscriber.cache for sub in subs)

    assert await receive_command(mock_command)
    assert mock_command.response.startswith("✓")
    assert "🔕" in mock_command.response_embed.fields[0].name.lower()
    assert "unsubscribed from" in mock_command.response_embed.fields[
        0].name.lower()
    assert "type:nominate" in mock_command.response_embed.fields[0].value
    assert "`type:nominate`" in mock_command.response_embed.fields[0].value
    assert subs[0] not in subscriber.cache
    assert subs[1] in subscriber.cache
    assert subs[2] in subscriber.cache
Exemple #6
0
def load() -> None:
    """Retrieves all subscriptions from the database and appends them to the internal list."""
    global cache
    cache = []

    for sub in Database(DEFAULT_DB_NAME).retrieve_subscriptions():
        cache.append(sub)
Exemple #7
0
def bot_test_database():
    database = Database(BOT_TEST_DB_NAME)
    database.clear_table_data("subscriptions")
    database.clear_table_data("prefixes")
    database.clear_table_data("permissions")
    db_module.clear_cache(BOT_TEST_DB_NAME)
    return database
Exemple #8
0
def test_correct_setup():
    database = Database(SCRAPER_TEST_DB_NAME)
    assert not database.retrieve_table_data("events")
    assert not database.retrieve_table_data("discussions")
    assert not database.retrieve_table_data("beatmapsets")
    assert not database.retrieve_table_data("users")
    assert not database.retrieve_table_data("beatmapset_modes")
Exemple #9
0
def setup_function():
    database = Database(BOT_TEST_DB_NAME)
    # Reset database to state before any tests ran.
    database.clear_table_data("subscriptions")
    # Use the test database by default, so we don't clutter the production one.
    subscriber.DEFAULT_DB_NAME = BOT_TEST_DB_NAME
    subscriber.cache = []
Exemple #10
0
def setup_function():
    database = Database(SCRAPER_TEST_DB_NAME)
    # Reset database to state before any tests ran.
    database.clear_table_data("events")
    database.clear_table_data("discussions")
    database.clear_table_data("beatmapsets")
    database.clear_table_data("users")
    database.clear_table_data("beatmapset_modes")
Exemple #11
0
def add_subscription(sub: Subscription) -> None:
    """Inserts a subscription into the subscription table of the database and reloads the cache.
    Causes any new events passing the filter to be sent to the channel."""
    if sub.guild_id is None:
        # Prevents excessive discord rate limiting (5 DMs per second globally).
        raise ValueError("Cannot subscribe in DM channels.")

    Database(DEFAULT_DB_NAME).insert_subscription(sub)
    load()
Exemple #12
0
def load() -> None:
    """Loads the guild-specific command permissions from the database into the cache."""
    cache.clear()
    for perm_obj in Database(DEFAULT_DB_NAME).retrieve_permissions():
        if perm_obj.guild_id not in cache:
            cache[perm_obj.guild_id] = {
                perm_obj.command_name: perm_obj.permission_filter
            }
        else:
            cache[perm_obj.guild_id][
                perm_obj.command_name] = perm_obj.permission_filter
Exemple #13
0
    def _initialize_models(self):
        """
        Set up our database connection and load up the model classes

        :return: None
        """

        self.db = Database(self.settings)
        self.db.run_migrations()
        for channel in self.settings.CHANNEL_LIST:
            self.channel_models[channel] = self.db.get_models(channel)
Exemple #14
0
    async def db_connect(self) -> None:
        """Estabolish connection with the database."""
        self.database = Database(config.DATABASE)
        connected = await self.database.connect()
        while not connected:
            logger.warning("Retrying to connect to database in 5s")
            # Synchronous sleep function to stop everything until db is connecting
            time.sleep(5)
            connected = await self.database.connect()

        await self.database.load_tables(self.db_table_list, self)
Exemple #15
0
def test_load():
    sub1 = Subscription(guild_id=1, channel_id=1, _filter="type:nominate")
    sub2 = Subscription(guild_id=1, channel_id=2, _filter="type:ranked")

    database = Database(BOT_TEST_DB_NAME)
    database.insert_subscription(sub1)
    database.insert_subscription(sub2)

    subscriber.load()

    assert sub1 in subscriber.cache
    assert sub2 in subscriber.cache
Exemple #16
0
def test_load():
    permissions.load()
    assert not permissions.cache

    Database(BOT_TEST_DB_NAME).insert_permission(
        CommandPermission(guild_id=3,
                          command_name="test1",
                          permission_filter="filter"))

    permissions.load()
    assert permissions.cache
    assert permissions.cache[3]["test1"] == "filter"
Exemple #17
0
def retrieve_with_timeout(db_name,
                          table,
                          where="TRUE",
                          selection="*",
                          group_by: str = None,
                          order_by: str = None,
                          limit: int = None):
    try:
        db = Database(db_name)
        return db.retrieve_table_data(table=table,
                                      where=where,
                                      selection=selection,
                                      group_by=group_by,
                                      order_by=order_by,
                                      limit=limit)[0][0]
    except TimeoutError:
        return "(timed out)"
Exemple #18
0
async def format_history(beatmapset: Beatmapset,
                         length_limit: int = None,
                         database: Database = None) -> str:
    """Returns the nomination history of this beatmapset (i.e. icons and names of actions and their authors).
    Optionally within a certain length, smartly shortening/truncating the contents if needed."""
    if not database:
        database = Database(
            SCRAPER_DB_NAME)  # Using wrapped database to access events.

    # Sorted by time ascending; newer events first.
    events = list(
        filter(lambda event: type_props[event.type].show_in_history, await
               database.retrieve_beatmapset_events(beatmapset)))

    long_history = ""
    for event in events:
        # Some nomination events seem to be missing a user.
        if not event.user:
            if event.discussion and event.discussion.user:
                event.user = event.discussion.user
            else:
                # Old versions of the scraper inserted system qualifications, we should ignore those.
                continue

        long_history = (
            f"{type_props[event.type].emoji} [{event.user}](https://osu.ppy.sh/users/{event.user.id})"
            + ("\u2000" if long_history else "") + long_history)

    if length_limit is None or len(long_history) <= length_limit:
        return f"\n{long_history}"

    short_history = ""
    for event in events:
        emoji = (f"{type_props[event.type].emoji}" +
                 (" " if short_history else ""))

        # `- 3` to give space to ellipses if we need them.
        if len(short_history) + len(emoji) <= length_limit - 3:
            short_history = emoji + short_history
        else:
            # If there isn't enough space for anything, we skip the history completely.
            if short_history:
                short_history = "..." + short_history
            break

    return f"\n{short_history}"
Exemple #19
0
async def test_recent():
    beatmapset = Beatmapset(1,
                            "artist",
                            "title",
                            creator=User(2, "sometwo"),
                            modes=["osu"])
    event1 = Event("nominate",
                   from_string("2020-01-01 00:00:00"),
                   beatmapset,
                   user=User(1, "someone"))
    event2 = Event("qualify",
                   from_string("2020-01-01 01:00:00"),
                   beatmapset,
                   user=User(4, "somefour"),
                   content="nicely done")

    database = Database(SCRAPER_TEST_DB_NAME)
    database.insert_event(event1)
    database.insert_event(event2)

    mock_message = MockMessage(
        channel=MockChannel(_id=6, guild=MockGuild(_id=2)))
    mock_command = MockCommand("recent",
                               "type:(nominate or qualify)",
                               context=mock_message)

    assert await receive_command(mock_command)

    assert mock_command.response.startswith("✓")
    assert "https://osu.ppy.sh/beatmapsets/1" in mock_command.response
    assert mock_command.response_embed
    assert mock_command.response_embed.fields
    assert mock_command.response_embed.fields[0].name.startswith(
        ":heart:\u2000Qualified (**")
    assert mock_command.response_embed.fields[0].name.endswith("** ago)")
    assert "artist - title" in mock_command.response_embed.fields[0].value
    assert "sometwo" in mock_command.response_embed.fields[0].value
    assert mock_command.response_embed.footer.text == "somefour \"nicely done\""
    assert mock_command.response_embed.footer.icon_url == "https://a.ppy.sh/4"
Exemple #20
0
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))
import string
import random
import time
import os

from bot.database import Database
from pyrogram import filters
from pyrogram import Client
from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from pyrogram.errors import FloodWait, InputUserDeactivated, UserIsBlocked, PeerIdInvalid
import aiofiles
import aiofiles.os

from bot import (SESSION_NAME, DATABASE_URL)

db = Database(DATABASE_URL, SESSION_NAME)
CURRENT_PROCESSES = {}
CHAT_FLOOD = {}
broadcast_ids = {}


async def send_msg(user_id, message):
    try:
        await message.forward(chat_id=user_id)
        return 200, None
    except FloodWait as e:
        await asyncio.sleep(e.x)
        return send_msg(user_id, message)
    except InputUserDeactivated:
        return 400, f"{user_id} : deactivated\n"
    except UserIsBlocked:
Exemple #22
0
def setup_function():
    prefixes.DEFAULT_DB_NAME = BOT_TEST_DB_NAME
    Database(BOT_TEST_DB_NAME).clear_table_data("prefixes")
    prefixes.cache = {}
Exemple #23
0
from pyrogram import filters as Filters

from bot.screenshotbot import ScreenShotBot
from bot.utils import Utilities
from bot.config import Config
from bot.database import Database


db = Database()


@ScreenShotBot.on_callback_query(
    Filters.create(lambda _, __, query: query.data.startswith("set"))
)
async def settings_cb(c, m):
    try:
        _, typ, action = m.data.split("+")  # Reverse compatibility.
    except Exception:
        _, typ = m.data.split("+")
    chat_id = m.from_user.id
    alert_text = "Not supported action."

    if typ == "af":
        as_file = await db.is_as_file(chat_id)
        await db.update_as_file(chat_id, not as_file)
        alert_text = "Successfully changed screenshot upload mode!"

    elif typ == "wm":
        watermark_text = await db.get_watermark_text(chat_id)
        if watermark_text:
            await db.update_watermark_text(chat_id)
Exemple #24
0
def test_database():
    database = Database(SCRAPER_TEST_DB_NAME)
    database.clear_table_data("events")
    db_module.clear_cache(SCRAPER_TEST_DB_NAME)
    return database
Exemple #25
0
def test_correct_setup():
    assert not Database(BOT_TEST_DB_NAME).retrieve_table_data("subscriptions")
Exemple #26
0
import logging
import os
import sys
from sqlite3 import DatabaseError

from telegram import ParseMode, TelegramError
from telegram.ext import Defaults, Updater

from bot.database import Database

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(funcName)s - %(message)s",
    datefmt="%Y.%m.%d %H:%M:%S")

try:
    updater = Updater(token=os.environ['TOKEN'],
                      defaults=Defaults(parse_mode=ParseMode.MARKDOWN))
except KeyError:
    logging.critical("'TOKEN' environment variable is required.")
    sys.exit(1)
except TelegramError as err:
    logging.critical("Telegram connection error: %s", err)
    sys.exit(1)

try:
    db = Database('data/facebook.db')
except DatabaseError as err:
    logging.critical("Database connection error: %s", err)
    sys.exit(1)
Exemple #27
0
def get_subscription(channel: TextChannel) -> Subscription:
    """Returns the subscription associated with the given channel, if any, otherwise None."""
    return Database(DEFAULT_DB_NAME).retrieve_subscription(
        "guild_id=%s AND channel_id=%s",
        (guild_id_or_none(channel), channel.id))
Exemple #28
0
def remove_subscription(sub: Subscription) -> None:
    """Deletes a subscription from the subscription table of the database and reloads the cache."""
    Database(DEFAULT_DB_NAME).delete_subscription(sub)
    load()
Exemple #29
0
def setup_function():
    permissions.DEFAULT_DB_NAME = BOT_TEST_DB_NAME
    Database(BOT_TEST_DB_NAME).clear_table_data("permissions")
    permissions.cache = {}
Exemple #30
0
def setup_function():
    subscriber.DEFAULT_DB_NAME = BOT_TEST_DB_NAME
    # Reset database to state before any tests ran.
    Database(BOT_TEST_DB_NAME).clear_table_data("subscriptions")