# tests/integration/api/v1/admin/test_admin_users.py """ Integration tests for admin user management API endpoints. Tests the /api/v1/admin/admin-users/* endpoints. """ import pytest @pytest.mark.integration @pytest.mark.api @pytest.mark.admin class TestAdminUsersListAPI: """Test listing admin users.""" def test_list_admin_users_as_super_admin( self, client, super_admin_headers, test_platform_admin ): """Test listing admin users as super admin.""" response = client.get( "/api/v1/admin/admin-users", headers=super_admin_headers, ) assert response.status_code == 200 data = response.json() assert "admins" in data assert "total" in data assert data["total"] >= 1 def test_list_admin_users_as_platform_admin_forbidden( self, client, platform_admin_headers ): """Test that platform admin cannot list admin users.""" response = client.get( "/api/v1/admin/admin-users", headers=platform_admin_headers, ) assert response.status_code == 403 # Super admin required def test_list_admin_users_excludes_super_admins( self, client, super_admin_headers, test_platform_admin ): """Test listing admin users excluding super admins.""" response = client.get( "/api/v1/admin/admin-users", params={"include_super_admins": False}, headers=super_admin_headers, ) assert response.status_code == 200 data = response.json() # All returned admins should not be super admins for admin in data["admins"]: assert admin["role"] != "super_admin" @pytest.mark.integration @pytest.mark.api @pytest.mark.admin class TestAdminUsersCreateAPI: """Test creating platform admins.""" def test_create_platform_admin_success( self, client, super_admin_headers, test_platform, another_platform ): """Test creating a new platform admin.""" response = client.post( "/api/v1/admin/admin-users", json={ "email": "new_platform_admin@example.com", "username": "new_platform_admin", "password": "securepass123", "first_name": "New", "last_name": "Admin", "platform_ids": [test_platform.id, another_platform.id], }, headers=super_admin_headers, ) assert response.status_code == 200 data = response.json() assert data["email"] == "new_platform_admin@example.com" assert data["username"] == "new_platform_admin" assert data["role"] == "platform_admin" assert len(data["platform_assignments"]) == 2 def test_create_platform_admin_duplicate_email( self, client, super_admin_headers, test_platform, test_platform_admin ): """Test creating platform admin with duplicate email fails.""" response = client.post( "/api/v1/admin/admin-users", json={ "email": test_platform_admin.email, "username": "unique_username", "password": "securepass123", "platform_ids": [test_platform.id], }, headers=super_admin_headers, ) assert response.status_code == 409 # Conflict - user already exists def test_create_platform_admin_as_platform_admin_forbidden( self, client, platform_admin_headers, test_platform ): """Test that platform admin cannot create other admins.""" response = client.post( "/api/v1/admin/admin-users", json={ "email": "another@example.com", "username": "another", "password": "securepass123", "platform_ids": [test_platform.id], }, headers=platform_admin_headers, ) assert response.status_code == 403 # Forbidden for non-super admin @pytest.mark.integration @pytest.mark.api @pytest.mark.admin class TestAdminUsersPlatformAssignmentAPI: """Test admin platform assignment endpoints.""" def test_assign_admin_to_platform( self, client, super_admin_headers, test_platform_admin, test_platform ): """Test assigning an admin to a platform.""" response = client.post( f"/api/v1/admin/admin-users/{test_platform_admin.id}/platforms/{test_platform.id}", headers=super_admin_headers, ) assert response.status_code == 200 data = response.json() assert "message" in data assert data["user_id"] == test_platform_admin.id assert data["platform_id"] == test_platform.id def test_remove_admin_from_platform( self, client, super_admin_headers, db, test_platform_admin, test_platform, test_super_admin ): """Test removing an admin from a platform.""" from app.modules.tenancy.models import AdminPlatform # First create an assignment assignment = AdminPlatform( user_id=test_platform_admin.id, platform_id=test_platform.id, is_active=True, assigned_by_user_id=test_super_admin.id, ) db.add(assignment) db.commit() response = client.delete( f"/api/v1/admin/admin-users/{test_platform_admin.id}/platforms/{test_platform.id}", headers=super_admin_headers, ) assert response.status_code == 200 data = response.json() assert "message" in data def test_get_admin_platforms( self, client, super_admin_headers, db, test_platform_admin, test_platform, test_super_admin ): """Test getting platforms for an admin.""" from app.modules.tenancy.models import AdminPlatform # Create assignment assignment = AdminPlatform( user_id=test_platform_admin.id, platform_id=test_platform.id, is_active=True, assigned_by_user_id=test_super_admin.id, ) db.add(assignment) db.commit() response = client.get( f"/api/v1/admin/admin-users/{test_platform_admin.id}/platforms", headers=super_admin_headers, ) assert response.status_code == 200 data = response.json() assert "platforms" in data assert len(data["platforms"]) == 1 assert data["platforms"][0]["id"] == test_platform.id @pytest.mark.integration @pytest.mark.api @pytest.mark.admin class TestAdminUsersSuperAdminToggleAPI: """Test super admin promotion/demotion.""" def test_promote_to_super_admin( self, client, super_admin_headers, test_platform_admin ): """Test promoting a platform admin to super admin.""" response = client.put( f"/api/v1/admin/admin-users/{test_platform_admin.id}/super-admin", json={"role": "super_admin"}, headers=super_admin_headers, ) assert response.status_code == 200 data = response.json() assert data["role"] == "super_admin" def test_demote_from_super_admin( self, client, super_admin_headers, db, auth_manager ): """Test demoting a super admin to platform admin.""" from app.modules.tenancy.models import User # Create another super admin to demote another_super = User( email="demote_test@example.com", username="demote_test", hashed_password=auth_manager.hash_password("pass"), role="super_admin", is_active=True, ) db.add(another_super) db.commit() response = client.put( f"/api/v1/admin/admin-users/{another_super.id}/super-admin", json={"role": "platform_admin"}, headers=super_admin_headers, ) assert response.status_code == 200 data = response.json() assert data["role"] == "platform_admin" @pytest.mark.integration @pytest.mark.api @pytest.mark.admin class TestAdminAuthPlatformSelectionAPI: """Test platform selection for platform admins.""" def test_get_accessible_platforms_super_admin( self, client, super_admin_headers, test_platform ): """Test getting accessible platforms as super admin.""" response = client.get( "/api/v1/admin/auth/accessible-platforms", headers=super_admin_headers, ) assert response.status_code == 200 data = response.json() assert data["is_super_admin"] is True assert "platforms" in data assert data["requires_platform_selection"] is False def test_get_accessible_platforms_platform_admin( self, client, db, test_platform_admin, test_platform, test_super_admin, auth_manager ): """Test getting accessible platforms as platform admin.""" from app.modules.tenancy.models import AdminPlatform # Create assignment assignment = AdminPlatform( user_id=test_platform_admin.id, platform_id=test_platform.id, is_active=True, assigned_by_user_id=test_super_admin.id, ) db.add(assignment) db.commit() # Login as platform admin response = client.post( "/api/v1/admin/auth/login", json={ "email_or_username": test_platform_admin.username, "password": "platformadminpass123", }, ) assert response.status_code == 200 token = response.json()["access_token"] # Get accessible platforms response = client.get( "/api/v1/admin/auth/accessible-platforms", headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 200 data = response.json() assert data["is_super_admin"] is False assert len(data["platforms"]) == 1 assert data["platforms"][0]["id"] == test_platform.id assert data["requires_platform_selection"] is True def test_select_platform_success( self, client, db, test_platform_admin, test_platform, test_super_admin ): """Test selecting a platform as platform admin.""" from app.modules.tenancy.models import AdminPlatform # Create assignment assignment = AdminPlatform( user_id=test_platform_admin.id, platform_id=test_platform.id, is_active=True, assigned_by_user_id=test_super_admin.id, ) db.add(assignment) db.commit() # Login response = client.post( "/api/v1/admin/auth/login", json={ "email_or_username": test_platform_admin.username, "password": "platformadminpass123", }, ) token = response.json()["access_token"] # Select platform response = client.post( "/api/v1/admin/auth/select-platform", params={"platform_id": test_platform.id}, headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 200 data = response.json() assert "access_token" in data # New token should be different assert data["access_token"] != token def test_select_platform_not_assigned( self, client, db, test_platform_admin, test_platform ): """Test selecting a platform that admin is not assigned to.""" # Login (no platform assignment exists) response = client.post( "/api/v1/admin/auth/login", json={ "email_or_username": test_platform_admin.username, "password": "platformadminpass123", }, ) token = response.json()["access_token"] # Try to select platform response = client.post( "/api/v1/admin/auth/select-platform", params={"platform_id": test_platform.id}, headers={"Authorization": f"Bearer {token}"}, ) assert response.status_code == 403 # Access denied def test_select_platform_as_super_admin_fails( self, client, super_admin_headers, test_platform ): """Test that super admin cannot select platform (they don't need to).""" response = client.post( "/api/v1/admin/auth/select-platform", params={"platform_id": test_platform.id}, headers=super_admin_headers, ) assert response.status_code == 401 # Super admins don't need this