Telegram:
- /start <contact_id> Deep-Link Handler: verknüpft Kontakt automatisch mit chat_id
- QR-Code Endpunkt GET /api/v1/contacts/{id}/telegram-qr (PNG)
- TUI: Taste T öffnet QR-Code im Browser (HTML mit eingebettetem PNG)
- config.py + .env.example: TELEGRAM_BOT_USERNAME=mcm_bot
- qrcode[pil] zu requirements.txt hinzugefügt
WhatsApp:
- receiveTimeout 5→3s, HTTP-Timeout 8s → verhindert Polling-Overlap
91 lines
2.8 KiB
Python
91 lines
2.8 KiB
Python
import io
|
|
|
|
import qrcode
|
|
from fastapi import APIRouter, Depends, HTTPException, status
|
|
from fastapi.responses import StreamingResponse
|
|
from sqlalchemy.orm import Session
|
|
|
|
from api.auth import require_api_key
|
|
from config import settings
|
|
from db.database import get_db
|
|
from schemas import ContactCreate, ContactResponse, ContactUpdate
|
|
from services import contact_service
|
|
|
|
router = APIRouter(prefix="/contacts", tags=["contacts"])
|
|
|
|
|
|
@router.get("/", response_model=list[ContactResponse])
|
|
def list_contacts(db: Session = Depends(get_db), _: str = Depends(require_api_key)):
|
|
return contact_service.get_all(db)
|
|
|
|
|
|
@router.post("/", response_model=ContactResponse, status_code=status.HTTP_201_CREATED)
|
|
def create_contact(
|
|
data: ContactCreate,
|
|
db: Session = Depends(get_db),
|
|
_: str = Depends(require_api_key),
|
|
):
|
|
return contact_service.create(db, data)
|
|
|
|
|
|
@router.get("/{contact_id}", response_model=ContactResponse)
|
|
def get_contact(
|
|
contact_id: str,
|
|
db: Session = Depends(get_db),
|
|
_: str = Depends(require_api_key),
|
|
):
|
|
contact = contact_service.get_by_id(db, contact_id)
|
|
if not contact:
|
|
raise HTTPException(status_code=404, detail="Contact not found")
|
|
return contact
|
|
|
|
|
|
@router.put("/{contact_id}", response_model=ContactResponse)
|
|
def update_contact(
|
|
contact_id: str,
|
|
data: ContactUpdate,
|
|
db: Session = Depends(get_db),
|
|
_: str = Depends(require_api_key),
|
|
):
|
|
contact = contact_service.get_by_id(db, contact_id)
|
|
if not contact:
|
|
raise HTTPException(status_code=404, detail="Contact not found")
|
|
return contact_service.update(db, contact, data)
|
|
|
|
|
|
@router.delete("/{contact_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
def delete_contact(
|
|
contact_id: str,
|
|
db: Session = Depends(get_db),
|
|
_: str = Depends(require_api_key),
|
|
):
|
|
contact = contact_service.get_by_id(db, contact_id)
|
|
if not contact:
|
|
raise HTTPException(status_code=404, detail="Contact not found")
|
|
contact_service.delete(db, contact)
|
|
|
|
|
|
@router.get("/{contact_id}/telegram-qr", tags=["contacts"])
|
|
def telegram_qr(
|
|
contact_id: str,
|
|
db: Session = Depends(get_db),
|
|
_: str = Depends(require_api_key),
|
|
):
|
|
"""QR-Code als PNG: Invite-Link für Telegram-Bot mit Kontakt-ID als Deep-Link-Parameter."""
|
|
contact = contact_service.get_by_id(db, contact_id)
|
|
if not contact:
|
|
raise HTTPException(status_code=404, detail="Contact not found")
|
|
|
|
bot_username = settings.telegram_bot_username.lstrip("@")
|
|
invite_url = f"https://t.me/{bot_username}?start={contact_id}"
|
|
|
|
img = qrcode.make(invite_url)
|
|
buf = io.BytesIO()
|
|
img.save(buf, format="PNG")
|
|
buf.seek(0)
|
|
return StreamingResponse(
|
|
buf,
|
|
media_type="image/png",
|
|
headers={"Content-Disposition": f'attachment; filename="telegram_qr_{contact_id}.png"'},
|
|
)
|