264 lines
8.4 KiB
Python
264 lines
8.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import select
|
|
|
|
from app.config import Settings
|
|
from app.db.models import ReferralCode, ReferralInvite, RemnawaveUser, TelegramUser
|
|
from app.schemas.remnawave import PaginatedUsers
|
|
from app.services.sync_service import SyncService
|
|
from tests.helpers import make_remote_user
|
|
|
|
|
|
class _StubRemnawaveClient:
|
|
def __init__(self, users) -> None:
|
|
self.users = users
|
|
|
|
async def get_users_by_telegram_id(self, telegram_id: int):
|
|
return list(self.users)
|
|
|
|
async def get_all_users(self, *, start: int = 0, size: int = 100):
|
|
items = list(self.users)[start : start + size]
|
|
return PaginatedUsers(users=items, total=len(self.users))
|
|
|
|
|
|
async def test_refresh_cached_users_clears_stale_links_and_keeps_profile(
|
|
session_factory,
|
|
) -> None:
|
|
user_one = make_remote_user(
|
|
user_uuid="44444444-4444-4444-4444-444444444444",
|
|
user_id=4,
|
|
short_uuid="user-one",
|
|
username="oreol-one",
|
|
telegram_id=1001,
|
|
)
|
|
user_two = make_remote_user(
|
|
user_uuid="55555555-5555-5555-5555-555555555555",
|
|
user_id=5,
|
|
short_uuid="user-two",
|
|
username="oreol-two",
|
|
telegram_id=1001,
|
|
)
|
|
client = _StubRemnawaveClient([user_one, user_two])
|
|
service = SyncService(
|
|
settings=Settings.model_construct(
|
|
bot_admin_ids_raw="",
|
|
sync_subscription_history=False,
|
|
),
|
|
session_factory=session_factory,
|
|
remnawave_client=client,
|
|
)
|
|
|
|
await service.sync_users_for_telegram(
|
|
telegram_id=1001,
|
|
username="keeper",
|
|
first_name="Keep",
|
|
last_name="Me",
|
|
language_code="ru",
|
|
)
|
|
|
|
client.users = [user_one]
|
|
views = await service.refresh_cached_users_for_telegram(telegram_id=1001)
|
|
|
|
assert [view.record.rw_uuid for view in views] == [str(user_one.uuid)]
|
|
|
|
async with session_factory() as session:
|
|
telegram_user = await session.scalar(
|
|
select(TelegramUser).where(TelegramUser.telegram_id == 1001)
|
|
)
|
|
stale_user = await session.scalar(
|
|
select(RemnawaveUser).where(RemnawaveUser.rw_uuid == str(user_two.uuid))
|
|
)
|
|
|
|
assert telegram_user is not None
|
|
assert telegram_user.username == "keeper"
|
|
assert stale_user is not None
|
|
assert stale_user.telegram_id is None
|
|
assert stale_user.owner_telegram_user_id is None
|
|
|
|
|
|
async def test_get_admin_telegram_users_page_returns_paginated_users(
|
|
session_factory,
|
|
) -> None:
|
|
service = SyncService(
|
|
settings=Settings.model_construct(
|
|
bot_admin_ids_raw="",
|
|
sync_subscription_history=False,
|
|
),
|
|
session_factory=session_factory,
|
|
remnawave_client=_StubRemnawaveClient([]),
|
|
)
|
|
|
|
async with session_factory() as session:
|
|
session.add_all(
|
|
[
|
|
TelegramUser(
|
|
telegram_id=1001,
|
|
username="first",
|
|
first_name="First",
|
|
last_name="User",
|
|
language_code="ru",
|
|
last_seen_at=datetime(2026, 4, 21, 10, 0),
|
|
created_at=datetime(2026, 4, 1, 10, 0),
|
|
updated_at=datetime(2026, 4, 21, 10, 0),
|
|
),
|
|
TelegramUser(
|
|
telegram_id=1002,
|
|
username="second",
|
|
first_name="Second",
|
|
last_name="User",
|
|
language_code="ru",
|
|
last_seen_at=datetime(2026, 4, 22, 12, 0),
|
|
created_at=datetime(2026, 4, 2, 10, 0),
|
|
updated_at=datetime(2026, 4, 22, 12, 0),
|
|
),
|
|
TelegramUser(
|
|
telegram_id=1003,
|
|
username="third",
|
|
first_name="Third",
|
|
last_name="User",
|
|
language_code="ru",
|
|
last_seen_at=datetime(2026, 4, 22, 12, 0),
|
|
created_at=datetime(2026, 4, 3, 10, 0),
|
|
updated_at=datetime(2026, 4, 22, 12, 0),
|
|
),
|
|
]
|
|
)
|
|
await session.commit()
|
|
|
|
page_one = await service.get_admin_telegram_users_page(page=1, page_size=2)
|
|
page_two = await service.get_admin_telegram_users_page(page=2, page_size=2)
|
|
|
|
assert page_one.total_items == 3
|
|
assert page_one.total_pages == 2
|
|
assert [item.telegram_id for item in page_one.items] == [1003, 1002]
|
|
assert [item.telegram_id for item in page_two.items] == [1001]
|
|
|
|
|
|
async def test_get_admin_telegram_user_profile_returns_referral_and_access_data(
|
|
session_factory,
|
|
) -> None:
|
|
remote_user = make_remote_user(
|
|
user_uuid="66666666-6666-6666-6666-666666666666",
|
|
user_id=6,
|
|
short_uuid="profile-user",
|
|
username="oreol-profile",
|
|
telegram_id=2001,
|
|
)
|
|
service = SyncService(
|
|
settings=Settings.model_construct(
|
|
bot_admin_ids_raw="1001",
|
|
sync_subscription_history=False,
|
|
),
|
|
session_factory=session_factory,
|
|
remnawave_client=_StubRemnawaveClient([remote_user]),
|
|
)
|
|
|
|
await service.sync_users_for_telegram(
|
|
telegram_id=2001,
|
|
username="profile",
|
|
first_name="Profile",
|
|
last_name="User",
|
|
language_code="ru",
|
|
)
|
|
|
|
async with session_factory() as session:
|
|
session.add(
|
|
TelegramUser(
|
|
telegram_id=1001,
|
|
username="inviter",
|
|
first_name="Inviter",
|
|
last_name="Admin",
|
|
language_code="ru",
|
|
is_admin=True,
|
|
last_seen_at=datetime(2026, 4, 22, 11, 0),
|
|
created_at=datetime(2026, 4, 1, 8, 0),
|
|
updated_at=datetime(2026, 4, 22, 11, 0),
|
|
)
|
|
)
|
|
session.add(
|
|
ReferralCode(telegram_id=1001, code="INVITER1001")
|
|
)
|
|
session.add(
|
|
ReferralCode(telegram_id=2001, code="SELF2001")
|
|
)
|
|
session.add_all(
|
|
[
|
|
ReferralInvite(
|
|
inviter_telegram_id=1001,
|
|
invited_telegram_id=2001,
|
|
invited_username="profile",
|
|
invited_display_name="Profile User",
|
|
),
|
|
ReferralInvite(
|
|
inviter_telegram_id=2001,
|
|
invited_telegram_id=3001,
|
|
invited_username="child",
|
|
invited_display_name="Child User",
|
|
),
|
|
]
|
|
)
|
|
await session.commit()
|
|
|
|
profile = await service.get_admin_telegram_user_profile(telegram_id=2001)
|
|
|
|
assert profile is not None
|
|
assert profile.user.telegram_id == 2001
|
|
assert profile.referral_code == "SELF2001"
|
|
assert profile.applied_referral_code == "INVITER1001"
|
|
assert profile.invited_count == 1
|
|
assert profile.recent_invited_names == ["Child User"]
|
|
assert len(profile.accesses) == 1
|
|
assert profile.accesses[0].record.username == "oreol-profile"
|
|
|
|
|
|
async def test_sync_all_users_does_not_autoflush_half_built_user(
|
|
session_factory,
|
|
) -> None:
|
|
remote_user = make_remote_user(
|
|
user_uuid="77777777-7777-7777-7777-777777777777",
|
|
user_id=7,
|
|
short_uuid="sync-all-user",
|
|
username="oreol-sync-all",
|
|
telegram_id=4001,
|
|
)
|
|
service = SyncService(
|
|
settings=Settings.model_construct(
|
|
bot_admin_ids_raw="",
|
|
sync_subscription_history=False,
|
|
),
|
|
session_factory=session_factory,
|
|
remnawave_client=_StubRemnawaveClient([remote_user]),
|
|
)
|
|
|
|
async with session_factory() as session:
|
|
session.add(
|
|
TelegramUser(
|
|
telegram_id=4001,
|
|
username="owner",
|
|
first_name="Sync",
|
|
last_name="Owner",
|
|
language_code="ru",
|
|
)
|
|
)
|
|
await session.commit()
|
|
|
|
total = await service.sync_all_users(batch_size=50)
|
|
|
|
assert total == 1
|
|
|
|
async with session_factory() as session:
|
|
owner = await session.scalar(
|
|
select(TelegramUser).where(TelegramUser.telegram_id == 4001)
|
|
)
|
|
cached_user = await session.scalar(
|
|
select(RemnawaveUser).where(RemnawaveUser.rw_uuid == str(remote_user.uuid))
|
|
)
|
|
|
|
assert owner is not None
|
|
assert cached_user is not None
|
|
assert cached_user.rw_id == 7
|
|
assert cached_user.owner_telegram_user_id == owner.id
|
|
assert cached_user.username == "oreol-sync-all"
|