From d74cb070ca9b39943e3c0fce493b0be830660658 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Wed, 3 Sep 2025 18:46:11 +0900 Subject: [PATCH] =?UTF-8?q?Fix:=20=EB=AC=B8=EC=84=9C-=EB=85=B8=ED=8A=B8=20?= =?UTF-8?q?=EA=B0=84=20=EB=A7=81=ED=81=AC=20=EC=83=9D=EC=84=B1=20=EB=B0=8F?= =?UTF-8?q?=20=EB=A7=81=ED=81=AC=20=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 문서에서 노트로의 링크 생성 지원 추가 - 대상이 문서가 아닌 경우 NoteDocument 테이블에서 검색 - 노트 권한 확인 로직 추가 - 링크 삭제 엔드포인트에 /document-links/{link_id} 경로 추가 (프론트엔드 호환성) - 응답에서 노트 제목과 노트북 ID 지원 --- backend/src/api/routes/document_links.py | 60 +++++++++++++++--------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/backend/src/api/routes/document_links.py b/backend/src/api/routes/document_links.py index da016c9..44401ea 100644 --- a/backend/src/api/routes/document_links.py +++ b/backend/src/api/routes/document_links.py @@ -115,29 +115,44 @@ async def create_document_link( detail="Access denied to source document" ) - # 대상 문서 확인 + # 대상 문서 또는 노트 확인 result = await db.execute(select(Document).where(Document.id == link_data.target_document_id)) target_doc = result.scalar_one_or_none() + target_note = None if not target_doc: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail="Target document not found" - ) + # 문서에서 찾지 못하면 노트에서 찾기 + from models.note_document import NoteDocument + result = await db.execute(select(NoteDocument).where(NoteDocument.id == link_data.target_document_id)) + target_note = result.scalar_one_or_none() + + if not target_note: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Target document or note not found" + ) - # 대상 문서 권한 확인 - if not target_doc.is_public and target_doc.uploaded_by != current_user.id and not current_user.is_admin: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Access denied to target document" - ) - - # HTML 문서만 링크 가능 - if not target_doc.html_path: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Can only link to HTML documents" - ) + # 대상 문서/노트 권한 확인 + if target_doc: + if not target_doc.is_public and target_doc.uploaded_by != current_user.id and not current_user.is_admin: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Access denied to target document" + ) + + # HTML 문서만 링크 가능 + if not target_doc.html_path: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Can only link to HTML documents" + ) + elif target_note: + # 노트 권한 확인 (노트는 기본적으로 생성자만 접근 가능) + if target_note.created_by != current_user.id and not current_user.is_admin: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Access denied to target note" + ) # 링크 생성 new_link = DocumentLink( @@ -160,7 +175,9 @@ async def create_document_link( await db.commit() await db.refresh(new_link) - print(f"✅ 링크 생성 완료: {source_doc.title} -> {target_doc.title}") + target_title = target_doc.title if target_doc else target_note.title + target_type = "document" if target_doc else "note" + print(f"✅ 링크 생성 완료: {source_doc.title} -> {target_title} ({target_type})") print(f" - 링크 타입: {new_link.link_type}") print(f" - 선택된 텍스트: {new_link.selected_text}") print(f" - 대상 텍스트: {new_link.target_text}") @@ -184,8 +201,8 @@ async def create_document_link( link_type=new_link.link_type, created_at=new_link.created_at.isoformat(), updated_at=new_link.updated_at.isoformat() if new_link.updated_at else None, - target_document_title=target_doc.title, - target_document_book_id=str(target_doc.book_id) if target_doc.book_id else None + target_document_title=target_title, + target_document_book_id=str(target_doc.book_id) if target_doc and target_doc.book_id else (str(target_note.notebook_id) if target_note and target_note.notebook_id else None) ) @@ -384,6 +401,7 @@ async def update_document_link( @router.delete("/links/{link_id}") +@router.delete("/document-links/{link_id}") # 프론트엔드 호환성을 위한 추가 경로 async def delete_document_link( link_id: str, current_user: User = Depends(get_current_active_user),