2025-12-19 10:12:55 +01:00
|
|
|
"""Tests for user profile and contact details."""
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
from sqlalchemy import select
|
|
|
|
|
|
|
|
|
|
from auth import get_password_hash
|
2025-12-21 21:54:26 +01:00
|
|
|
from models import User
|
2025-12-19 10:12:55 +01:00
|
|
|
from tests.helpers import unique_email
|
|
|
|
|
|
|
|
|
|
# Valid npub for testing (32 zero bytes encoded as bech32)
|
|
|
|
|
VALID_NPUB = "npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqzqujme"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestUserContactFields:
|
|
|
|
|
"""Test that contact fields work correctly on the User model."""
|
|
|
|
|
|
|
|
|
|
async def test_contact_fields_default_to_none(self, client_factory):
|
|
|
|
|
"""New users should have all contact fields as None."""
|
|
|
|
|
email = unique_email("test")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
user = User(
|
|
|
|
|
email=email,
|
|
|
|
|
hashed_password=get_password_hash("password123"),
|
|
|
|
|
)
|
|
|
|
|
db.add(user)
|
|
|
|
|
await db.commit()
|
|
|
|
|
await db.refresh(user)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert user.contact_email is None
|
|
|
|
|
assert user.telegram is None
|
|
|
|
|
assert user.signal is None
|
|
|
|
|
assert user.nostr_npub is None
|
|
|
|
|
|
|
|
|
|
async def test_contact_fields_can_be_set(self, client_factory):
|
|
|
|
|
"""Contact fields can be set when creating a user."""
|
|
|
|
|
email = unique_email("test")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
user = User(
|
|
|
|
|
email=email,
|
|
|
|
|
hashed_password=get_password_hash("password123"),
|
|
|
|
|
contact_email="contact@example.com",
|
|
|
|
|
telegram="@alice",
|
|
|
|
|
signal="alice.42",
|
|
|
|
|
nostr_npub="npub1test",
|
|
|
|
|
)
|
|
|
|
|
db.add(user)
|
|
|
|
|
await db.commit()
|
|
|
|
|
await db.refresh(user)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert user.contact_email == "contact@example.com"
|
|
|
|
|
assert user.telegram == "@alice"
|
|
|
|
|
assert user.signal == "alice.42"
|
|
|
|
|
assert user.nostr_npub == "npub1test"
|
|
|
|
|
|
|
|
|
|
async def test_contact_fields_persist_after_reload(self, client_factory):
|
|
|
|
|
"""Contact fields should persist in the database."""
|
|
|
|
|
email = unique_email("test")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
user = User(
|
|
|
|
|
email=email,
|
|
|
|
|
hashed_password=get_password_hash("password123"),
|
|
|
|
|
contact_email="contact@example.com",
|
|
|
|
|
telegram="@bob",
|
|
|
|
|
signal="bob.99",
|
|
|
|
|
nostr_npub="npub1xyz",
|
|
|
|
|
)
|
|
|
|
|
db.add(user)
|
|
|
|
|
await db.commit()
|
|
|
|
|
user_id = user.id
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Reload from database in a new session
|
|
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
result = await db.execute(select(User).where(User.id == user_id))
|
|
|
|
|
loaded_user = result.scalar_one()
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert loaded_user.contact_email == "contact@example.com"
|
|
|
|
|
assert loaded_user.telegram == "@bob"
|
|
|
|
|
assert loaded_user.signal == "bob.99"
|
|
|
|
|
assert loaded_user.nostr_npub == "npub1xyz"
|
|
|
|
|
|
|
|
|
|
async def test_contact_fields_can_be_updated(self, client_factory):
|
|
|
|
|
"""Contact fields can be updated after user creation."""
|
|
|
|
|
email = unique_email("test")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
user = User(
|
|
|
|
|
email=email,
|
|
|
|
|
hashed_password=get_password_hash("password123"),
|
|
|
|
|
)
|
|
|
|
|
db.add(user)
|
|
|
|
|
await db.commit()
|
|
|
|
|
user_id = user.id
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Update fields
|
|
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
result = await db.execute(select(User).where(User.id == user_id))
|
|
|
|
|
user = result.scalar_one()
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
user.contact_email = "new@example.com"
|
|
|
|
|
user.telegram = "@updated"
|
|
|
|
|
await db.commit()
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Verify update persisted
|
|
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
result = await db.execute(select(User).where(User.id == user_id))
|
|
|
|
|
user = result.scalar_one()
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert user.contact_email == "new@example.com"
|
|
|
|
|
assert user.telegram == "@updated"
|
|
|
|
|
assert user.signal is None # Still None
|
|
|
|
|
assert user.nostr_npub is None # Still None
|
|
|
|
|
|
|
|
|
|
async def test_contact_fields_can_be_cleared(self, client_factory):
|
|
|
|
|
"""Contact fields can be set back to None."""
|
|
|
|
|
email = unique_email("test")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
user = User(
|
|
|
|
|
email=email,
|
|
|
|
|
hashed_password=get_password_hash("password123"),
|
|
|
|
|
contact_email="contact@example.com",
|
|
|
|
|
telegram="@alice",
|
|
|
|
|
)
|
|
|
|
|
db.add(user)
|
|
|
|
|
await db.commit()
|
|
|
|
|
user_id = user.id
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Clear fields
|
|
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
result = await db.execute(select(User).where(User.id == user_id))
|
|
|
|
|
user = result.scalar_one()
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
user.contact_email = None
|
|
|
|
|
user.telegram = None
|
|
|
|
|
await db.commit()
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Verify cleared
|
|
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
result = await db.execute(select(User).where(User.id == user_id))
|
|
|
|
|
user = result.scalar_one()
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert user.contact_email is None
|
|
|
|
|
assert user.telegram is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestGetProfileEndpoint:
|
|
|
|
|
"""Tests for GET /api/profile endpoint."""
|
|
|
|
|
|
|
|
|
|
async def test_regular_user_can_get_profile(self, client_factory, regular_user):
|
|
|
|
|
"""Regular user can fetch their profile."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
response = await client.get("/api/profile")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert "contact_email" in data
|
|
|
|
|
assert "telegram" in data
|
|
|
|
|
assert "signal" in data
|
|
|
|
|
assert "nostr_npub" in data
|
|
|
|
|
# All should be None for new user
|
|
|
|
|
assert data["contact_email"] is None
|
|
|
|
|
assert data["telegram"] is None
|
|
|
|
|
assert data["signal"] is None
|
|
|
|
|
assert data["nostr_npub"] is None
|
|
|
|
|
|
|
|
|
|
async def test_admin_user_cannot_access_profile(self, client_factory, admin_user):
|
2025-12-21 23:50:06 +01:00
|
|
|
"""Admin user gets 403 when trying to access profile (lacks MANAGE_OWN_PROFILE)."""
|
2025-12-19 10:12:55 +01:00
|
|
|
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
|
|
|
|
response = await client.get("/api/profile")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 403
|
2025-12-21 23:50:06 +01:00
|
|
|
assert "manage_own_profile" in response.json()["detail"].lower()
|
2025-12-19 10:12:55 +01:00
|
|
|
|
|
|
|
|
async def test_unauthenticated_user_gets_401(self, client_factory):
|
|
|
|
|
"""Unauthenticated user gets 401."""
|
|
|
|
|
async with client_factory.create() as client:
|
|
|
|
|
response = await client.get("/api/profile")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 401
|
|
|
|
|
|
|
|
|
|
async def test_profile_returns_existing_data(self, client_factory, regular_user):
|
|
|
|
|
"""Profile returns data that was previously set."""
|
|
|
|
|
# Set some data directly in DB
|
|
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
result = await db.execute(
|
|
|
|
|
select(User).where(User.email == regular_user["email"])
|
|
|
|
|
)
|
|
|
|
|
user = result.scalar_one()
|
|
|
|
|
user.contact_email = "contact@test.com"
|
|
|
|
|
user.telegram = "@testuser"
|
|
|
|
|
await db.commit()
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Fetch via API
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
response = await client.get("/api/profile")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert data["contact_email"] == "contact@test.com"
|
|
|
|
|
assert data["telegram"] == "@testuser"
|
|
|
|
|
assert data["signal"] is None
|
|
|
|
|
assert data["nostr_npub"] is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestUpdateProfileEndpoint:
|
|
|
|
|
"""Tests for PUT /api/profile endpoint."""
|
|
|
|
|
|
|
|
|
|
async def test_regular_user_can_update_profile(self, client_factory, regular_user):
|
|
|
|
|
"""Regular user can update their profile."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
response = await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={
|
|
|
|
|
"contact_email": "new@example.com",
|
|
|
|
|
"telegram": "@newhandle",
|
|
|
|
|
"signal": "signal.42",
|
|
|
|
|
"nostr_npub": VALID_NPUB,
|
|
|
|
|
},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert data["contact_email"] == "new@example.com"
|
|
|
|
|
assert data["telegram"] == "@newhandle"
|
|
|
|
|
assert data["signal"] == "signal.42"
|
|
|
|
|
assert data["nostr_npub"] == VALID_NPUB
|
|
|
|
|
|
|
|
|
|
async def test_profile_update_persists(self, client_factory, regular_user):
|
|
|
|
|
"""Profile updates persist in the database."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={"telegram": "@persisted"},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Fetch again to verify
|
|
|
|
|
response = await client.get("/api/profile")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
assert response.json()["telegram"] == "@persisted"
|
|
|
|
|
|
|
|
|
|
async def test_admin_user_cannot_update_profile(self, client_factory, admin_user):
|
|
|
|
|
"""Admin user gets 403 when trying to update profile."""
|
|
|
|
|
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
|
|
|
|
response = await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={"telegram": "@admin"},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 403
|
|
|
|
|
|
|
|
|
|
async def test_unauthenticated_user_gets_401(self, client_factory):
|
|
|
|
|
"""Unauthenticated user gets 401."""
|
|
|
|
|
async with client_factory.create() as client:
|
|
|
|
|
response = await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={"telegram": "@test"},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 401
|
|
|
|
|
|
|
|
|
|
async def test_can_clear_fields(self, client_factory, regular_user):
|
|
|
|
|
"""User can clear fields by setting them to null."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
# First set some values
|
|
|
|
|
await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={
|
|
|
|
|
"contact_email": "test@example.com",
|
|
|
|
|
"telegram": "@test",
|
|
|
|
|
},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Then clear them
|
|
|
|
|
response = await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={
|
|
|
|
|
"contact_email": None,
|
|
|
|
|
"telegram": None,
|
|
|
|
|
"signal": None,
|
|
|
|
|
"nostr_npub": None,
|
|
|
|
|
},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert data["contact_email"] is None
|
|
|
|
|
assert data["telegram"] is None
|
|
|
|
|
|
|
|
|
|
async def test_invalid_email_returns_422(self, client_factory, regular_user):
|
|
|
|
|
"""Invalid email format returns 422 with field error."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
response = await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={"contact_email": "not-an-email"},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 422
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert "field_errors" in data["detail"]
|
|
|
|
|
assert "contact_email" in data["detail"]["field_errors"]
|
|
|
|
|
|
|
|
|
|
async def test_invalid_telegram_returns_422(self, client_factory, regular_user):
|
|
|
|
|
"""Invalid telegram handle returns 422 with field error."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
response = await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={"telegram": "missing_at_sign"},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 422
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert "field_errors" in data["detail"]
|
|
|
|
|
assert "telegram" in data["detail"]["field_errors"]
|
|
|
|
|
|
|
|
|
|
async def test_invalid_npub_returns_422(self, client_factory, regular_user):
|
|
|
|
|
"""Invalid nostr npub returns 422 with field error."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
response = await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={"nostr_npub": "npub1invalid"},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 422
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert "field_errors" in data["detail"]
|
|
|
|
|
assert "nostr_npub" in data["detail"]["field_errors"]
|
|
|
|
|
|
2025-12-21 21:54:26 +01:00
|
|
|
async def test_multiple_invalid_fields_returns_all_errors(
|
|
|
|
|
self, client_factory, regular_user
|
|
|
|
|
):
|
2025-12-19 10:12:55 +01:00
|
|
|
"""Multiple invalid fields return all errors."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
response = await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={
|
|
|
|
|
"contact_email": "bad-email",
|
|
|
|
|
"telegram": "no-at",
|
|
|
|
|
},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 422
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert "contact_email" in data["detail"]["field_errors"]
|
|
|
|
|
assert "telegram" in data["detail"]["field_errors"]
|
|
|
|
|
|
2025-12-21 21:54:26 +01:00
|
|
|
async def test_partial_update_preserves_other_fields(
|
|
|
|
|
self, client_factory, regular_user
|
|
|
|
|
):
|
2025-12-19 10:12:55 +01:00
|
|
|
"""Updating one field doesn't affect others (they get set to the request values)."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
# Set initial values
|
|
|
|
|
await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={
|
|
|
|
|
"contact_email": "initial@example.com",
|
|
|
|
|
"telegram": "@initial",
|
|
|
|
|
},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Update only telegram, but note: PUT replaces all fields
|
|
|
|
|
# So we need to include all fields we want to keep
|
|
|
|
|
response = await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={
|
|
|
|
|
"contact_email": "initial@example.com",
|
|
|
|
|
"telegram": "@updated",
|
|
|
|
|
},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert data["contact_email"] == "initial@example.com"
|
|
|
|
|
assert data["telegram"] == "@updated"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestProfilePrivacy:
|
|
|
|
|
"""Tests to ensure profile data is private."""
|
|
|
|
|
|
|
|
|
|
async def test_profile_not_in_auth_me(self, client_factory, regular_user):
|
|
|
|
|
"""Contact details should NOT appear in /api/auth/me response."""
|
|
|
|
|
# First set some profile data
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
await client.put(
|
|
|
|
|
"/api/profile",
|
|
|
|
|
json={
|
|
|
|
|
"contact_email": "secret@example.com",
|
|
|
|
|
"telegram": "@secret",
|
|
|
|
|
},
|
|
|
|
|
)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
# Check /api/auth/me doesn't expose it
|
|
|
|
|
response = await client.get("/api/auth/me")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-19 10:12:55 +01:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
# These fields should NOT be in the response
|
|
|
|
|
assert "contact_email" not in data
|
|
|
|
|
assert "telegram" not in data
|
|
|
|
|
assert "signal" not in data
|
|
|
|
|
assert "nostr_npub" not in data
|
2025-12-20 11:12:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestProfileGodfather:
|
|
|
|
|
"""Tests for godfather information in profile."""
|
|
|
|
|
|
2025-12-21 21:54:26 +01:00
|
|
|
async def test_profile_shows_godfather_email(
|
|
|
|
|
self, client_factory, admin_user, regular_user
|
|
|
|
|
):
|
2025-12-20 11:12:11 +01:00
|
|
|
"""Profile shows godfather email for users who signed up with invite."""
|
|
|
|
|
from sqlalchemy import select
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-20 11:12:11 +01:00
|
|
|
from models import User
|
2025-12-21 21:54:26 +01:00
|
|
|
from tests.helpers import unique_email
|
|
|
|
|
|
2025-12-20 11:12:11 +01:00
|
|
|
# Create invite
|
|
|
|
|
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
|
|
|
|
async with client_factory.get_db_session() as db:
|
|
|
|
|
result = await db.execute(
|
|
|
|
|
select(User).where(User.email == regular_user["email"])
|
|
|
|
|
)
|
|
|
|
|
godfather = result.scalar_one()
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-20 11:12:11 +01:00
|
|
|
create_resp = await client.post(
|
|
|
|
|
"/api/admin/invites",
|
|
|
|
|
json={"godfather_id": godfather.id},
|
|
|
|
|
)
|
|
|
|
|
identifier = create_resp.json()["identifier"]
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-20 11:12:11 +01:00
|
|
|
# Register new user with invite
|
|
|
|
|
new_email = unique_email("godchild")
|
|
|
|
|
async with client_factory.create() as client:
|
|
|
|
|
reg_resp = await client.post(
|
|
|
|
|
"/api/auth/register",
|
|
|
|
|
json={
|
|
|
|
|
"email": new_email,
|
|
|
|
|
"password": "password123",
|
|
|
|
|
"invite_identifier": identifier,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
new_user_cookies = dict(reg_resp.cookies)
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-20 11:12:11 +01:00
|
|
|
# Check profile shows godfather
|
|
|
|
|
async with client_factory.create(cookies=new_user_cookies) as client:
|
|
|
|
|
response = await client.get("/api/profile")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-20 11:12:11 +01:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert data["godfather_email"] == regular_user["email"]
|
|
|
|
|
|
2025-12-21 21:54:26 +01:00
|
|
|
async def test_profile_godfather_null_for_seeded_users(
|
|
|
|
|
self, client_factory, regular_user
|
|
|
|
|
):
|
2025-12-20 11:12:11 +01:00
|
|
|
"""Profile shows null godfather for users without one (e.g., seeded users)."""
|
|
|
|
|
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
|
|
|
|
response = await client.get("/api/profile")
|
2025-12-21 21:54:26 +01:00
|
|
|
|
2025-12-20 11:12:11 +01:00
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert data["godfather_email"] is None
|