first commit
This commit is contained in:
commit
6e354ba041
109 changed files with 12110 additions and 0 deletions
159
backend/app/routers/documents.py
Normal file
159
backend/app/routers/documents.py
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from motor.motor_asyncio import AsyncIOMotorDatabase
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import get_db
|
||||
from app.dependencies import get_current_user, get_mongo_db_dep
|
||||
from app.models.user import User
|
||||
from app.schemas.document import DocumentCreate, DocumentResponse, DocumentUpdate, ShareRequest
|
||||
from app.services.document_service import (
|
||||
add_member,
|
||||
create_document,
|
||||
delete_document,
|
||||
get_document,
|
||||
list_documents,
|
||||
record_visit,
|
||||
remove_member,
|
||||
search_documents,
|
||||
update_document,
|
||||
)
|
||||
from app.services.user_service import get_user_by_email_or_username
|
||||
|
||||
router = APIRouter(prefix="/documents", tags=["documents"])
|
||||
|
||||
|
||||
@router.get("", response_model=list[DocumentResponse])
|
||||
async def list_docs(
|
||||
type: str | None = Query(None, description="Filter by document type"),
|
||||
stead_id: str | None = Query(None, description="Filter by parent stead"),
|
||||
starred: bool | None = Query(None, description="Filter starred projects"),
|
||||
sort: str = Query("updated_at", description="Sort field: updated_at or last_visited_at"),
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncIOMotorDatabase = Depends(get_mongo_db_dep),
|
||||
) -> list[DocumentResponse]:
|
||||
sort_field = "last_visited_at" if sort == "last_visited_at" else "updated_at"
|
||||
docs = await list_documents(
|
||||
db,
|
||||
current_user.id,
|
||||
doc_type=type,
|
||||
stead_id=stead_id,
|
||||
starred=starred,
|
||||
sort=sort_field,
|
||||
)
|
||||
return [DocumentResponse(**doc) for doc in docs]
|
||||
|
||||
|
||||
@router.get("/search", response_model=list[DocumentResponse])
|
||||
async def search_docs(
|
||||
q: str = Query("", min_length=0),
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncIOMotorDatabase = Depends(get_mongo_db_dep),
|
||||
) -> list[DocumentResponse]:
|
||||
docs = await search_documents(db, current_user.id, q)
|
||||
return [DocumentResponse(**doc) for doc in docs]
|
||||
|
||||
|
||||
@router.get("/{doc_id}", response_model=DocumentResponse)
|
||||
async def get_doc(
|
||||
doc_id: str,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncIOMotorDatabase = Depends(get_mongo_db_dep),
|
||||
) -> DocumentResponse:
|
||||
doc = await get_document(db, doc_id, current_user.id)
|
||||
if doc is None:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Document not found or access denied")
|
||||
return DocumentResponse(**doc)
|
||||
|
||||
|
||||
@router.post("", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_doc(
|
||||
data: DocumentCreate,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncIOMotorDatabase = Depends(get_mongo_db_dep),
|
||||
) -> DocumentResponse:
|
||||
created_by = current_user.full_name or current_user.username
|
||||
doc = await create_document(db, current_user.id, created_by, data)
|
||||
return DocumentResponse(**doc)
|
||||
|
||||
|
||||
@router.patch("/{doc_id}", response_model=DocumentResponse)
|
||||
async def update_doc(
|
||||
doc_id: str,
|
||||
data: DocumentUpdate,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncIOMotorDatabase = Depends(get_mongo_db_dep),
|
||||
) -> DocumentResponse:
|
||||
doc = await update_document(db, doc_id, current_user.id, data)
|
||||
if doc is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="Document not found or you do not have edit access",
|
||||
)
|
||||
return DocumentResponse(**doc)
|
||||
|
||||
|
||||
@router.post("/{doc_id}/visit", response_model=DocumentResponse)
|
||||
async def visit_doc(
|
||||
doc_id: str,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncIOMotorDatabase = Depends(get_mongo_db_dep),
|
||||
) -> DocumentResponse:
|
||||
doc = await record_visit(db, doc_id, current_user.id)
|
||||
if doc is None:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Document not found or access denied")
|
||||
return DocumentResponse(**doc)
|
||||
|
||||
|
||||
@router.post("/{doc_id}/share", response_model=DocumentResponse)
|
||||
async def share_doc(
|
||||
doc_id: str,
|
||||
data: ShareRequest,
|
||||
current_user: User = Depends(get_current_user),
|
||||
mongo: AsyncIOMotorDatabase = Depends(get_mongo_db_dep),
|
||||
sql: Session = Depends(get_db),
|
||||
) -> DocumentResponse:
|
||||
identifier = data.email_or_username.strip().lower()
|
||||
user = get_user_by_email_or_username(sql, identifier)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||
if user.id == current_user.id:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="You already own this document")
|
||||
|
||||
doc = await add_member(
|
||||
mongo,
|
||||
doc_id,
|
||||
current_user.id,
|
||||
{
|
||||
"user_id": user.id,
|
||||
"name": user.full_name or user.username,
|
||||
"email": user.email,
|
||||
},
|
||||
data.role,
|
||||
)
|
||||
if doc is None:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only the owner can share this document")
|
||||
return DocumentResponse(**doc)
|
||||
|
||||
|
||||
@router.delete("/{doc_id}/share/{user_id}", response_model=DocumentResponse)
|
||||
async def unshare_doc(
|
||||
doc_id: str,
|
||||
user_id: int,
|
||||
current_user: User = Depends(get_current_user),
|
||||
mongo: AsyncIOMotorDatabase = Depends(get_mongo_db_dep),
|
||||
) -> DocumentResponse:
|
||||
doc = await remove_member(mongo, doc_id, current_user.id, user_id)
|
||||
if doc is None:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Only the owner can update sharing")
|
||||
return DocumentResponse(**doc)
|
||||
|
||||
|
||||
@router.delete("/{doc_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_doc(
|
||||
doc_id: str,
|
||||
current_user: User = Depends(get_current_user),
|
||||
db: AsyncIOMotorDatabase = Depends(get_mongo_db_dep),
|
||||
) -> None:
|
||||
deleted = await delete_document(db, doc_id, current_user.id)
|
||||
if not deleted:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Document not found")
|
||||
Loading…
Add table
Add a link
Reference in a new issue