File size: 5,719 Bytes
792ad00
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
951d5c6
 
 
792ad00
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
from fastapi import APIRouter, Depends, UploadFile, File, HTTPException
from typing import List
from sqlalchemy.orm import Session
from services.s3_service import s3_service
from api.auth import get_current_user
from core.database import get_db
from models import db_models
from models.schemas import SourceFileResponse
from services.rag_service import rag_service

router = APIRouter(prefix="/api/sources", tags=["sources"])

@router.post("/upload", response_model=dict)
async def upload_source(
    file: UploadFile = File(...),
    current_user: db_models.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    try:
        content = await file.read()
        file_info = await s3_service.upload_file(
            file_content=content,
            filename=file.filename,
            user_id=str(current_user.id)
        )
        
        # Save metadata to database
        db_source = db_models.Source(
            filename=file.filename,
            s3_key=file_info["key"],
            s3_url=file_info["public_url"], # Store public URL in DB
            size=len(content),
            user_id=current_user.id
        )
        db.add(db_source)
        db.commit()
        db.refresh(db_source)

        return {
            "id": db_source.id,
            "filename": file.filename, 
            "key": file_info["key"], 
            "public_url": file_info["public_url"],
            "private_url": file_info["private_url"],
            "message": "Upload successful"
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/list", response_model=List[SourceFileResponse])
async def list_sources(
    current_user: db_models.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    try:
        # Join Source with RAGDocument to get indexing info if it exists
        results = db.query(
            db_models.Source,
            db_models.RAGDocument.id.label("rag_id"),
            db_models.RAGDocument.azure_doc_id
        ).outerjoin(
            db_models.RAGDocument, 
            db_models.Source.id == db_models.RAGDocument.source_id
        ).filter(
            db_models.Source.user_id == current_user.id
        ).all()
        
        response_sources = []
        for source, rag_id, azure_doc_id in results:
            response_sources.append({
                "id": source.id,
                "filename": source.filename,
                "s3_key": source.s3_key,
                "public_url": source.s3_url,
                "private_url": s3_service.get_presigned_url(source.s3_key),
                "size": source.size,
                "created_at": source.created_at,
                "rag_id": rag_id,
                "azure_doc_id": azure_doc_id
            })
        return response_sources
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.delete("/{source_id}")
async def delete_source(
    source_id: int,
    current_user: db_models.User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    source = db.query(db_models.Source).filter(
        db_models.Source.id == source_id,
        db_models.Source.user_id == current_user.id
    ).first()
    
    if not source:
        raise HTTPException(status_code=404, detail="Source not found")
    
    try:
        # 1. Handle RAG Document (Delete completely as it's useless without the source)
        rag_doc = db.query(db_models.RAGDocument).filter(
            db_models.RAGDocument.source_id == source.id
        ).first()
        
        if rag_doc:
            # Delete from Azure Search
            rag_service.delete_document(rag_doc.azure_doc_id)
            # Delete from DB
            db.delete(rag_doc)

        # 2. Handle other dependencies (Delete everything linked to this source)
        # We must delete children (Flashcards, Questions) before parents (Sets) because of SQL constraints
        
        # Delete Flashcards
        flashcard_set_ids = [s.id for s in db.query(db_models.FlashcardSet).filter(db_models.FlashcardSet.source_id == source.id).all()]
        if flashcard_set_ids:
            db.query(db_models.Flashcard).filter(db_models.Flashcard.flashcard_set_id.in_(flashcard_set_ids)).delete(synchronize_session=False)
        
        # Delete Quiz Questions
        quiz_set_ids = [s.id for s in db.query(db_models.QuizSet).filter(db_models.QuizSet.source_id == source.id).all()]
        if quiz_set_ids:
            db.query(db_models.QuizQuestion).filter(db_models.QuizQuestion.quiz_set_id.in_(quiz_set_ids)).delete(synchronize_session=False)

        # Now delete the sets and other items
        db.query(db_models.MindMap).filter(db_models.MindMap.source_id == source.id).delete()
        db.query(db_models.FlashcardSet).filter(db_models.FlashcardSet.source_id == source.id).delete()
        db.query(db_models.QuizSet).filter(db_models.QuizSet.source_id == source.id).delete()
        db.query(db_models.Report).filter(db_models.Report.source_id == source.id).delete()
        db.query(db_models.VideoSummary).filter(db_models.VideoSummary.source_id == source.id).delete()
        
        db.commit() # Commit deletions 

        # 3. Delete from S3 if it exists
        if source.s3_key:
            await s3_service.delete_file(source.s3_key)
        
        # 4. Delete the Source itself from Database
        db.delete(source)
        db.commit()
        
        return {"message": "Source and all associated generated content (mind maps, quizzes, etc.) deleted successfully."}
        
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=f"Failed to delete source: {str(e)}")