First product
This commit is contained in:
parent
778da9e2fc
commit
4433d7d2c4
157 changed files with 23975 additions and 0 deletions
200
tests/integration/test_admin_user_management.py
Normal file
200
tests/integration/test_admin_user_management.py
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.main import app
|
||||
from tests.integration.helpers import extract_csrf_token, insert_user, login_user
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.db
|
||||
@pytest.mark.asyncio
|
||||
async def test_users_page_is_admin_only(db_session: AsyncSession) -> None:
|
||||
await insert_user(
|
||||
db_session,
|
||||
email="member@example.com",
|
||||
password="member-pass",
|
||||
is_admin=False,
|
||||
)
|
||||
|
||||
client = TestClient(app)
|
||||
login_user(client, email="member@example.com", password="member-pass")
|
||||
|
||||
response = client.get("/users")
|
||||
|
||||
assert response.status_code == 403
|
||||
assert response.json()["detail"] == "Admin access required."
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.db
|
||||
@pytest.mark.asyncio
|
||||
async def test_non_admin_dashboard_hides_users_nav(db_session: AsyncSession) -> None:
|
||||
await insert_user(
|
||||
db_session,
|
||||
email="member@example.com",
|
||||
password="member-pass",
|
||||
is_admin=False,
|
||||
)
|
||||
|
||||
client = TestClient(app)
|
||||
login_user(client, email="member@example.com", password="member-pass")
|
||||
dashboard = client.get("/")
|
||||
|
||||
assert dashboard.status_code == 200
|
||||
assert ">Users<" not in dashboard.text
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.db
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_dashboard_shows_users_nav(db_session: AsyncSession) -> None:
|
||||
await insert_user(
|
||||
db_session,
|
||||
email="admin@example.com",
|
||||
password="admin-pass",
|
||||
is_admin=True,
|
||||
)
|
||||
|
||||
client = TestClient(app)
|
||||
login_user(client, email="admin@example.com", password="admin-pass")
|
||||
dashboard = client.get("/")
|
||||
|
||||
assert dashboard.status_code == 200
|
||||
assert ">Users<" in dashboard.text
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.db
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_can_create_and_deactivate_user(db_session: AsyncSession) -> None:
|
||||
await insert_user(
|
||||
db_session,
|
||||
email="admin@example.com",
|
||||
password="admin-pass",
|
||||
is_admin=True,
|
||||
)
|
||||
|
||||
client = TestClient(app)
|
||||
login_user(client, email="admin@example.com", password="admin-pass")
|
||||
|
||||
users_page = client.get("/users")
|
||||
csrf_token = extract_csrf_token(users_page.text)
|
||||
create_response = client.post(
|
||||
"/users",
|
||||
data={
|
||||
"email": "new-user@example.com",
|
||||
"password": "new-user-pass",
|
||||
"csrf_token": csrf_token,
|
||||
},
|
||||
follow_redirects=False,
|
||||
)
|
||||
assert create_response.status_code == 303
|
||||
assert create_response.headers["location"].startswith("/users")
|
||||
|
||||
created_user_id_result = await db_session.execute(
|
||||
text("SELECT id FROM users WHERE email = 'new-user@example.com'")
|
||||
)
|
||||
created_user_id = int(created_user_id_result.scalar_one())
|
||||
|
||||
users_page_after_create = client.get("/users")
|
||||
csrf_after_create = extract_csrf_token(users_page_after_create.text)
|
||||
toggle_response = client.post(
|
||||
f"/users/{created_user_id}/toggle-active",
|
||||
data={"csrf_token": csrf_after_create},
|
||||
follow_redirects=False,
|
||||
)
|
||||
assert toggle_response.status_code == 303
|
||||
|
||||
status_result = await db_session.execute(
|
||||
text("SELECT is_active FROM users WHERE id = :user_id"),
|
||||
{"user_id": created_user_id},
|
||||
)
|
||||
assert status_result.scalar_one() is False
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.db
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_can_reset_user_password(db_session: AsyncSession) -> None:
|
||||
target_user_id = await insert_user(
|
||||
db_session,
|
||||
email="target@example.com",
|
||||
password="old-password",
|
||||
is_admin=False,
|
||||
)
|
||||
await insert_user(
|
||||
db_session,
|
||||
email="admin@example.com",
|
||||
password="admin-pass",
|
||||
is_admin=True,
|
||||
)
|
||||
|
||||
client = TestClient(app)
|
||||
login_user(client, email="admin@example.com", password="admin-pass")
|
||||
|
||||
users_page = client.get("/users")
|
||||
csrf_token = extract_csrf_token(users_page.text)
|
||||
reset_response = client.post(
|
||||
f"/users/{target_user_id}/reset-password",
|
||||
data={
|
||||
"new_password": "new-password",
|
||||
"csrf_token": csrf_token,
|
||||
},
|
||||
follow_redirects=False,
|
||||
)
|
||||
assert reset_response.status_code == 303
|
||||
|
||||
users_page_after_reset = client.get("/users")
|
||||
logout_csrf = extract_csrf_token(users_page_after_reset.text)
|
||||
client.post(
|
||||
"/logout",
|
||||
data={"csrf_token": logout_csrf},
|
||||
follow_redirects=False,
|
||||
)
|
||||
|
||||
failed_login_page = client.get("/login")
|
||||
failed_login_csrf = extract_csrf_token(failed_login_page.text)
|
||||
failed_login = client.post(
|
||||
"/login",
|
||||
data={
|
||||
"email": "target@example.com",
|
||||
"password": "old-password",
|
||||
"csrf_token": failed_login_csrf,
|
||||
},
|
||||
follow_redirects=False,
|
||||
)
|
||||
assert failed_login.status_code == 401
|
||||
|
||||
login_user(client, email="target@example.com", password="new-password")
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.db
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_cannot_deactivate_self(db_session: AsyncSession) -> None:
|
||||
admin_user_id = await insert_user(
|
||||
db_session,
|
||||
email="admin@example.com",
|
||||
password="admin-pass",
|
||||
is_admin=True,
|
||||
)
|
||||
client = TestClient(app)
|
||||
login_user(client, email="admin@example.com", password="admin-pass")
|
||||
|
||||
users_page = client.get("/users")
|
||||
csrf_token = extract_csrf_token(users_page.text)
|
||||
response = client.post(
|
||||
f"/users/{admin_user_id}/toggle-active",
|
||||
data={"csrf_token": csrf_token},
|
||||
follow_redirects=False,
|
||||
)
|
||||
|
||||
assert response.status_code == 303
|
||||
assert response.headers["location"].startswith("/users")
|
||||
result = await db_session.execute(
|
||||
text("SELECT is_active FROM users WHERE id = :user_id"),
|
||||
{"user_id": admin_user_id},
|
||||
)
|
||||
assert result.scalar_one() is True
|
||||
Loading…
Add table
Add a link
Reference in a new issue