Ekaropolus c954488c28
All checks were successful
continuous-integration/drone/push Build is passing
FIX AGAIN
2025-09-07 03:28:08 -06:00

127 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# /home/polisplexity/polisplexity/pxy_meta_pages/views.py
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
import json, logging, hmac, hashlib
from .webhook_handlers import (
verify_webhook_token, # keep using your apps style if you already have it
parse_webhook_payload, # your existing parser for Page feed "changes"
handle_comment_event, # existing
handle_share_event, # existing
handle_message_event, # NEW (youll add it below)
handle_postback_event, # NEW (youll add it below)
)
logger = logging.getLogger(__name__)
VERIFY_TOKEN = getattr(settings, "VERIFY_TOKEN", "")
APP_SECRET = getattr(settings, "APP_SECRET", "") # add this in settings/.env
VERIFY_SIG = getattr(settings, "VERIFY_SIGNATURE", True) # optional toggle (default True)
def _valid_signature(raw_body: bytes, header: str) -> bool:
"""
Verify X-Hub-Signature-256 header using APP_SECRET (recommended by Meta).
"""
if not VERIFY_SIG:
return True
if not APP_SECRET:
logger.warning("APP_SECRET not set; skipping signature verification.")
return True
if not header or not header.startswith("sha256="):
logger.warning("Missing/invalid X-Hub-Signature-256 header.")
return False
received = header.split("=", 1)[1]
expected = hmac.new(APP_SECRET.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(received, expected)
if not ok:
logger.warning("Signature mismatch on webhook payload.")
return ok
@csrf_exempt
def facebook_webhook(request):
"""
One endpoint for:
- GET: webhook verification (Messenger)
- POST: Page feed changes (comment/share) and Messenger events (messages/postbacks)
"""
# --- GET VERIFICATION (fixes 405) ---
if request.method == "GET":
mode = request.GET.get("hub.mode")
token = request.GET.get("hub.verify_token")
challenge = request.GET.get("hub.challenge", "")
# Use your helper if you prefer: verify_webhook_token(token)
if mode == "subscribe" and token == VERIFY_TOKEN:
return HttpResponse(challenge, status=200)
return HttpResponse("Forbidden", status=403)
# --- EVENTS ---
if request.method == "POST":
raw = request.body or b""
# Verify signature (recommended)
sig = request.META.get("HTTP_X_HUB_SIGNATURE_256")
if not _valid_signature(raw, sig):
return JsonResponse({"error": "Invalid signature"}, status=403)
try:
payload = json.loads(raw.decode("utf-8") or "{}")
entries = payload.get("entry", [])
for entry in entries:
page_id = entry.get("id")
keys = list(entry.keys())
print(f"[WEBHOOK] entry0.keys={keys}", flush=True)
# ---- Messenger events ----
if "messaging" in entry:
for evt in entry.get("messaging", []):
sender_id = (evt.get("sender") or {}).get("id")
# Log similar to your current style
print(f"[WEBHOOK] MESSENGER page={page_id} psid={sender_id}", flush=True)
# Message (avoid echo loops)
msg = evt.get("message")
if msg and not msg.get("is_echo"):
# Let your handler decide what to do (persist PSID, enqueue reply, etc.)
resp = handle_message_event(page_id, sender_id, msg)
if resp is not None:
return resp
# Postback (Get Started, buttons, persistent menu)
postback = evt.get("postback")
if postback:
resp = handle_postback_event(page_id, sender_id, postback)
if resp is not None:
return resp
# ---- Page feed changes (your existing flow) ----
if "changes" in entry:
# Keep your existing parse + handlers untouched
data = parse_webhook_payload(payload)
sender = (data.get("from") or {}).get("id")
item_type = data.get("item")
# Optional: quick visibility
print(f"[WEBHOOK] page_id={page_id} item_type={item_type!r}", flush=True)
if item_type == "share":
resp = handle_share_event(page_id, data)
if resp is not None:
return resp
elif item_type == "comment":
resp = handle_comment_event(page_id, sender, data)
if resp is not None:
return resp
# Acknowledge within 5s
return JsonResponse({"status": "ok"}, status=200)
except json.JSONDecodeError:
logger.exception("Invalid JSON payload")
return JsonResponse({"error": "Invalid JSON payload"}, status=400)
except Exception as e:
logger.exception("Error processing webhook")
return JsonResponse({"error": str(e)}, status=500)
# Anything elses
logger.warning(f"Received unsupported HTTP method: {request.method}")
return HttpResponse("Method Not Allowed", status=405)