Initial commit: site monorepo with API, web, and infra.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
from tests.fixtures import make_test_png
|
||||
from tests.helpers import latest_token, register_and_verify, register_verify_login
|
||||
|
||||
|
||||
def _admin_headers(client) -> dict[str, str]:
|
||||
login = client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={"email": "admin@compton.example", "password": "Admin1234"},
|
||||
)
|
||||
token = login.json()["access_token"]
|
||||
return {"Authorization": f"Bearer {token}"}
|
||||
|
||||
|
||||
def test_auth_refresh_and_logout(client):
|
||||
register_and_verify(client, "refresh@example.com")
|
||||
login = client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={"email": "refresh@example.com", "password": "Valid123"},
|
||||
)
|
||||
assert login.status_code == 200
|
||||
assert "refresh_token" in login.cookies
|
||||
|
||||
refresh = client.post("/api/v1/auth/refresh", headers={"Origin": "http://localhost:5173"})
|
||||
assert refresh.status_code == 200
|
||||
assert "access_token" in refresh.json()
|
||||
|
||||
logout = client.post("/api/v1/auth/logout", headers={"Origin": "http://localhost:5173"})
|
||||
assert logout.status_code == 200
|
||||
|
||||
|
||||
def test_auth_invalid_login(client):
|
||||
response = client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={"email": "missing@example.com", "password": "Valid123"},
|
||||
)
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_users_patch_and_password_and_avatar(client):
|
||||
headers = register_verify_login(client, "patch@example.com")
|
||||
patch = client.patch("/api/v1/users/me", headers=headers, json={"display_name": "Patched"})
|
||||
assert patch.status_code == 200
|
||||
assert patch.json()["profile"]["display_name"] == "Patched"
|
||||
|
||||
bad_password = client.post(
|
||||
"/api/v1/users/me/password",
|
||||
headers=headers,
|
||||
json={"current_password": "wrong", "new_password": "NewValid1"},
|
||||
)
|
||||
assert bad_password.status_code == 400
|
||||
|
||||
avatar = client.post(
|
||||
"/api/v1/users/me/avatar",
|
||||
headers=headers,
|
||||
files={"file": ("avatar.png", make_test_png(), "image/png")},
|
||||
)
|
||||
assert avatar.status_code == 200
|
||||
assert avatar.json()["profile"]["avatar_url"]
|
||||
|
||||
|
||||
def test_users_unauthorized(client):
|
||||
response = client.get("/api/v1/users/me")
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
def test_content_crud_flow(client):
|
||||
headers = _admin_headers(client)
|
||||
created = client.post(
|
||||
"/api/v1/content/pages",
|
||||
headers=headers,
|
||||
json={"slug": "terms", "title": "Terms", "body": "<p>Terms</p>", "status": "draft"},
|
||||
)
|
||||
assert created.status_code == 200
|
||||
page_id = created.json()["id"]
|
||||
|
||||
listed = client.get("/api/v1/content/pages")
|
||||
assert listed.status_code == 200
|
||||
|
||||
updated = client.patch(
|
||||
f"/api/v1/content/pages/{page_id}",
|
||||
headers=headers,
|
||||
json={"status": "published"},
|
||||
)
|
||||
assert updated.status_code == 200
|
||||
|
||||
fetched = client.get("/api/v1/content/pages/terms")
|
||||
assert fetched.status_code == 200
|
||||
|
||||
deleted = client.delete(f"/api/v1/content/pages/{page_id}", headers=headers)
|
||||
assert deleted.status_code == 200
|
||||
|
||||
|
||||
def test_admin_stats_and_patch_user(client):
|
||||
headers = _admin_headers(client)
|
||||
stats = client.get("/api/v1/admin/stats", headers=headers)
|
||||
assert stats.status_code == 200
|
||||
|
||||
user_headers = register_verify_login(client, "blockme@example.com")
|
||||
me = client.get("/api/v1/users/me", headers=user_headers)
|
||||
user_id = me.json()["user"]["id"]
|
||||
|
||||
blocked = client.patch(
|
||||
f"/api/v1/admin/users/{user_id}",
|
||||
headers=headers,
|
||||
json={"status": "blocked"},
|
||||
)
|
||||
assert blocked.status_code == 200
|
||||
assert blocked.json()["status"] == "blocked"
|
||||
|
||||
|
||||
def test_auth_pending_user_cannot_login(client):
|
||||
client.post("/api/v1/auth/register", json={"email": "pending@example.com", "password": "Valid123"})
|
||||
response = client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={"email": "pending@example.com", "password": "Valid123"},
|
||||
)
|
||||
assert response.status_code == 403
|
||||
assert response.json()["detail"] == "EMAIL_NOT_VERIFIED"
|
||||
|
||||
|
||||
def test_pending_user_cannot_access_profile(client):
|
||||
from app.core.security import create_access_token
|
||||
from app.modules.users.repository import get_user_by_email
|
||||
|
||||
client.post("/api/v1/auth/register", json={"email": "pendingme@example.com", "password": "Valid123"})
|
||||
user = get_user_by_email("pendingme@example.com")
|
||||
token = create_access_token(user.id, user.role)
|
||||
response = client.get("/api/v1/users/me", headers={"Authorization": f"Bearer {token}"})
|
||||
assert response.status_code == 403
|
||||
assert response.json()["detail"] == "EMAIL_NOT_VERIFIED"
|
||||
|
||||
|
||||
def test_auth_invalid_refresh_token(client):
|
||||
response = client.post("/api/v1/auth/refresh")
|
||||
assert response.status_code == 401
|
||||
|
||||
client.cookies.set("refresh_token", "invalid-token", path="/api/v1/auth")
|
||||
invalid = client.post("/api/v1/auth/refresh", headers={"Origin": "http://localhost:5173"})
|
||||
assert invalid.status_code == 401
|
||||
|
||||
|
||||
def test_auth_resend_and_reset_password(client):
|
||||
client.post("/api/v1/auth/register", json={"email": "resetme@example.com", "password": "Valid123"})
|
||||
resend = client.post("/api/v1/auth/resend-verification", json={"email": "resetme@example.com"})
|
||||
assert resend.status_code == 200
|
||||
verify_token = latest_token("resetme@example.com", "verify_email")
|
||||
verify = client.post("/api/v1/auth/verify-email", json={"token": verify_token})
|
||||
assert verify.status_code == 200
|
||||
|
||||
forgot = client.post("/api/v1/auth/forgot-password", json={"email": "resetme@example.com"})
|
||||
assert forgot.status_code == 200
|
||||
reset_token = latest_token("resetme@example.com", "reset_password")
|
||||
|
||||
reset = client.post(
|
||||
"/api/v1/auth/reset-password",
|
||||
json={"token": reset_token, "new_password": "NewValid1"},
|
||||
)
|
||||
assert reset.status_code == 200
|
||||
|
||||
login = client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={"email": "resetme@example.com", "password": "NewValid1"},
|
||||
)
|
||||
assert login.status_code == 200
|
||||
|
||||
invalid = client.post(
|
||||
"/api/v1/auth/reset-password",
|
||||
json={"token": "invalid-token", "new_password": "NewValid1"},
|
||||
)
|
||||
assert invalid.status_code == 400
|
||||
Reference in New Issue
Block a user