diff --git a/src/backend/app/projects/project_routes.py b/src/backend/app/projects/project_routes.py index fd951d440e..18ccff28a6 100644 --- a/src/backend/app/projects/project_routes.py +++ b/src/backend/app/projects/project_routes.py @@ -109,12 +109,12 @@ def get_task(lat: float, long: float, user_id: int = None): return "Coming..." -@router.get("/summaries", response_model=List[project_schemas.ProjectSummary]) +@router.get("/summaries", response_model=project_schemas.PaginatedProjectSummaries) async def read_project_summaries( user_id: int = None, hashtags: str = None, - skip: int = 0, - limit: int = 100, + page: int = Query(1, ge=1), # Default to page 1, must be greater than or equal to 1 + results_per_page: int = Query(13, le=100), db: Session = Depends(database.get_db), ): if hashtags: @@ -123,8 +123,33 @@ async def read_project_summaries( filter(lambda hashtag: hashtag.startswith("#"), hashtags) ) # filter hashtags that do start with # + skip = (page - 1) * results_per_page + limit = results_per_page + + total_projects = db.query(db_models.DbProject).count() + hasNext = (page * results_per_page) < total_projects + hasPrev = page > 1 + total_pages = (total_projects + results_per_page - 1) // results_per_page + projects = project_crud.get_project_summaries(db, user_id, skip, limit, hashtags) - return projects + project_summaries = [ + project_schemas.ProjectSummary.from_db_project(project) for project in projects + ] + + response = project_schemas.PaginatedProjectSummaries( + results=project_summaries, + pagination=project_schemas.PaginationInfo( + hasNext=hasNext, + hasPrev=hasPrev, + nextNum=page + 1 if hasNext else None, + page=page, + pages=total_pages, + prevNum=page - 1 if hasPrev else None, + perPage=results_per_page, + total=total_projects, + ), + ) + return response @router.get("/{project_id}", response_model=project_schemas.ProjectOut) diff --git a/src/backend/app/projects/project_schemas.py b/src/backend/app/projects/project_schemas.py index 9865e96f5a..db15bc2362 100644 --- a/src/backend/app/projects/project_schemas.py +++ b/src/backend/app/projects/project_schemas.py @@ -21,6 +21,7 @@ from geojson_pydantic import Feature as GeojsonFeature from pydantic import BaseModel +from ..db import db_models from ..models.enums import ProjectPriority, ProjectStatus from ..tasks import tasks_schemas from ..users.user_schemas import User @@ -76,6 +77,45 @@ class ProjectSummary(BaseModel): organisation_id: Optional[int] = None organisation_logo: Optional[str] = None + @classmethod + def from_db_project( + cls, + project: db_models.DbProject, + ) -> "ProjectSummary": + priority = project.priority + return cls( + id=project.id, + priority=priority, + priority_str=priority.name, + title=project.title, + location_str=project.location_str, + description=project.description, + total_tasks=project.total_tasks, + tasks_mapped=project.tasks_mapped, + num_contributors=project.num_contributors, + tasks_validated=project.tasks_validated, + tasks_bad=project.tasks_bad, + hashtags=project.hashtags, + organisation_id=project.organisation_id, + organisation_logo=project.organisation_logo, + ) + + +class PaginationInfo(BaseModel): + hasNext: bool + hasPrev: bool + nextNum: Optional[int] + page: int + pages: int + prevNum: Optional[int] + perPage: int + total: int + + +class PaginatedProjectSummaries(BaseModel): + results: List[ProjectSummary] + pagination: PaginationInfo + class ProjectBase(BaseModel): id: int