148 lines
5.0 KiB
Python
148 lines
5.0 KiB
Python
import hashlib
|
|
|
|
import pytest
|
|
from httpx import AsyncClient
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.contact_lead import ContactLead
|
|
from app.models.member import MemberVerificationCode
|
|
|
|
pytestmark = pytest.mark.asyncio
|
|
|
|
|
|
async def test_public_contact_submission_creates_lead(client: AsyncClient, db_session: AsyncSession):
|
|
response = await client.post(
|
|
"/api/contact",
|
|
json={
|
|
"name": "Jamie Smith",
|
|
"email": "jamie@example.com",
|
|
"phone": "021 333 4444",
|
|
"services": ["Pack Walks", "Puppy Visits"],
|
|
"petName": "Buddy",
|
|
"petBreed": "Shih Tzu",
|
|
"location": "Ponsonby",
|
|
"serviceAreaStatus": "in_area",
|
|
"message": "Interested in a meet and greet.",
|
|
},
|
|
)
|
|
assert response.status_code == 201
|
|
body = response.json()
|
|
assert body["status"] == "invite"
|
|
assert body["email"] == "jamie@example.com"
|
|
|
|
result = await db_session.execute(select(ContactLead).where(ContactLead.email == "jamie@example.com"))
|
|
lead = result.scalars().first()
|
|
assert lead is not None
|
|
assert lead.requested_services == "Pack Walks, Puppy Visits"
|
|
assert lead.pet_name == "Buddy"
|
|
|
|
|
|
async def test_admin_can_invite_lead_into_onboarding(client: AsyncClient, admin_token: str):
|
|
create_response = await client.post(
|
|
"/api/contact",
|
|
json={
|
|
"name": "Jamie Smith",
|
|
"email": "jamie@example.com",
|
|
"phone": "021 333 4444",
|
|
"services": ["Pack Walks"],
|
|
"petName": "Buddy",
|
|
"petBreed": "Shih Tzu",
|
|
"location": "Ponsonby",
|
|
"message": "Interested in a meet and greet.",
|
|
},
|
|
)
|
|
lead_id = create_response.json()["id"]
|
|
|
|
invite_response = await client.post(
|
|
f"/api/v1/admin/leads/{lead_id}/invite",
|
|
headers={"Authorization": f"Bearer {admin_token}"},
|
|
json={"send_email": False},
|
|
)
|
|
assert invite_response.status_code == 200
|
|
body = invite_response.json()
|
|
assert body["lead"]["status"] == "invited"
|
|
assert body["member_status"] == "invited"
|
|
assert body["member_id"]
|
|
|
|
members_response = await client.get(
|
|
"/api/v1/admin/members",
|
|
headers={"Authorization": f"Bearer {admin_token}"},
|
|
)
|
|
assert any(member["email"] == "jamie@example.com" for member in members_response.json())
|
|
|
|
|
|
async def test_lead_becomes_converted_after_member_activation(
|
|
client: AsyncClient,
|
|
admin_token: str,
|
|
db_session: AsyncSession,
|
|
):
|
|
create_response = await client.post(
|
|
"/api/contact",
|
|
json={
|
|
"name": "Jamie Smith",
|
|
"email": "jamie@example.com",
|
|
"services": ["Pack Walks"],
|
|
"petName": "Buddy",
|
|
},
|
|
)
|
|
lead_id = create_response.json()["id"]
|
|
|
|
invite_response = await client.post(
|
|
f"/api/v1/admin/leads/{lead_id}/invite",
|
|
headers={"Authorization": f"Bearer {admin_token}"},
|
|
json={"send_email": False},
|
|
)
|
|
member_id = invite_response.json()["member_id"]
|
|
|
|
await client.post("/api/v1/members/claim/request", json={"email": "jamie@example.com"})
|
|
await db_session.execute(
|
|
MemberVerificationCode.__table__.update()
|
|
.values(code_hash=hashlib.sha256("AABBCC".encode()).hexdigest())
|
|
)
|
|
await db_session.commit()
|
|
await client.post(
|
|
"/api/v1/members/claim/complete",
|
|
json={"email": "jamie@example.com", "code": "AABBCC", "password": "NewPass99!"},
|
|
)
|
|
|
|
await client.post(
|
|
"/api/v1/members/auth/login",
|
|
json={"email": "jamie@example.com", "password": "NewPass99!"},
|
|
)
|
|
await db_session.execute(
|
|
MemberVerificationCode.__table__.update()
|
|
.where(MemberVerificationCode.purpose == "login_2fa")
|
|
.values(code_hash=hashlib.sha256("112233".encode()).hexdigest())
|
|
)
|
|
await db_session.commit()
|
|
verify_response = await client.post(
|
|
"/api/v1/members/auth/login/verify",
|
|
json={"email": "jamie@example.com", "code": "112233"},
|
|
)
|
|
access_token = verify_response.json()["access_token"]
|
|
|
|
await client.put(
|
|
"/api/v1/members/onboarding",
|
|
headers={"Authorization": f"Bearer {access_token}"},
|
|
json={"onboarding_data": {"dog_name": "Buddy"}, "complete_onboarding": True},
|
|
)
|
|
await client.post(
|
|
"/api/v1/members/onboarding/contract",
|
|
headers={"Authorization": f"Bearer {access_token}"},
|
|
json={"signer_name": "Jamie Smith", "agreed": True},
|
|
)
|
|
|
|
activate_response = await client.post(
|
|
f"/api/v1/admin/members/{member_id}/activate",
|
|
headers={"Authorization": f"Bearer {admin_token}"},
|
|
)
|
|
assert activate_response.status_code == 200
|
|
|
|
leads_response = await client.get(
|
|
"/api/v1/admin/leads",
|
|
headers={"Authorization": f"Bearer {admin_token}"},
|
|
)
|
|
matching_lead = next(lead for lead in leads_response.json() if lead["id"] == lead_id)
|
|
assert matching_lead["status"] == "converted"
|