Skip to content
Snippets Groups Projects
Commit 5140cff7 authored by James Abrenica's avatar James Abrenica
Browse files

added fast api facebook webhook

parent 33a01716
Branches main
No related tags found
No related merge requests found
Showing
with 269 additions and 0 deletions
VERIFY_TOKEN=my_token
PAGE_ACCESS_TOKEN=104099084771493
MONGO_DETAILS=mongodb://user:password@localhost:27017
\ No newline at end of file
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
docs/_build/doctrees
docs/_build/html
docs/_build/latex
docs/_build/man
docs/_build/rst
docs/_build/texinfo
docs/_build/xml
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# dotenv
.env
.env.*
# virtualenv
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# VS Code
.vscode/
# Local IDE settings
.idea/
\ No newline at end of file
File added
File added
File added
File added
File added
from motor.motor_asyncio import AsyncIOMotorClient
import os
MONGO_DETAILS = os.getenv("MONGO_DETAILS", "mongodb://user:password@localhost:27017")
client = AsyncIOMotorClient(MONGO_DETAILS)
database = client.webhook_db
log_collection = database.get_collection("logs")
\ No newline at end of file
from fastapi import FastAPI, Request, HTTPException, Depends
from .database import log_collection
from bson import ObjectId
import logging
import os
from dotenv import load_dotenv
import httpx
import json
load_dotenv() # Load environment variables from .env file
app = FastAPI()
logging.basicConfig(level=logging.INFO)
VERIFY_TOKEN = os.getenv("VERIFY_TOKEN", "my_token")
PAGE_ACCESS_TOKEN = os.getenv("PAGE_ACCESS_TOKEN")
async def send_message(page_access_token: str, recipient_id: str, message_text: str, message_type: str = "UPDATE"):
"""
Send message to specific user (by recipient ID) from specific page (by access token).
Arguments:
page_access_token: (string) Target page access token.
recipient_id: (string) The ID of the user that the message is addressed to.
message_text: (string) The content of the message.
message_type: (string) The type of the target message.
"""
r = httpx.post(
"https://graph.facebook.com/v2.6/me/messages",
params={"access_token": page_access_token},
headers={"Content-Type": "application/json"},
json={
"recipient": {"id": recipient_id},
"message": {"text": message_text},
"messaging_type": message_type,
},
)
r.raise_for_status()
@app.get("/messaging-webhook")
async def verify_webhook(request: Request):
mode = request.query_params.get("hub.mode")
token = request.query_params.get("hub.verify_token")
challenge = request.query_params.get("hub.challenge")
logging.info(f"Received mode: {mode}, token: {token}, challenge: {challenge}, expected token: {VERIFY_TOKEN}")
if mode and token:
if mode == "subscribe" and token == VERIFY_TOKEN:
logging.info("WEBHOOK_VERIFIED")
return int(challenge)
else:
logging.error("Invalid token or mode")
raise HTTPException(status_code=403, detail="Invalid token or mode")
else:
logging.error("Missing mode or token")
raise HTTPException(status_code=400, detail="Missing mode or token")
@app.post("/messaging-webhook")
async def receive_webhook(request: Request):
try:
webhook_data = await request.json()
logging.info(f"Received webhook data: {webhook_data}")
# Insert the raw webhook data into MongoDB
result = await log_collection.insert_one(webhook_data)
logging.info(f"Inserted log with ID: {result.inserted_id}")
# Extract sender_id and message_text for sending a response
for entry in webhook_data.get("entry", []):
for messaging in entry.get("messaging", []):
sender_id = messaging.get("sender", {}).get("id")
message_text = messaging.get("message", {}).get("text")
if sender_id and message_text:
await send_message(
page_access_token=PAGE_ACCESS_TOKEN,
recipient_id=sender_id,
message_text=f"echo: {message_text}"
)
return {"status": "success"}
except Exception as e:
logging.error(f"Error processing webhook: {e}")
raise HTTPException(status_code=400, detail=str(e))
\ No newline at end of file
# models.py
from pydantic import BaseModel, Field
from typing import Optional
class Log(BaseModel):
id: Optional[str] = Field(None, alias="_id")
sender_id: str
message: str
timestamp: str
\ No newline at end of file
from pydantic import BaseModel
from typing import List
class Message(BaseModel):
mid: str
seq: int
text: str
class Messaging(BaseModel):
sender: dict
recipient: dict
timestamp: int
message: Message
class Entry(BaseModel):
id: str
time: int
messaging: List[Messaging]
class WebhookData(BaseModel):
object: str
entry: List[Entry]
\ No newline at end of file
version: '3.1'
services:
db:
image: mongo
restart: always
environment:
MONGO_INITDB_ROOT_USERNAME: user
MONGO_INITDB_ROOT_PASSWORD: password
ports:
- "27017:27017"
\ No newline at end of file
fastapi
uvicorn
sqlalchemy
psycopg2-binary
pydantic
httpx
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment