06/16 Phase 6
This commit is contained in:
+129
-4
@@ -489,6 +489,12 @@ def _phase6(app):
|
||||
from app.services import admin_users as usvc
|
||||
from app.services import admin_dashboard as dash
|
||||
from app.services.settings import get_setting, set_setting
|
||||
from app.models.report import Report
|
||||
from app.models.category import Category
|
||||
from app.models.enums import ListingStatus, ReportReason
|
||||
from app.services import listings as lsvc
|
||||
from app.services import reports as rsvc
|
||||
from app.services import moderation as msvc
|
||||
|
||||
with app.app_context():
|
||||
admin = User(email="admin@example.com", display_name="Admin",
|
||||
@@ -547,6 +553,95 @@ def _phase6(app):
|
||||
usvc.set_status(target, UserStatus.active, actor=admin)
|
||||
db.session.commit()
|
||||
|
||||
# --- keyword blocklist: auto-flag on create ---
|
||||
for_sale = Category.query.filter_by(slug="for-sale").first()
|
||||
set_setting("keyword_blocklist", ["viagra"])
|
||||
db.session.commit()
|
||||
spammy = lsvc.create_listing(target, for_sale, title="Cheap meds",
|
||||
body="Buy real viagra online cheap",
|
||||
lang="en", price_cents=500, zip_code="92683",
|
||||
raw_attributes={"condition": "new"})
|
||||
assert spammy.status == ListingStatus.flagged
|
||||
print("keyword blocklist auto-flags on create: ok")
|
||||
|
||||
# --- keyword blocklist: auto-flag on update ---
|
||||
clean = lsvc.create_listing(target, for_sale, title="Clean Listing",
|
||||
body="A perfectly normal item for sale.",
|
||||
lang="en", price_cents=500, zip_code="92683",
|
||||
raw_attributes={"condition": "new"})
|
||||
assert clean.status == ListingStatus.active
|
||||
lsvc.update_listing(clean, for_sale, title="Clean Listing",
|
||||
body="Now selling viagra too", lang="en",
|
||||
price_cents=500, zip_code="92683",
|
||||
raw_attributes={"condition": "new"})
|
||||
assert clean.status == ListingStatus.flagged
|
||||
print("keyword blocklist auto-flags on update: ok")
|
||||
set_setting("keyword_blocklist", [])
|
||||
db.session.commit()
|
||||
|
||||
# --- reports: self-report blocked ---
|
||||
report_target = lsvc.create_listing(target, for_sale, title="Reportable Item",
|
||||
body="Nothing wrong with this one.",
|
||||
lang="en", price_cents=1000, zip_code="92683",
|
||||
raw_attributes={"condition": "new"})
|
||||
try:
|
||||
rsvc.create_report(report_target, target, ReportReason.spam)
|
||||
assert False, "expected self-report to be blocked"
|
||||
except rsvc.ReportError as e:
|
||||
assert "own listing" in str(e)
|
||||
print("self-report blocked: ok")
|
||||
|
||||
# --- reports: duplicate report blocked ---
|
||||
buyer = User.query.filter_by(email="buyer@example.com").first()
|
||||
rsvc.create_report(report_target, buyer, ReportReason.spam, note="looks fake")
|
||||
try:
|
||||
rsvc.create_report(report_target, buyer, ReportReason.scam)
|
||||
assert False, "expected duplicate report to be blocked"
|
||||
except rsvc.ReportError as e:
|
||||
assert "already reported" in str(e)
|
||||
print("duplicate report blocked: ok")
|
||||
|
||||
# --- reports: threshold auto-flags ---
|
||||
set_setting("flag_threshold", 2)
|
||||
db.session.commit()
|
||||
assert report_target.flag_count == 1
|
||||
assert report_target.status == ListingStatus.active
|
||||
rsvc.create_report(report_target, admin, ReportReason.scam)
|
||||
assert report_target.flag_count == 2
|
||||
assert report_target.status == ListingStatus.flagged
|
||||
print(f"report threshold auto-flag: ok (flag_count={report_target.flag_count})")
|
||||
|
||||
# --- moderation actions + audit log ---
|
||||
msvc.approve(report_target, actor=admin)
|
||||
db.session.commit()
|
||||
assert report_target.status == ListingStatus.active and report_target.flag_count == 0
|
||||
assert AuditLog.query.filter_by(action="listing.approved",
|
||||
target_id=report_target.id).count() == 1
|
||||
print("moderation approve + audit log: ok")
|
||||
|
||||
msvc.hide(spammy, actor=admin)
|
||||
db.session.commit()
|
||||
assert spammy.status == ListingStatus.flagged
|
||||
assert AuditLog.query.filter_by(action="listing.hidden",
|
||||
target_id=spammy.id).count() == 1
|
||||
print("moderation hide + audit log: ok")
|
||||
|
||||
msvc.remove(clean, actor=admin)
|
||||
db.session.commit()
|
||||
assert clean.status == ListingStatus.removed
|
||||
assert AuditLog.query.filter_by(action="listing.removed",
|
||||
target_id=clean.id).count() == 1
|
||||
print("moderation remove + audit log: ok")
|
||||
|
||||
# lower threshold to 1 so a single HTTP report flips status for the next check
|
||||
set_setting("flag_threshold", 1)
|
||||
http_listing = lsvc.create_listing(target, for_sale, title="HTTP Report Test",
|
||||
body="Totally fine listing.", lang="en",
|
||||
price_cents=750, zip_code="92683",
|
||||
raw_attributes={"condition": "new"})
|
||||
http_listing_id = http_listing.id
|
||||
db.session.commit()
|
||||
|
||||
# --- route checks ---
|
||||
c = app.test_client(); B = "https://localhost"
|
||||
|
||||
@@ -562,15 +657,17 @@ def _phase6(app):
|
||||
|
||||
# non-admin gets 403
|
||||
login("t@example.com", "NewPass456")
|
||||
assert c.get("/admin", base_url=B).status_code == 403
|
||||
print("non-admin /admin -> 403: ok")
|
||||
for path in ("/admin", "/admin/listings", "/admin/reports"):
|
||||
assert c.get(path, base_url=B).status_code == 403
|
||||
print("non-admin /admin* -> 403: ok")
|
||||
c.get("/auth/logout", base_url=B)
|
||||
|
||||
# admin gets 200 on dashboard/users/user_detail
|
||||
# admin gets 200 on dashboard/users/user_detail/listings/reports
|
||||
login("admin@example.com", "AdminPass123")
|
||||
with app.app_context():
|
||||
target_id = User.query.filter_by(email="t@example.com").first().id
|
||||
for path in ("/admin", "/admin/users", f"/admin/users/{target_id}"):
|
||||
for path in ("/admin", "/admin/users", f"/admin/users/{target_id}",
|
||||
"/admin/listings", "/admin/reports"):
|
||||
code = c.get(path, base_url=B).status_code
|
||||
assert code == 200, f"{path} -> {code}"
|
||||
print(f"{code} {path}")
|
||||
@@ -590,6 +687,34 @@ def _phase6(app):
|
||||
assert "suspended" in r.get_data(as_text=True).lower()
|
||||
print("banned user login rejected: ok")
|
||||
|
||||
# buyer reports a listing via the real HTTP route
|
||||
c.get("/auth/logout", base_url=B)
|
||||
login("buyer@example.com", "BuyerPass123")
|
||||
r = c.get(f"/listings/{http_listing_id}", base_url=B)
|
||||
tok = csrf(r.get_data(as_text=True))
|
||||
c.post(f"/listings/{http_listing_id}/report", base_url=B,
|
||||
data={"csrf_token": tok, "reason": "spam", "note": "test report"},
|
||||
headers={"Referer": B + f"/listings/{http_listing_id}"}, follow_redirects=True)
|
||||
with app.app_context():
|
||||
rep = Report.query.filter_by(listing_id=http_listing_id).first()
|
||||
assert rep is not None and rep.reason == ReportReason.spam
|
||||
report_id = rep.id
|
||||
assert db.session.get(Listing, http_listing_id).status == ListingStatus.flagged
|
||||
print("user-facing report route: ok")
|
||||
|
||||
# admin sees it in the open reports queue, dismisses it, it disappears
|
||||
c.get("/auth/logout", base_url=B)
|
||||
login("admin@example.com", "AdminPass123")
|
||||
r = c.get("/admin/reports", base_url=B)
|
||||
assert "HTTP Report Test" in r.get_data(as_text=True)
|
||||
tok = csrf(r.get_data(as_text=True))
|
||||
c.post(f"/admin/reports/{report_id}/dismiss", base_url=B,
|
||||
data={"csrf_token": tok},
|
||||
headers={"Referer": B + "/admin/reports"}, follow_redirects=True)
|
||||
r2 = c.get("/admin/reports", base_url=B)
|
||||
assert "HTTP Report Test" not in r2.get_data(as_text=True)
|
||||
print("report dismiss hides from open queue: ok")
|
||||
|
||||
# restore target to active for cleanliness (not strictly needed, smoke ends here)
|
||||
with app.app_context():
|
||||
u = User.query.filter_by(email="t@example.com").first()
|
||||
|
||||
Reference in New Issue
Block a user