"""Tests for role-related repository: get_user_role, set_user_role, is_admin, can_access_miniapp.""" from unittest.mock import patch import pytest from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from duty_teller.db.models import Base, Role from duty_teller.db.repository import ( ROLE_USER, ROLE_ADMIN, get_user_by_username, get_user_role, set_user_role, is_admin_for_telegram_user, can_access_miniapp_for_telegram_user, can_access_miniapp_for_user, get_or_create_user, ) @pytest.fixture def session(): """Session with roles and users tables; roles 'user' and 'admin' inserted.""" engine = create_engine( "sqlite:///:memory:", connect_args={"check_same_thread": False} ) Base.metadata.create_all(engine) Session = sessionmaker(bind=engine, autocommit=False, autoflush=False) s = Session() try: for name in (ROLE_USER, ROLE_ADMIN): r = Role(name=name) s.add(r) s.commit() yield s finally: s.close() engine.dispose() @pytest.fixture def user_no_role(session): """User with telegram_user_id set, no role.""" u = get_or_create_user( session, telegram_user_id=100, full_name="No Role", username="norole", ) return u @pytest.fixture def role_user(session): return session.query(Role).filter(Role.name == ROLE_USER).first() @pytest.fixture def role_admin(session): return session.query(Role).filter(Role.name == ROLE_ADMIN).first() def test_get_user_role_none_when_no_role(session, user_no_role): assert get_user_role(session, user_no_role.id) is None def test_get_user_role_returns_name(session, user_no_role, role_user, role_admin): user_no_role.role_id = role_user.id session.commit() assert get_user_role(session, user_no_role.id) == ROLE_USER user_no_role.role_id = role_admin.id session.commit() assert get_user_role(session, user_no_role.id) == ROLE_ADMIN def test_set_user_role(session, user_no_role, role_user): updated = set_user_role(session, user_no_role.id, ROLE_USER) assert updated is not None assert updated.id == user_no_role.id assert updated.role_id == role_user.id session.refresh(user_no_role) assert user_no_role.role.name == ROLE_USER def test_set_user_role_invalid_name_returns_none(session, user_no_role): assert set_user_role(session, user_no_role.id, "superuser") is None assert set_user_role(session, 99999, ROLE_USER) is None @patch("duty_teller.db.repository.config.is_admin") @patch("duty_teller.db.repository.config.is_admin_by_phone") def test_is_admin_for_telegram_user_from_db_role( mock_admin_phone, mock_admin, session, user_no_role, role_admin, role_user ): mock_admin.return_value = False mock_admin_phone.return_value = False user_no_role.role_id = role_user.id session.commit() assert is_admin_for_telegram_user(session, 100) is False user_no_role.role_id = role_admin.id session.commit() assert is_admin_for_telegram_user(session, 100) is True mock_admin.assert_not_called() mock_admin_phone.assert_not_called() @patch("duty_teller.db.repository.config.is_admin") @patch("duty_teller.db.repository.config.is_admin_by_phone") def test_is_admin_for_telegram_user_fallback_when_no_role( mock_admin_phone, mock_admin, session, user_no_role ): mock_admin.return_value = True mock_admin_phone.return_value = False assert is_admin_for_telegram_user(session, 100) is True mock_admin.assert_called_once() mock_admin.return_value = False mock_admin_phone.return_value = True assert is_admin_for_telegram_user(session, 100) is True @patch("duty_teller.db.repository.config.is_admin") @patch("duty_teller.db.repository.config.is_admin_by_phone") def test_is_admin_for_telegram_user_false_when_no_user( mock_admin_phone, mock_admin, session ): mock_admin.return_value = False mock_admin_phone.return_value = False assert is_admin_for_telegram_user(session, 99999) is False def test_can_access_miniapp_for_telegram_user_no_user(session): assert can_access_miniapp_for_telegram_user(session, 99999) is False def test_can_access_miniapp_for_telegram_user_with_role( session, user_no_role, role_user, role_admin ): user_no_role.role_id = role_user.id session.commit() assert can_access_miniapp_for_telegram_user(session, 100) is True user_no_role.role_id = role_admin.id session.commit() assert can_access_miniapp_for_telegram_user(session, 100) is True @patch("duty_teller.db.repository.config.is_admin") @patch("duty_teller.db.repository.config.is_admin_by_phone") def test_can_access_miniapp_for_telegram_user_fallback_when_no_role( mock_admin_phone, mock_admin, session, user_no_role ): mock_admin.return_value = False mock_admin_phone.return_value = False assert can_access_miniapp_for_telegram_user(session, 100) is False mock_admin.return_value = True assert can_access_miniapp_for_telegram_user(session, 100) is True def test_can_access_miniapp_for_user_none(session): assert can_access_miniapp_for_user(session, None) is False def test_get_user_by_username(session, user_no_role): u = get_user_by_username(session, "norole") assert u is not None and u.id == user_no_role.id u2 = get_user_by_username(session, "@norole") assert u2 is not None and u2.id == user_no_role.id u3 = get_user_by_username(session, "NOROLE") assert u3 is not None and u3.id == user_no_role.id assert get_user_by_username(session, "unknown") is None assert get_user_by_username(session, "") is None