Пример #1
0
async def pm(msg: ProtocolMessage) -> None:
    if len(msg.params) >= 4 and msg.params[3] == "requestpage":
        return

    sender = User.get(msg.conn, msg.params[0])
    receiver = User.get(msg.conn, msg.params[1])
    message = "|".join(msg.params[2:]).strip()

    if sender.userid == utils.to_user_id(msg.conn.username):
        return
    if receiver.userid != utils.to_user_id(msg.conn.username):
        return

    await parse_chat_message(msg.conn, None, sender, message)
Пример #2
0
async def translate(msg: Message) -> None:
    if len(msg.args) > 3:
        return

    word = utils.to_user_id(utils.remove_diacritics(msg.args[0]))
    if word == "":
        await msg.reply("Cosa devo tradurre?")
        return

    languages_list: list[int] = []
    for lang in msg.args[1:]:  # Get language ids from the command parameters
        languages_list.append(utils.get_language_id(lang))
    languages_list.append(msg.language_id)  # Add the room language
    languages_list.extend([9, 8])  # Hardcode english and italian as fallbacks

    # Get the first two unique languages
    languages = tuple(dict.fromkeys(languages_list))[:2]
    languages = cast(tuple[int, int], languages)

    results = _get_translations(word, languages)

    if results:
        if len(results) == 1:
            await msg.reply(" / ".join(sorted(list(results.values())[0])))
            return
        resultstext = ""
        for key, val in results.items():
            if resultstext != "":
                resultstext += ", "
            resultstext += f"{' / '.join(sorted(val))} ({key[0]})"
        await msg.reply(resultstext)
        return

    await msg.reply("Non trovato")
Пример #3
0
    async def add_queryresponse_userdetails(
        self,
        user: str,
        *,
        group: str = " ",
        rooms: dict[str, str] | None = None,
    ) -> None:
        userid = utils.to_user_id(user)

        if rooms is None:
            rooms = {}

        data = {
            "id": user,
            "userid": userid,
            "name": user,
            "avatar": "1",
            "group": group,
            "autoconfirmed": True,
            "status": "",
            "rooms": {rooms[room].strip() + room: {}
                      for room in rooms},
        }

        await self.add_messages([
            f"|queryresponse|userdetails|{json.dumps(data)}",
        ])
Пример #4
0
async def profile(msg: Message) -> None:
    userid = utils.to_user_id(msg.arg.strip())
    if userid == "":
        userid = msg.user.userid

    db = Database.open()
    with db.get_session() as session:
        stmt = select(d.Users).filter_by(userid=userid)
        # TODO: remove annotation
        userdata: d.Users = session.scalar(stmt)

        if userdata and userdata.userid and userdata.avatar:
            stmt = (
                select(d.Badges).filter_by(userid=userdata.userid).order_by(d.Badges.id)
            )
            badges: list[d.Badges] = session.execute(stmt).scalars().all()

            if userdata.avatar[0] == "#":
                avatar_dir = "trainers-custom"
                avatar_name = userdata.avatar[1:]
            else:
                avatar_dir = "trainers"
                avatar_name = userdata.avatar

            html = ProfileHTML(
                avatar_dir=avatar_dir,
                avatar_name=avatar_name,
                username=userdata.username or userdata.userid,
                badges=badges,
                description=userdata.description,
                pokemon_icon=userdata.icon,
            )

            await msg.reply_htmlbox(html.doc)
Пример #5
0
async def join_leave_name(msg: ProtocolMessage) -> None:
    db = Database.open()
    with db.get_session() as session:
        for user in msg.params:
            stmt = (update(d.TemporaryVoices).filter_by(
                roomid=msg.room.roomid, userid=utils.to_user_id(user)).values(
                    date=str(datetime.utcnow())))
            session.execute(stmt)
Пример #6
0
    async def add_user_leave(self, room: str, user: str) -> None:
        roomid = utils.to_room_id(room)
        userid = utils.to_user_id(user)

        await self.add_messages([
            f">{roomid}",
            f"|l|{userid}",
        ])
Пример #7
0
async def chat(msg: ProtocolMessage) -> None:
    user = User.get(msg.conn, msg.params[0])
    message = "|".join(msg.params[1:]).strip()

    msg.room.dynamic_buffer.append(message)

    if user.userid == utils.to_user_id(msg.conn.username):
        return

    await parse_chat_message(msg.conn, msg.room, user, message)
Пример #8
0
    async def add_user_namechange(
        self,
        room: str,
        user: str,
        olduser: str,
        rank: str = " ",
        *,
        group: str = " ",
    ) -> None:
        roomid = utils.to_room_id(room)
        userid = utils.to_user_id(user)
        olduserid = utils.to_user_id(olduser)

        await self.add_messages([
            f">{roomid}",
            f"|n|{rank}{userid}|{olduserid}",
        ])
        await self.add_queryresponse_userdetails(user,
                                                 group=group,
                                                 rooms={roomid: rank})
Пример #9
0
async def timestampchat(msg: ProtocolMessage) -> None:
    timestamp = msg.params[0]
    user = User.get(msg.conn, msg.params[1])
    message = "|".join(msg.params[2:]).strip()

    msg.room.dynamic_buffer.append(message)

    if user.userid == utils.to_user_id(msg.conn.username):
        return
    if int(timestamp) < msg.conn.timestamp:
        return

    await parse_chat_message(msg.conn, msg.room, user, message)
Пример #10
0
def _get_translations(
        word: str, languages: tuple[int,
                                    int]) -> dict[tuple[str, str], set[str]]:
    word = utils.to_user_id(utils.remove_diacritics(utils.get_alias(word)))

    results: dict[tuple[str, str], set[str]] = {}

    db = Database.open("veekun")

    with db.get_session() as session:

        tables: dict[str, tuple[type[v.TranslatableMixin],
                                type[TranslatableTableNames]]] = {
                                    "ability": (v.Abilities, v.AbilityNames),
                                    "item": (v.Items, v.ItemNames),
                                    "move": (v.Moves, v.MoveNames),
                                    "nature": (v.Natures, v.NatureNames),
                                }

        for category_name, t in tables.items():
            stmt = (select(t[0], t[1].local_language_id).select_from(
                t[0]).join(t[1]).where(
                    t[1].local_language_id.in_(languages),
                    t[1].name_normalized == word,
                ))
            # TODO: remove annotations
            row: v.TranslatableMixin
            language_id: int
            for row, language_id in session.execute(stmt):
                translation = row.get_translation(
                    f"{category_name}_names",
                    language_id=list(set(languages) - {language_id})[0],
                    fallback_english=False,
                )

                if translation is not None:
                    res = (
                        category_name,
                        utils.to_id(utils.remove_diacritics(translation)),
                    )
                    if res not in results:
                        results[res] = set()
                    results[res].add(translation)

    return results
Пример #11
0
    def get(cls, conn: Connection, userstring: str) -> User:
        """Safely retrieves a User instance, if it exists, or creates a new one.

        Args:
            conn (Connection): Used to access the websocket.
            userstring (str): User string of the room to retrieve.

        Returns:
            User: Existing instance associated with userstring or newly created one.
        """

        if conn not in cls._instances:
            cls._instances[conn] = WeakValueDictionary()

        userid = utils.to_user_id(userstring)
        try:
            instance = cls._instances[conn][userid]
        except KeyError:
            instance = cls._instances[conn][userid] = cls(conn, userstring)
        return instance
Пример #12
0
 def userid(self) -> UserId:
     return utils.to_user_id(self.userstring)
Пример #13
0
async def csv_to_sqlite(conn: Connection) -> None:
    latest_veekun_commit = ""
    try:
        latest_veekun_commit = (subprocess.run(
            [
                "git",
                "rev-list",
                "-1",
                "HEAD",
                "--",
                "data/veekun",
                "databases/veekun.py",
                "tasks/veekun.py",
            ],
            cwd=join(dirname(__file__), ".."),
            capture_output=True,
            check=True,
        ).stdout.decode().strip())
        db = Database.open("veekun")
        with db.get_session() as session:
            stmt = select(v.LatestCommit.commit_id)
            if session.scalar(stmt) == latest_veekun_commit:
                return  # database is already up-to-date, skip rebuild

    except (
            subprocess.SubprocessError,  # generic subprocess error
            FileNotFoundError,  # git is not available
            OperationalError,  # table does not exist
    ):
        pass  # always rebuild on error

    print("Rebuilding veekun database...")

    with open(utils.get_config_file("veekun.sqlite"),
              "wb"):  # truncate database
        pass

    db = Database.open("veekun")

    v.Base.metadata.create_all(db.engine)

    tables_classes = {
        obj.__tablename__: obj
        for name, obj in inspect.getmembers(v) if inspect.isclass(obj)
        and obj.__module__ == v.__name__ and hasattr(obj, "__tablename__")
    }

    with db.get_session() as session:
        if latest_veekun_commit:
            session.add(v.LatestCommit(commit_id=latest_veekun_commit))

        for table in v.Base.metadata.sorted_tables:
            tname = table.key
            file_name = utils.get_data_file("veekun", f"{tname}.csv")
            if isfile(file_name):
                with open(file_name, encoding="utf-8") as f:
                    csv_data = csv.DictReader(f)
                    csv_keys = csv_data.fieldnames

                    if csv_keys is not None:
                        data = [dict(i) for i in csv_data]

                        if hasattr(table.columns, "name_normalized"):
                            for row in data:
                                row["name_normalized"] = utils.to_user_id(
                                    utils.remove_diacritics(row["name"]))

                        if tname == "locations":
                            for row in data:
                                if num := re.search(r"route-(\d+)",
                                                    row["identifier"]):
                                    row["route_number"] = num[1]

                        bulk_insert_stmt = insert(tables_classes[tname])
                        session.execute(bulk_insert_stmt, data)

                        if "identifier" in csv_keys:
                            bulk_update_stmt = (update(
                                tables_classes[tname]).values(
                                    identifier=func.replace(
                                        tables_classes[tname].identifier, "-",
                                        "")).execution_options(
                                            synchronize_session=False))
                            session.execute(bulk_update_stmt)
Пример #14
0
    async def make_connection(
        enable_commands: bool = False,
        *,
        username: str | None = None,
        password: str = "",
        avatar: str = "",
        statustext: str = "",
        rooms: list[str] | None = None,
        main_room: str = "lobby",
        command_character: str = ".",
        administrators: list[str] | None = None,
        webhooks: dict[str, str] | None = None,
    ) -> AsyncGenerator[Any, None]:
        if username is None:
            # Create and yield two default connections if no username is passed
            bot_username = env.str("USERNAME")
            bot_password = env.str("PASSWORD")
            mod_username = env.str("TESTS_MOD_USERNAME")
            mod_password = env.str("TESTS_MOD_PASSWORD")

            bot_userid = utils.to_user_id(bot_username)
            mod_userid = utils.to_user_id(mod_username)

            async with make_connection(
                True, username=bot_username, password=bot_password
            ) as bot, make_connection(
                username=mod_username, password=mod_password
            ) as mod:
                await bot.await_message(
                    f'|queryresponse|userdetails|{{"id":"{mod_userid}"', startswith=True
                )
                await mod.await_message(
                    f'|queryresponse|userdetails|{{"id":"{bot_userid}"', startswith=True
                )
                yield bot, mod
                return

        url = f"ws://localhost:{showdown_server}/showdown/websocket"

        if rooms is None:
            rooms = ["lobby"]
        if administrators is None:
            administrators = ["parnassius"]
        if webhooks is None:
            webhooks = {"room1": "https://discord.com/api/webhooks/00000/aaaaa"}

        conn = TestConnection(
            url=url,
            username=username,
            password=password,
            avatar=avatar,
            statustext=statustext,
            rooms=rooms,
            main_room=main_room,
            command_character=command_character,
            administrators=administrators,
            webhooks=webhooks,
            unittesting=True,
        )

        if not enable_commands:
            conn.commands = {}

        asyncio.create_task(conn._start_websocket())

        rooms_to_join = {utils.to_room_id(room) for room in rooms}
        while rooms_to_join:
            msg = await conn.recv_queue.get()
            msg_parts = msg.split("\n")
            roomname = ""
            if msg_parts[0][0] == ">":
                roomname = msg_parts[0]
            roomid = utils.to_room_id(roomname)
            if roomid not in rooms_to_join:
                continue
            if any(x.startswith("|init|") for x in msg_parts):
                rooms_to_join.remove(roomid)

        try:
            yield conn
        finally:
            if conn.websocket is not None:
                for task in asyncio.all_tasks():
                    if not task.get_coro().__name__.startswith("test_"):  # type: ignore
                        task.cancel()
                await conn.websocket.close()