mirror of
https://github.com/fccapria/scientify.git
synced 2026-01-12 02:36:10 +00:00
Initial release
This commit is contained in:
commit
ae5e4b8873
52 changed files with 17572 additions and 0 deletions
233
backend/app/publication_routes.py
Normal file
233
backend/app/publication_routes.py
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue