From f69cc2d9870fa5556bbca4863b61f9963d6c5032 Mon Sep 17 00:00:00 2001 From: rotlir Date: Mon, 24 Jun 2024 03:52:50 +0300 Subject: [PATCH] [+] add autotests for clans fastapi functions, add member ranking, add Belarusian translation --- galaxy_backend/api/clans.py | 15 ++- galaxy_backend/langs/be.json | 23 ++++ galaxy_backend/langs/en.json | 3 +- galaxy_backend/langs/ru.json | 3 +- galaxy_backend/langs/uk.json | 3 +- galaxy_backend/tests/clans.py | 17 +-- galaxy_backend/tests/clans_fastapi.py | 146 +++++++++++++++++++++----- galaxy_backend/tests/run.py | 1 + galaxy_backend/tg/parse_langs.py | 1 + 9 files changed, 173 insertions(+), 39 deletions(-) create mode 100644 galaxy_backend/langs/be.json diff --git a/galaxy_backend/api/clans.py b/galaxy_backend/api/clans.py index 28b3384..5192cb5 100644 --- a/galaxy_backend/api/clans.py +++ b/galaxy_backend/api/clans.py @@ -74,8 +74,14 @@ async def get_owner(clan_id: int) -> int: return clan_owner_user.tg_id +def sort_members(member: User) -> int: + return member.coins + +# now it always returns a list of users sorted by the amount of their coins async def get_members(clan_id: int) -> list[User]: - return await User.filter(clan_id=clan_id) + users = await User.filter(clan_id=clan_id) + users.sort(key=sort_members) + return users # get an invite link for a clan with id clan_id @@ -88,20 +94,23 @@ async def get_invite_link(clan_id: int): raise fastapi.HTTPException(status_code=400, detail=str(e)) +# list all clans registered in the db +# returns something like +# {'clan2': {'id': 2, 'name': 'ClanA'}, 'clan3': {'id': 3, 'name': 'ClanB'}, 'clan4': {'id': 4, 'name': 'ClanC'}} @api.routers.clan.get('/list') async def list_clans(): try: clans = await Clan.all() + clans_dict = {} clan_dict = { 'id': 0, 'name': '' } - clans_dict = {} for clan in clans: assert isinstance(clan, Clan) clan_dict['id'] = clan.id clan_dict['name'] = clan.name - clans_dict[f'clan{clan.id}'] = clan_dict + clans_dict[f'clan{clan.id}'] = clan_dict.copy() return clans_dict except Exception as e: raise fastapi.HTTPException(status_code=400, detail=str(e)) diff --git a/galaxy_backend/langs/be.json b/galaxy_backend/langs/be.json new file mode 100644 index 0000000..f3a7080 --- /dev/null +++ b/galaxy_backend/langs/be.json @@ -0,0 +1,23 @@ +{ + "start_game": "Пачаць гульню", + "bonuses": "Бонусы", + "back": "Назад", + "join": "Далучыцца", + "check": "Праверыць", + "join_our_channel": "Падпіска на канал", + "hello": "Прывітанне", + "coins_for_tasks": "Вы атрымаеце манеты за выкананыя заданні. Выберыце заданне, якое хочаце выканаць, ніжэй.", + "click_to_join": "Націсніце кнопку ніжэй, каб далучыцца да канала", + "thanks_for_joining": "Дзякуем за падпіску на наш канал, вось вашыя 100 манет!", + "invite_friend_button": "Запрасіць сябра", + "clans_invalid_id": "На жаль, гэтая спасылка-запрашэнне несапраўдная. Папрасіце чалавека, які даў вам яе, даць іншую.", + "clans_already_participate": "Вы ўжо ў складзе гэтага клана.", + "yes": "Так", + "no": "Не", + "clan_join_request": "Вы былі запрошаны ў клан '{clan}'. Вы хочаце далучыцца да гэтага клана?", + "clan_join_confirmed": "Віншуем! Цяпер вы ўдзельнік клана '{clan}'!", + "clan_join_denied": "Вы адмовіліся далучацца да клана '{clan}'", + "not_subscribed": "Вы не падпісаныя", + "clan_already_owned": "Вы валодаеце кланам, таму не можаце далучыцца да іншага клана." +} + diff --git a/galaxy_backend/langs/en.json b/galaxy_backend/langs/en.json index 21082eb..c139822 100644 --- a/galaxy_backend/langs/en.json +++ b/galaxy_backend/langs/en.json @@ -17,6 +17,7 @@ "clan_join_request": "You were invited to the clan '{clan}'. Do you want to join this clan?", "clan_join_confirmed": "Congratulations! You are a member of the clan '{clan}' now!", "clan_join_denied": "You refused to join the clan '{clan}'", - "not_subscribed": "You are not subscribed" + "not_subscribed": "You are not subscribed", + "clan_already_owned": "You own a clan so you can't join an another clan." } diff --git a/galaxy_backend/langs/ru.json b/galaxy_backend/langs/ru.json index 7115117..425b9ed 100644 --- a/galaxy_backend/langs/ru.json +++ b/galaxy_backend/langs/ru.json @@ -17,6 +17,7 @@ "clan_join_request": "Вы были приглашены в клан '{clan}'. Вы хотите присоединиться к этому клану?", "clan_join_confirmed": "Поздравляем! Теперь вы участник клана '{clan}'!", "clan_join_denied": "Вы отказались присоединяться к клану '{clan}'", - "not_subscribed": "Вы не подписаны" + "not_subscribed": "Вы не подписаны", + "clan_already_owned": "Вы владеете кланом, так что вы не можете присоединиться к другому клану." } diff --git a/galaxy_backend/langs/uk.json b/galaxy_backend/langs/uk.json index c18b4ba..4dca776 100644 --- a/galaxy_backend/langs/uk.json +++ b/galaxy_backend/langs/uk.json @@ -17,6 +17,7 @@ "clan_join_request": "Вас запросили до клану '{clan}'. Чи хочете ви приєднатися до цього клану?", "clan_join_confirmed": "Вітаємо! Ви тепер учасник клану '{clan}'!", "clan_join_denied": "Ви відмовилися від приєднання до клану '{clan}'", - "not_subscribed": "Ви не підписані" + "not_subscribed": "Ви не підписані", + "clan_already_owned": "You own a clan so you can't join an another clan." } diff --git a/galaxy_backend/tests/clans.py b/galaxy_backend/tests/clans.py index fe7addc..639447f 100644 --- a/galaxy_backend/tests/clans.py +++ b/galaxy_backend/tests/clans.py @@ -38,12 +38,15 @@ async def check_basic() -> str: except AssertionError: raise AssertionError("remove_user() did not work correctly") # cleanup for further tests - clanA_owner = await ClanOwner.get(clan=clanA) - await clanA_owner.delete() - await clanA.delete() - await user1.delete() - await user2.delete() - await user3.delete() - await user4.delete() + clan_owners = await ClanOwner.all() + for clan_owner in clan_owners: + await clan_owner.delete() + all_clans = await Clan.all() + for clan in all_clans: + await clan.delete() + users = await User.all() + for user in users: + if user.tg_id != 0: + await user.delete() return "check basic functionality of clans" diff --git a/galaxy_backend/tests/clans_fastapi.py b/galaxy_backend/tests/clans_fastapi.py index deb14c5..5c6e963 100644 --- a/galaxy_backend/tests/clans_fastapi.py +++ b/galaxy_backend/tests/clans_fastapi.py @@ -1,26 +1,26 @@ -from core.common import all +from core.common import all, tg from models.db import User, Clan, ClanOwner import api.clans async def init(): - user1 = await User.create(tg_id=1) - user2 = await User.create(tg_id=2) - user3 = await User.create(tg_id=3) - user4 = await User.create(tg_id=4) - user5 = await User.create(tg_id=5) - user6 = await User.create(tg_id=6) - user7 = await User.create(tg_id=7) - user8 = await User.create(tg_id=8) - user9 = await User.create(tg_id=9) + user1 = await User.create(tg_id=1, coins=100) + user2 = await User.create(tg_id=2, coins=200) + user3 = await User.create(tg_id=3, coins=300) + user4 = await User.create(tg_id=4, coins=400) + user5 = await User.create(tg_id=5, coins=500) + user6 = await User.create(tg_id=6, coins=600) + user7 = await User.create(tg_id=7, coins=700) + user8 = await User.create(tg_id=8, coins=800) + user9 = await User.create(tg_id=9, coins=900) clanA = await api.clans.create_clan('ClanA', user1.tg_id) clanB = await api.clans.create_clan('ClanB', user2.tg_id) clanC = await api.clans.create_clan('ClanC', user3.tg_id) - await api.clans.add_user(user4.tg_id, clanA.id) - await api.clans.add_user(user5.tg_id, clanA.id) - await api.clans.add_user(user6.tg_id, clanB.id) - await api.clans.add_user(user7.tg_id, clanB.id) - await api.clans.add_user(user8.tg_id, clanC.id) - await api.clans.add_user(user9.tg_id, clanC.id) + await api.clans.add_user(clanA.id, user4.tg_id) + await api.clans.add_user(clanA.id, user5.tg_id) + await api.clans.add_user(clanB.id, user6.tg_id) + await api.clans.add_user(clanB.id, user7.tg_id) + await api.clans.add_user(clanC.id, user8.tg_id) + await api.clans.add_user(clanC.id, user9.tg_id) async def deinit(): @@ -37,21 +37,115 @@ async def deinit(): async def run_tests() -> str: await init() - list_clans_res = await list_clans() - if list_clans_res != 'success': - await deinit() - raise Exception(list_clans_res) + await list_clans() + clans = await Clan.all() + for clan in clans: + await get_invite(clan) + user4 = await User.filter(tg_id=4).first() + user6 = await User.filter(tg_id=6).first() + user8 = await User.filter(tg_id=8).first() + assert isinstance(user4, User) + assert isinstance(user6, User) + assert isinstance(user8, User) + clanA = await Clan.filter(name='ClanA').first() + clanB = await Clan.filter(name='ClanB').first() + clanC = await Clan.filter(name='ClanC').first() + assert isinstance(clanA, Clan) + assert isinstance(clanB, Clan) + assert isinstance(clanC, Clan) + await remove_user(user4) + await remove_user(user6) + await remove_user(user8) + await create_clan('ClanD', user4) + await get_owner(clanA) + await get_owner(clanB) + await get_owner(clanC) + await api.clans.add_user(clanA.id, user6.tg_id) + clanD = await Clan.filter(name='ClanD').first() + assert isinstance(clanD, Clan) + await get_members(clanA) + await get_members(clanB) + await get_members(clanD) await deinit() - return list_clans_res return 'check clans fastapi functions' -async def list_clans() -> str: +async def list_clans(): response = await all.async_client.get('/clan/list') + assert response.status_code == 200 + data = response.json() + expected_result = {'clan2': {'id': 2, 'name': 'ClanA'}, 'clan3': {'id': 3, 'name': 'ClanB'}, 'clan4': {'id': 4, 'name': 'ClanC'}} + assert data == expected_result + + +async def get_invite(clan: Clan): try: - assert response.status_code == 200 - except AssertionError: - return 'list_clans(): response status code is not 200' + info = await tg.bot.get_me() + except AttributeError: # if run without token + return + username = info.username + expected_result = f'https://t.me/{username}?start=joinclan_{clan.id}' + response = await all.async_client.get(f'/clan/get_invite/{clan.id}') + assert response.status_code == 200 + msg = response.json() + assert isinstance(msg, dict) + link = msg['link'] + assert isinstance(link, str) + assert link == expected_result + + +async def remove_user(user: User): + await user.fetch_related('clan') + clan = user.clan + assert isinstance(clan, Clan) + members_expected = await api.clans.get_members(clan.id) + members_expected.remove(user) + id = user.tg_id + payload = {'user_id': id} + response = await all.async_client.post('/clan/member/remove', json=payload) + assert response.status_code == 200 data = response.json() - return data + expected_result = {'message': 'User removed from clan'} + assert data == expected_result + members_new = await api.clans.get_members(clan.id) + assert members_expected == members_new + + +async def create_clan(name: str, owner: User): + payload = {'clan_name': name, 'clan_owner_id': owner.tg_id} + response = await all.async_client.post('/clan/create', json=payload) + assert response.status_code == 200 + msg = response.json() + clan_from_db = await Clan.filter(name=name).first() + assert isinstance(clan_from_db, Clan) + await api.clans.get_owner(clan_from_db.id) + response_expected = {'clan_id': clan_from_db.id, 'clan_name': name} + assert msg == response_expected + + +async def get_owner(clan: Clan): + response = await all.async_client.get(f'/clan/get_owner/{clan.id}') + assert response.status_code == 200 + owner_from_db = await api.clans.get_owner(clan.id) + msg = response.json() + assert isinstance(msg, dict) + owner_id = msg['clan_owner_id'] + assert isinstance(owner_id, int) + assert owner_id == owner_from_db + + +async def get_members(clan: Clan): + response = await all.async_client.get(f'/clan/member/list/{clan.id}') + assert response.status_code == 200 + msg = response.json() + assert isinstance(msg, dict) + members_from_db = await api.clans.get_members(clan.id) + members_from_db_id = [] + for member in members_from_db: + members_from_db_id.append(member.tg_id) + members = msg['members'] + assert isinstance(members, list) + members.sort() + members_from_db_id.sort() + assert members == members_from_db_id diff --git a/galaxy_backend/tests/run.py b/galaxy_backend/tests/run.py index 149b432..142ab2b 100644 --- a/galaxy_backend/tests/run.py +++ b/galaxy_backend/tests/run.py @@ -14,6 +14,7 @@ async def thread1(): + # please don't change the order of the first 3 entries or tests may break to_run_list: list[core.types.cor_str] = [ init.create_user, clans.check_basic, diff --git a/galaxy_backend/tg/parse_langs.py b/galaxy_backend/tg/parse_langs.py index 488a41d..fd220e1 100644 --- a/galaxy_backend/tg/parse_langs.py +++ b/galaxy_backend/tg/parse_langs.py @@ -37,6 +37,7 @@ def load_langs(path: Path) -> dict: langs['en'] = Lang(path / 'en.json') langs['ru'] = Lang(path / 'ru.json', default_lang=langs['en']) langs['uk'] = Lang(path / 'uk.json', default_lang=langs['en']) + langs['be'] = Lang(path / 'be.json', default_lang=langs['en']) return langs langs = load_langs(core.common.path.langs)