pryscraper/routers/integrations.py
cryptorugmunch 2f1eec2f78
Some checks failed
CI / lint (pull_request) Successful in 33s
CI / typecheck (pull_request) Failing after 1m42s
CI / test (pull_request) Failing after 2m33s
CI / security (pull_request) Failing after 39s
CI / gitleaks (pull_request) Successful in 36s
CI / commitlint (pull_request) Failing after 10s
style: ruff format
2026-07-03 18:12:36 +02:00

138 lines
4.4 KiB
Python

"""Pry — Integrations router (remaining api.py routes).
Auto-extracted from api.py during the router-split refactor.
"""
# SPDX-License-Identifier: MIT
# Copyright (c) 2026 Rug Munch Media LLC
from __future__ import annotations
import logging
from typing import Any
from fastapi import APIRouter, Body
from deps import scraper
from errors import InvalidRequestError, ScrapeError
logger = logging.getLogger(__name__)
router = APIRouter(tags=["Integrations"])
@router.get(
"/v1/destinations",
tags=["Integrations"],
summary="List supported data destinations",
)
async def list_destinations() -> dict[str, Any]:
"""List all supported data destinations and their config requirements."""
return {
"success": True,
"data": {
"destinations": [
{
"id": "slack",
"name": "Slack",
"description": "Send data to a Slack channel via webhook",
"config_fields": ["webhook_url", "title"],
},
{
"id": "googlesheets",
"name": "Google Sheets",
"description": "Write data to a Google Spreadsheet",
"config_fields": ["spreadsheet_id", "range", "credentials_json"],
},
{
"id": "airtable",
"name": "Airtable",
"description": "Write records to an Airtable base",
"config_fields": ["base_id", "table_name", "api_key"],
},
{
"id": "email",
"name": "Email",
"description": "Send data via email (SMTP or mailto link)",
"config_fields": ["recipient", "subject", "smtp_host", "smtp_user"],
},
]
},
}
@router.post(
"/v1/destination/send",
tags=["Integrations"],
summary="Send scraped data to a business destination",
)
async def send_to_destination(
destination: str = Body(...),
data: dict[str, Any] = Body(...),
config: dict[str, Any] = Body(...),
url: str | None = Body(None),
) -> dict[str, Any]:
"""Send extracted data to a business destination in one click.
Destinations:
- slack: Send to Slack channel via webhook
- googlesheets: Write to Google Sheets (requires credentials)
- airtable: Write to Airtable base (requires API key)
- email: Send via email (requires SMTP config)
Config varies by destination:
- slack: {"webhook_url": "https://hooks.slack.com/..."}
- googlesheets: {"spreadsheet_id": "...", "credentials_json": "..."}
- airtable: {"base_id": "...", "table_name": "Table 1", "api_key": "..."}
- email: {"recipient": "user@example.com", "subject": "Data Export"}
"""
from destinations import SUPPORTED_DESTINATIONS, dispatch
if destination not in SUPPORTED_DESTINATIONS:
raise InvalidRequestError(
f"Unsupported destination: {destination}. Supported: {SUPPORTED_DESTINATIONS}"
)
result = await dispatch(destination, data, config)
return {"success": result["success"], "data": result}
@router.post(
"/v1/scrape-and-send",
tags=["Integrations"],
summary="Scrape a URL and send to a destination",
)
async def scrape_and_send(
url: str = Body(...),
destination: str = Body(...),
destination_config: dict[str, Any] = Body(...),
) -> dict[str, Any]:
"""Scrape a URL and send the results to a business destination in one step.
Combines /v1/scrape + /v1/destination/send into a single call.
Perfect for non-technical users who just want data in their tools.
"""
from destinations import SUPPORTED_DESTINATIONS, dispatch
if destination not in SUPPORTED_DESTINATIONS:
raise InvalidRequestError(
f"Unsupported destination: {destination}. Supported: {SUPPORTED_DESTINATIONS}"
)
# Scrape
result = await scraper.scrape(url, {"bypass_cloudflare": True})
if result.get("status") != "ok":
raise ScrapeError(result.get("error") or "Scrape failed")
# Send to destination
send_result = await dispatch(destination, result.get("data", result), destination_config)
return {
"success": send_result["success"],
"data": {
"url": url,
"destination": destination,
"scrape_status": result.get("status"),
"delivery": send_result,
},
}