First commit

This commit is contained in:
unknown
2026-06-09 21:18:13 -03:00
commit 5bff6b938b
66 changed files with 10922 additions and 0 deletions
+157
View File
@@ -0,0 +1,157 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from database import get_db
import models
import schemas
from typing import List
from datetime import datetime
from auth import get_current_user
from fastapi.responses import StreamingResponse
from io import BytesIO
from integrations.chats import TelegramChatSingleton
router = APIRouter()
# ATTACHMENT CRUD
@router.post("/attachments/", response_model=schemas.AttachmentResponse, tags=['Attachments'])
def create_attachment(attachment: schemas.AttachmentCreate, db: Session = Depends(get_db)):
# Verificar que el mensaje existe (FK compuesta)
db_message = db.query(models.Message).filter(
models.Message.id_mess_g == attachment.message_id,
models.Message.group_id == attachment.group_id
).first()
if not db_message:
raise HTTPException(status_code=404, detail="Message not found")
db_attachment = models.Attachment(**attachment.model_dump())
db.add(db_attachment)
db.commit()
db.refresh(db_attachment)
return db_attachment
@router.get("/attachments/", response_model=List[schemas.AttachmentResponse], tags=['Attachments'])
def read_attachments(skip: int = 0, limit: int = 100, db: Session = Depends(get_db), current_user: str = Depends(get_current_user)):
attachments = db.query(models.Attachment).offset(skip).limit(limit).all()
return attachments
@router.get("/attachments/{attachment_id}", response_model=schemas.AttachmentResponse, tags=['Attachments'])
def read_attachment(attachment_id: int, db: Session = Depends(get_db), current_user: str = Depends(get_current_user)):
db_attachment = db.query(models.Attachment).filter(models.Attachment.id == attachment_id).first()
if not db_attachment:
raise HTTPException(status_code=404, detail="Attachment not found")
return db_attachment
@router.put("/attachments/{attachment_id}", response_model=schemas.AttachmentResponse, tags=['Attachments'])
def update_attachment(attachment_id: int, attachment: schemas.AttachmentCreate, db: Session = Depends(get_db), current_user: str = Depends(get_current_user)):
db_attachment = db.query(models.Attachment).filter(models.Attachment.id == attachment_id).first()
if not db_attachment:
raise HTTPException(status_code=404, detail="Attachment not found")
for field, value in attachment.model_dump().items():
setattr(db_attachment, field, value)
db.commit()
db.refresh(db_attachment)
return db_attachment
@router.delete("/attachments/{attachment_id}", tags=['Attachments'])
def delete_attachment(attachment_id: int, db: Session = Depends(get_db), current_user: str = Depends(get_current_user)):
db_attachment = db.query(models.Attachment).filter(models.Attachment.id == attachment_id).first()
if not db_attachment:
raise HTTPException(status_code=404, detail="Attachment not found")
db.delete(db_attachment)
db.commit()
return {"message": "Attachment deleted successfully"}
def _download_sync(group_id: int, message_id: int) -> bytes:
"""
Descarga el media de un mensaje de Telegram de forma síncrona.
Pensado para correrse dentro de asyncio.to_thread().
Usa el TelegramChatSingleton existente para no abrir una segunda sesión.
"""
scraper = TelegramChatSingleton.get_scraper()
client = scraper.client # TelegramClient ya conectado y autorizado
# get_messages es una corrutina de Telethon — la corremos en el event loop
# del cliente, que es síncrono en el contexto del scraper
message = client.loop.run_until_complete(
client.get_messages(group_id, ids=message_id)
)
if message is None:
raise ValueError(f"Mensaje {message_id} no encontrado en grupo {group_id}")
if not message.media:
raise ValueError(f"El mensaje {message_id} no tiene media adjunta")
buffer = BytesIO()
client.loop.run_until_complete(
client.download_media(message, file=buffer)
)
buffer.seek(0)
return buffer.read()
@router.get("/attachments/{attachment_id}/download", tags=["Attachments"])
def download_attachment(
attachment_id: int,
db: Session = Depends(get_db),
current_user: str = Depends(get_current_user),
):
db_attachment = db.query(models.Attachment).filter(
models.Attachment.id == attachment_id
).first()
if not db_attachment:
raise HTTPException(status_code=404, detail="Attachment not found")
print(f"[DL] attachment encontrado: id={db_attachment.id}, type={db_attachment.type}, "
f"group_id={db_attachment.group_id}, message_id={db_attachment.message_id}")
try:
scraper = TelegramChatSingleton.get_tmp_scraper()
print(f"[DL] scraper obtenido: {scraper}")
except Exception as e:
msg = f"No se pudo obtener el scraper: {type(e).__name__}: {e}"
print(f"[DL] ERROR — {msg}")
raise HTTPException(status_code=503, detail=msg)
try:
buffer = scraper.download_attachment_to_buffer(
db_attachment.group_id,
db_attachment.message_id
)
except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
msg = f"{type(e).__name__}: {e}"
print(f"[DL] ERROR en download_attachment_to_buffer — {msg}")
raise HTTPException(status_code=503, detail=msg)
content_type_map = {
"photo": ("image/jpeg", "jpg"),
"video": ("video/mp4", "mp4"),
"audio": ("audio/mpeg", "mp3"),
"voice": ("audio/ogg", "ogg"),
"sticker": ("image/webp", "webp"),
"document": ("application/octet-stream", "bin"),
"gif": ("image/gif", "gif"),
"zip": ("application/zip", ".zip"),
"pdf": ("application/pdf", ".pdf"),
"msword": ("application/msword", ".doc"),
"vnd.openxmlformats-officedocument.wordprocessingml.document": ("application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".docx"),
"vnd.ms-excel": ("application/vnd.ms-excel", ".xls"),
"vnd.openxmlformats-officedocument.spreadsheetml.sheet": ("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".xlsx"),
"plain": ("text/plain", ".txt"),
"csv": ("text/csv", ".csv"),
}
adj_type = db_attachment.type or "document"
content_type, ext = content_type_map.get(adj_type, ("application/octet-stream", "bin"))
filename = f"attachment_{attachment_id}.{ext}"
return StreamingResponse(
buffer,
media_type=content_type,
headers={"Content-Disposition": f"attachment; filename={filename}"}
)