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}"} )