mirror of
https://github.com/fccapria/scientify.git
synced 2026-01-12 10:36:11 +00:00
233 lines
No EOL
8.4 KiB
Python
233 lines
No EOL
8.4 KiB
Python
from fastapi import Depends, APIRouter, Query, HTTPException
|
|
from sqlalchemy import select, or_, and_, asc, desc
|
|
from sqlalchemy.orm import selectinload
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from typing import List, Optional
|
|
|
|
from app.db import Publication, get_db, Keyword, Author, User
|
|
from app.schemas import PublicationOut, UserPublicationOut
|
|
from app.users import current_active_user
|
|
|
|
# Create router for publication endpoints
|
|
router = APIRouter()
|
|
|
|
# Endpoint to delete a publication
|
|
@router.delete("/publications/{publication_id}")
|
|
async def delete_publication(
|
|
publication_id: int,
|
|
user: User = Depends(current_active_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""
|
|
Delete a publication owned by the current user
|
|
"""
|
|
# Find the publication with relations
|
|
result = await db.execute(
|
|
select(Publication).options(
|
|
selectinload(Publication.authors),
|
|
selectinload(Publication.keywords)
|
|
).where(
|
|
and_(
|
|
Publication.id == publication_id,
|
|
Publication.user_id == user.id # Security: only user's own publications
|
|
)
|
|
)
|
|
)
|
|
publication = result.scalar_one_or_none()
|
|
|
|
if not publication:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail="Publication not found or you don't have permission to delete it"
|
|
)
|
|
|
|
publication_title = publication.title
|
|
|
|
# Delete the publication (many-to-many relations are deleted automatically)
|
|
await db.delete(publication)
|
|
await db.commit()
|
|
|
|
print(f"🗑️ Publication deleted: '{publication_title}' (ID: {publication_id}) by user {user.email}")
|
|
|
|
return {"message": f"Publication '{publication_title}' successfully deleted"}
|
|
|
|
|
|
# Endpoint for user publications with sorting
|
|
@router.get("/users/me/publications", response_model=List[UserPublicationOut])
|
|
async def get_user_publications(
|
|
order_by: Optional[str] = Query("date_desc",
|
|
description="Sort by: date_asc, date_desc, title_asc, title_desc"),
|
|
user: User = Depends(current_active_user),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""
|
|
Returns all publications uploaded by the current user with sorting
|
|
"""
|
|
stmt = select(Publication).options(
|
|
selectinload(Publication.authors),
|
|
selectinload(Publication.keywords)
|
|
).where(
|
|
Publication.user_id == user.id
|
|
)
|
|
|
|
# Sorting management
|
|
if order_by == "date_asc":
|
|
stmt = stmt.order_by(asc(Publication.upload_date))
|
|
elif order_by == "date_desc":
|
|
stmt = stmt.order_by(desc(Publication.upload_date))
|
|
elif order_by == "title_asc":
|
|
stmt = stmt.order_by(asc(Publication.title))
|
|
elif order_by == "title_desc":
|
|
stmt = stmt.order_by(desc(Publication.title))
|
|
else:
|
|
# Default: descending by date (most recent first)
|
|
stmt = stmt.order_by(desc(Publication.upload_date))
|
|
|
|
result = await db.execute(stmt)
|
|
publications = result.scalars().all()
|
|
|
|
print(f"🔍 User {user.email} (ID: {user.id}) has {len(publications)} publications (sorted by: {order_by})")
|
|
|
|
return publications
|
|
|
|
|
|
# Search publications endpoint
|
|
@router.get("/publications", response_model=List[PublicationOut])
|
|
async def get_publications(
|
|
search: Optional[str] = Query(None,
|
|
description="Search by title, author or keyword. For multiple keywords use spaces: 'keyword1 keyword2'"),
|
|
order_by: Optional[str] = Query("date_desc",
|
|
description="Sort by: date_asc, date_desc, title_asc, title_desc"),
|
|
db: AsyncSession = Depends(get_db)
|
|
):
|
|
"""
|
|
🔍 ADVANCED SEARCH SYSTEM WITH KEYWORDS
|
|
|
|
Search function with priority and sorting:
|
|
1. Keywords (highest priority) - supports multiple search with spaces
|
|
2. Authors (medium priority)
|
|
3. Title (lowest priority)
|
|
|
|
Keywords are the core of the search system!
|
|
"""
|
|
|
|
print(f"🔍 Search: '{search}' | Sort by: {order_by}")
|
|
|
|
# If no search query, return all sorted
|
|
if search is None or not search.strip():
|
|
stmt = select(Publication).options(
|
|
selectinload(Publication.authors),
|
|
selectinload(Publication.keywords)
|
|
)
|
|
|
|
# Sorting management
|
|
if order_by == "date_asc":
|
|
stmt = stmt.order_by(asc(Publication.upload_date))
|
|
elif order_by == "date_desc":
|
|
stmt = stmt.order_by(desc(Publication.upload_date))
|
|
elif order_by == "title_asc":
|
|
stmt = stmt.order_by(asc(Publication.title))
|
|
elif order_by == "title_desc":
|
|
stmt = stmt.order_by(desc(Publication.title))
|
|
else:
|
|
# Default: descending by date
|
|
stmt = stmt.order_by(desc(Publication.upload_date))
|
|
|
|
result = await db.execute(stmt)
|
|
return result.scalars().all()
|
|
|
|
search_term = search.strip()
|
|
|
|
# Split search string into individual keywords
|
|
search_keywords = [kw.strip().lower() for kw in search_term.split() if kw.strip()]
|
|
print(f"🔍 Keywords to search: {search_keywords}")
|
|
|
|
# SET to track already found IDs
|
|
found_publication_ids = set()
|
|
final_results = []
|
|
|
|
# 🎯 1. SEARCH BY KEYWORDS (highest priority) - MULTIPLE SEARCH
|
|
if search_keywords:
|
|
print("🔍 Step 1: Searching by multiple keywords...")
|
|
|
|
# Create conditions for each keyword
|
|
keyword_conditions = []
|
|
for keyword in search_keywords:
|
|
keyword_pattern = f"%{keyword}%"
|
|
keyword_conditions.append(
|
|
Publication.keywords.any(Keyword.name.ilike(keyword_pattern))
|
|
)
|
|
|
|
# Publication must have ALL keywords (AND)
|
|
keyword_query = select(Publication).options(
|
|
selectinload(Publication.authors),
|
|
selectinload(Publication.keywords)
|
|
).where(
|
|
and_(*keyword_conditions) # All conditions must be true
|
|
)
|
|
|
|
keyword_result = await db.execute(keyword_query)
|
|
keyword_publications = keyword_result.scalars().all()
|
|
|
|
for pub in keyword_publications:
|
|
if pub.id not in found_publication_ids:
|
|
final_results.append(pub)
|
|
found_publication_ids.add(pub.id)
|
|
pub_keywords = [k.name for k in pub.keywords]
|
|
print(f" ✅ Found by keywords: {pub.title} (keywords: {pub_keywords})")
|
|
|
|
# 📝 2. SEARCH BY AUTHORS (medium priority) - uses complete string
|
|
print("🔍 Step 2: Searching by authors...")
|
|
author_pattern = f"%{search_term}%"
|
|
author_query = select(Publication).options(
|
|
selectinload(Publication.authors),
|
|
selectinload(Publication.keywords)
|
|
).join(Publication.authors).where(
|
|
Author.name.ilike(author_pattern)
|
|
)
|
|
|
|
author_result = await db.execute(author_query)
|
|
author_publications = author_result.scalars().all()
|
|
|
|
for pub in author_publications:
|
|
if pub.id not in found_publication_ids:
|
|
final_results.append(pub)
|
|
found_publication_ids.add(pub.id)
|
|
pub_authors = [a.name for a in pub.authors]
|
|
print(f" ✅ Found by author: {pub.title} (authors: {pub_authors})")
|
|
|
|
# 📰 3. SEARCH BY TITLE (lowest priority) - uses complete string
|
|
print("🔍 Step 3: Searching by title...")
|
|
title_pattern = f"%{search_term}%"
|
|
title_query = select(Publication).options(
|
|
selectinload(Publication.authors),
|
|
selectinload(Publication.keywords)
|
|
).where(
|
|
Publication.title.ilike(title_pattern)
|
|
)
|
|
|
|
title_result = await db.execute(title_query)
|
|
title_publications = title_result.scalars().all()
|
|
|
|
for pub in title_publications:
|
|
if pub.id not in found_publication_ids:
|
|
final_results.append(pub)
|
|
found_publication_ids.add(pub.id)
|
|
print(f" ✅ Found by title: {pub.title}")
|
|
|
|
# Apply sorting to final results
|
|
print(f"🔍 Applying sorting: {order_by}")
|
|
if order_by == "date_asc":
|
|
final_results.sort(key=lambda x: x.upload_date)
|
|
elif order_by == "date_desc":
|
|
final_results.sort(key=lambda x: x.upload_date, reverse=True)
|
|
elif order_by == "title_asc":
|
|
final_results.sort(key=lambda x: x.title.lower())
|
|
elif order_by == "title_desc":
|
|
final_results.sort(key=lambda x: x.title.lower(), reverse=True)
|
|
else:
|
|
# Default: descending by date
|
|
final_results.sort(key=lambda x: x.upload_date, reverse=True)
|
|
|
|
print(f"🔍 Total results found: {len(final_results)}")
|
|
return final_results |