06/15 Phase 3 codes
This commit is contained in:
+151
-1
@@ -37,6 +37,155 @@ def _csrf(html):
|
||||
return re.search(r'name="csrf_token"[^>]*value="([^"]+)"', html).group(1)
|
||||
|
||||
|
||||
|
||||
def _phase3(app):
|
||||
"""Phase 3: messaging, favorites, contact masking."""
|
||||
from app.models.user import User
|
||||
from app.models.plan import Plan
|
||||
from app.models.category import Category
|
||||
from app.models.listing import Listing
|
||||
from app.models.messaging import Conversation, Message
|
||||
from app.models.enums import TrustTier
|
||||
from app.services import messaging as msvc
|
||||
from app.services import favorites as fsvc
|
||||
from app.services.contact import mask_body, contact_revealed, contact_density
|
||||
|
||||
with app.app_context():
|
||||
# create a second user (buyer)
|
||||
buyer = User(email="buyer@example.com", display_name="Buyer",
|
||||
email_verified=True)
|
||||
buyer.set_password("BuyerPass123")
|
||||
buyer.tier_id = Plan.query.filter_by(slug="free").first().id
|
||||
buyer.trust_tier = TrustTier.trusted # can see contact info
|
||||
db.session.add(buyer); db.session.commit()
|
||||
|
||||
seller = User.query.filter_by(email="t@example.com").first()
|
||||
fs = Category.query.filter_by(slug="for-sale").first()
|
||||
listing = Listing.query.filter_by(user_id=seller.id).first()
|
||||
|
||||
# --- conversation create ---
|
||||
conv, created = msvc.get_or_create_conversation(listing, buyer)
|
||||
assert created and conv.buyer_id == buyer.id
|
||||
assert conv.seller_id == seller.id
|
||||
print("conversation created: ok")
|
||||
|
||||
# idempotent: get same conv again
|
||||
conv2, created2 = msvc.get_or_create_conversation(listing, buyer)
|
||||
assert conv2.id == conv.id and not created2
|
||||
print("conversation idempotent: ok")
|
||||
|
||||
# seller can't message own listing
|
||||
try:
|
||||
msvc.get_or_create_conversation(listing, seller)
|
||||
assert False, "should have raised"
|
||||
except msvc.MessagingError:
|
||||
pass
|
||||
print("self-message blocked: ok")
|
||||
|
||||
# --- send message ---
|
||||
msg1 = msvc.send_message(conv, buyer, "Hi, is this still available?")
|
||||
assert msg1.sender_id == buyer.id and msg1.read_at is None
|
||||
assert conv.last_message_at is not None
|
||||
print("send message: ok")
|
||||
|
||||
# seller replies
|
||||
msg2 = msvc.send_message(conv, seller, "Yes, come pick it up tomorrow.")
|
||||
assert len(conv.messages) == 2
|
||||
print("reply: ok")
|
||||
|
||||
# --- unread count ---
|
||||
# buyer: 1 unread (seller's reply)
|
||||
# seller: 1 unread (buyer's opening message)
|
||||
unread_buyer = conv.unread_count(buyer)
|
||||
unread_seller = conv.unread_count(seller)
|
||||
assert unread_buyer == 1, unread_buyer
|
||||
assert unread_seller == 1, unread_seller
|
||||
print(f"unread count: ok (buyer={unread_buyer}, seller={unread_seller})")
|
||||
|
||||
# --- mark read ---
|
||||
msvc.mark_conversation_read(conv, buyer)
|
||||
assert conv.unread_count(buyer) == 0
|
||||
print("mark read: ok")
|
||||
|
||||
# --- total unread ---
|
||||
total = msvc.total_unread(seller)
|
||||
assert total >= 1
|
||||
print(f"total unread: ok (seller sees {total})")
|
||||
|
||||
# --- inbox ---
|
||||
page = msvc.inbox(buyer)
|
||||
assert any(c.id == conv.id for c in page.items)
|
||||
print("inbox: ok")
|
||||
|
||||
# --- contact masking ---
|
||||
spammy = "Call me at 703-555-0192 or email me@test.com to buy!"
|
||||
assert contact_density(spammy) == 2
|
||||
masked = mask_body(spammy, reveal=False)
|
||||
assert "703" not in masked and "me@test.com" not in masked
|
||||
revealed = mask_body(spammy, reveal=True)
|
||||
assert "703-555-0192" in revealed
|
||||
print("contact masking: ok")
|
||||
|
||||
# trusted user can reveal; new-trust cannot
|
||||
assert contact_revealed(buyer) # trust_tier=trusted + email_verified
|
||||
seller.trust_tier = TrustTier.new
|
||||
db.session.commit()
|
||||
assert not contact_revealed(seller)
|
||||
print("contact reveal gating by trust tier: ok")
|
||||
|
||||
# --- favorites ---
|
||||
now_fav = fsvc.toggle_favorite(buyer.id, listing.id)
|
||||
assert now_fav
|
||||
assert fsvc.is_favorited(buyer.id, listing.id)
|
||||
page = fsvc.user_favorites(buyer.id)
|
||||
assert any(f.listing_id == listing.id for f in page.items)
|
||||
print("favorite add: ok")
|
||||
|
||||
now_fav = fsvc.toggle_favorite(buyer.id, listing.id)
|
||||
assert not now_fav
|
||||
assert not fsvc.is_favorited(buyer.id, listing.id)
|
||||
print("favorite remove: ok")
|
||||
|
||||
# --- empty body rejected ---
|
||||
try:
|
||||
msvc.send_message(conv, buyer, " ")
|
||||
assert False
|
||||
except msvc.MessagingError:
|
||||
pass
|
||||
print("empty message rejected: ok")
|
||||
|
||||
# --- route render checks ---
|
||||
import re
|
||||
c = app.test_client(); B = "https://localhost"
|
||||
def csrf(h): return re.search(r'name="csrf_token"[^>]*value="([^"]+)"', h).group(1)
|
||||
|
||||
# login as buyer
|
||||
r = c.get("/auth/login", base_url=B)
|
||||
tok = csrf(r.get_data(as_text=True))
|
||||
c.post("/auth/login", base_url=B,
|
||||
data={"csrf_token": tok, "email": "buyer@example.com",
|
||||
"password": "BuyerPass123"},
|
||||
headers={"Referer": B + "/auth/login"}, follow_redirects=True)
|
||||
|
||||
with app.app_context():
|
||||
conv_id = Conversation.query.filter_by(
|
||||
buyer_id=User.query.filter_by(email="buyer@example.com").first().id
|
||||
).first().id
|
||||
listing_id = Listing.query.first().id
|
||||
|
||||
for path, expect in [
|
||||
("/messages", 200),
|
||||
(f"/messages/{conv_id}", 200),
|
||||
("/my/favorites", 200),
|
||||
(f"/listings/{listing_id}/contact", 200),
|
||||
]:
|
||||
code = c.get(path, base_url=B).status_code
|
||||
assert code == expect, f"{path} -> {code}"
|
||||
print(f"{code} {path}")
|
||||
|
||||
print("Phase 3 route renders: ok")
|
||||
|
||||
|
||||
def run():
|
||||
app = create_app()
|
||||
with app.app_context():
|
||||
@@ -133,6 +282,7 @@ def run():
|
||||
print("home / healthz / 404: ok")
|
||||
|
||||
_phase2(app)
|
||||
_phase3(app)
|
||||
|
||||
print("\nALL SMOKE CHECKS PASSED")
|
||||
|
||||
@@ -241,7 +391,7 @@ def _phase2(app):
|
||||
user_id=user.id, status=ListingStatus.active).count()
|
||||
assert n == 1, n
|
||||
assert active_status_after == active_status_before - 1
|
||||
assert Listing.query.get(l2.id).status == ListingStatus.expired
|
||||
assert db.session.get(Listing, l2.id).status == ListingStatus.expired
|
||||
print(f"expiry sweep: ok (status active {active_status_before}->{active_status_after})")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user