06/15 Phase 3 codes
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
"""Contact masking.
|
||||
|
||||
Phone numbers and email addresses in listing bodies / messages are masked
|
||||
for low-trust senders to push communication through the in-site channel.
|
||||
Unmasked only once sender reaches TrustTier.trusted or verified_email=True.
|
||||
|
||||
Masking is a display-layer concern: raw body stored as-is; masked on render.
|
||||
For the *sending* side we heuristic-flag high-contact-density messages so
|
||||
moderators can spot scraping attempts.
|
||||
"""
|
||||
import re
|
||||
from app.models.enums import TrustTier
|
||||
|
||||
# patterns
|
||||
_PHONE_RE = re.compile(
|
||||
r"(\+?1[\s\-.]?)?"
|
||||
r"(\(?\d{3}\)?[\s\-.])"
|
||||
r"\d{3}[\s\-.]\d{4}"
|
||||
)
|
||||
_EMAIL_RE = re.compile(r"[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}")
|
||||
_URL_RE = re.compile(r"https?://\S+|www\.\S+", re.I)
|
||||
|
||||
|
||||
def contact_revealed(user) -> bool:
|
||||
"""True when this user's contact info may be shown unmasked."""
|
||||
if user is None:
|
||||
return False
|
||||
return (user.email_verified and
|
||||
user.trust_tier in (TrustTier.trusted, TrustTier.verified))
|
||||
|
||||
|
||||
def mask_body(text: str, reveal: bool = False) -> str:
|
||||
"""Optionally mask phones, emails, and URLs in a block of text."""
|
||||
if reveal or not text:
|
||||
return text
|
||||
text = _PHONE_RE.sub("[phone hidden]", text)
|
||||
text = _EMAIL_RE.sub("[email hidden]", text)
|
||||
text = _URL_RE.sub("[link hidden]", text)
|
||||
return text
|
||||
|
||||
|
||||
def contact_density(text: str) -> int:
|
||||
"""Count how many contact signals appear in text (for heuristic flagging)."""
|
||||
if not text:
|
||||
return 0
|
||||
return (len(_PHONE_RE.findall(text))
|
||||
+ len(_EMAIL_RE.findall(text))
|
||||
+ len(_URL_RE.findall(text)))
|
||||
Reference in New Issue
Block a user