# retoor <retoor@molodetz.nl>
import time
import pytest
import requests
from devplacepy.database import REPORTABLE_TARGETS, get_table, refresh_snapshot
from tests.conftest import BASE_URL
JSON = {"Accept": "application/json"}
_counter = [0]
def _unique(prefix="rep"):
_counter[0] += 1
return f"{prefix}{int(time.time() * 1000)}{_counter[0]}"
def _member():
name = _unique()
session = requests.Session()
session.post(
f"{BASE_URL}/auth/signup",
data={
"username": name,
"email": f"{name}@t.dev",
"password": "secret123",
"confirm_password": "secret123",
"birth_date": "1990-01-01",
"accept_terms": "1",
},
allow_redirects=True,
)
return session, name
def _post(session, title="Reportable post"):
response = session.post(
f"{BASE_URL}/posts/create",
data={"title": title, "content": "A post that can be reported by others."},
headers=JSON,
)
assert response.status_code == 200, response.text
return response.json()["data"]["uid"]
def _reports_for(target_type, target_uid):
refresh_snapshot()
return list(
get_table("content_reports").find(
target_type=target_type, target_uid=target_uid, deleted_at=None
)
)
@pytest.fixture(scope="module")
def author(app_server):
return _member()
def test_report_reasons_are_public(app_server):
response = requests.get(f"{BASE_URL}/reports/reasons", headers=JSON)
assert response.status_code == 200
keys = {entry["key"] for entry in response.json()["reasons"]}
assert {"harassment", "spam", "intellectual_property", "other"} <= keys
def test_the_reasons_page_is_indexable_with_breadcrumbs_and_a_site_schema(app_server):
html = requests.get(f"{BASE_URL}/reports/reasons").text
assert '<meta name="robots" content="index,follow">' in html
assert 'class="breadcrumb"' in html
assert "Report reasons" in html
assert '"@type": "WebSite"' in html
def test_the_reasons_page_title_carries_one_site_suffix(app_server):
html = requests.get(f"{BASE_URL}/reports/reasons").text
start = html.index("<title>") + len("<title>")
title = html[start : html.index("</title>", start)]
assert title == "Report reasons - DevPlace", title
def test_reporting_a_post_records_one_row_with_the_owner(author):
author_session, author_name = author
post_uid = _post(author_session)
reporter, _ = _member()
response = reporter.post(
f"{BASE_URL}/reports/post/{post_uid}",
data={"reason": "harassment", "detail": "Targets me personally."},
headers=JSON,
)
assert response.status_code == 200, response.text
assert response.json()["data"]["status"] == "open"
rows = _reports_for("post", post_uid)
assert len(rows) == 1
owner = get_table("users").find_one(username=author_name)
assert rows[0]["owner_uid"] == owner["uid"]
assert rows[0]["origin"] == "member"
def test_second_report_by_the_same_reporter_updates_instead_of_duplicating(author):
author_session, _ = author
post_uid = _post(author_session)
reporter, _ = _member()
for reason in ("spam", "harassment"):
response = reporter.post(
f"{BASE_URL}/reports/post/{post_uid}",
data={"reason": reason},
headers=JSON,
)
assert response.status_code == 200
rows = _reports_for("post", post_uid)
assert len(rows) == 1
assert rows[0]["reason"] == "harassment"
def test_a_different_reporter_creates_a_second_row(author):
author_session, _ = author
post_uid = _post(author_session)
for _ in range(2):
reporter, _ = _member()
reporter.post(
f"{BASE_URL}/reports/post/{post_uid}",
data={"reason": "spam"},
headers=JSON,
)
assert len(_reports_for("post", post_uid)) == 2
def test_guests_cannot_report(author):
author_session, _ = author
post_uid = _post(author_session)
response = requests.post(
f"{BASE_URL}/reports/post/{post_uid}",
data={"reason": "spam"},
headers=JSON,
)
assert response.status_code == 401
def test_reporting_your_own_content_is_refused(author):
author_session, _ = author
post_uid = _post(author_session)
response = author_session.post(
f"{BASE_URL}/reports/post/{post_uid}",
data={"reason": "spam"},
headers=JSON,
)
assert response.status_code == 400
assert _reports_for("post", post_uid) == []
def test_an_unknown_target_type_is_refused(author):
reporter, _ = _member()
response = reporter.post(
f"{BASE_URL}/reports/not_a_surface/whatever",
data={"reason": "spam"},
headers=JSON,
)
assert response.status_code == 400
def test_an_unknown_reason_is_refused(author):
author_session, _ = author
post_uid = _post(author_session)
reporter, _ = _member()
response = reporter.post(
f"{BASE_URL}/reports/post/{post_uid}",
data={"reason": "not_a_reason"},
headers=JSON,
)
assert response.status_code == 422
def test_every_registry_target_type_is_accepted_by_the_route(author):
author_session, _ = author
reporter, _ = _member()
for target_type in REPORTABLE_TARGETS:
response = reporter.post(
f"{BASE_URL}/reports/{target_type}/missing-{target_type}",
data={"reason": "other"},
headers=JSON,
)
assert response.status_code == 200, f"{target_type}: {response.text}"
def test_the_report_dialog_uses_the_shared_auth_field_classes(app_server):
reporter, _ = _member()
html = reporter.get(f"{BASE_URL}/feed").text
assert 'id="report-dialog"' in html
assert 'class="auth-field auth-field-gap"' in html
assert 'class="modal-footer"' in html
assert 'id="report-reason"' in html
assert 'id="report-detail"' in html
def test_your_reports_page_loads_the_admin_table_styles(author):
author_session, _ = author
post_uid = _post(author_session)
reporter, _ = _member()
reporter.post(
f"{BASE_URL}/reports/post/{post_uid}", data={"reason": "spam"}, headers=JSON
)
html = reporter.get(f"{BASE_URL}/reports/mine").text
assert "css/admin.css" in html
assert 'class="admin-table"' in html
def test_mine_lists_only_your_own_reports(author):
author_session, _ = author
post_uid = _post(author_session)
mine, _ = _member()
other, _ = _member()
mine.post(
f"{BASE_URL}/reports/post/{post_uid}", data={"reason": "spam"}, headers=JSON
)
other.post(
f"{BASE_URL}/reports/post/{post_uid}",
data={"reason": "harassment"},
headers=JSON,
)
payload = mine.get(f"{BASE_URL}/reports/mine", headers=JSON).json()
reasons = {entry["reason"] for entry in payload["reports"]}
assert "spam" in reasons
assert "harassment" not in reasons
assert requests.get(f"{BASE_URL}/reports/mine", headers=JSON).status_code == 401