Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actual contributors count in project summary #1484

Merged
merged 2 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions src/backend/app/projects/project_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ async def get_project_summaries(
project_count, db_projects = await get_projects(
db, skip, limit, user_id, hashtags, search
)
return project_count, await convert_to_project_summaries(db_projects)
return project_count, await convert_to_project_summaries(db, db_projects)


async def get_project(db: Session, project_id: int):
Expand Down Expand Up @@ -1265,7 +1265,7 @@ async def convert_project(project):
return []


async def convert_to_project_summary(db_project: db_models.DbProject):
async def convert_to_project_summary(db: Session, db_project: db_models.DbProject):
"""Legacy function to convert db models --> Pydantic.

TODO refactor to use Pydantic model methods instead.
Expand All @@ -1274,13 +1274,17 @@ async def convert_to_project_summary(db_project: db_models.DbProject):
summary: project_schemas.ProjectSummary = db_project

if db_project.project_info:
summary.location_str = db_project.location_str
summary.title = db_project.project_info.name
summary.description = db_project.project_info.short_description

summary.num_contributors = (
db_project.tasks_mapped + db_project.tasks_validated
) # TODO: get real number of contributors
db.query(db_models.DbTaskHistory.user_id)
.filter(
db_models.DbTaskHistory.project_id == db_project.id,
db_models.DbTaskHistory.user_id != (None),
)
.distinct()
.count()
)
summary.organisation_logo = (
db_project.organisation.logo if db_project.organisation else None
)
Expand All @@ -1291,6 +1295,7 @@ async def convert_to_project_summary(db_project: db_models.DbProject):


async def convert_to_project_summaries(
db: Session,
db_projects: List[db_models.DbProject],
) -> List[project_schemas.ProjectSummary]:
"""Legacy function to convert db models --> Pydantic.
Expand All @@ -1299,11 +1304,11 @@ async def convert_to_project_summaries(
"""
if db_projects and len(db_projects) > 0:

async def convert_summary(project):
return await convert_to_project_summary(project)
async def convert_summary(db, project):
return await convert_to_project_summary(db, project)

project_summaries = await gather(
*[convert_summary(project) for project in db_projects]
*[convert_summary(db, project) for project in db_projects]
)
return [summary for summary in project_summaries if summary is not None]
else:
Expand Down
4 changes: 2 additions & 2 deletions src/backend/app/projects/project_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ async def read_project_summaries(
)

project_summaries = [
project_schemas.ProjectSummary.from_db_project(project) for project in projects
project_schemas.ProjectSummary(**project.__dict__) for project in projects
]

response = project_schemas.PaginatedProjectSummaries(
Expand Down Expand Up @@ -181,7 +181,7 @@ async def search_project(
page, project_count, results_per_page, total_projects
)
project_summaries = [
project_schemas.ProjectSummary.from_db_project(project) for project in projects
project_schemas.ProjectSummary(**project.__dict__) for project in projects
]

response = project_schemas.PaginatedProjectSummaries(
Expand Down
56 changes: 15 additions & 41 deletions src/backend/app/projects/project_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from typing import Any, List, Optional, Union

from dateutil import parser
from geoalchemy2.elements import WKBElement
from geojson_pydantic import Feature, FeatureCollection, Polygon
from loguru import logger as log
from pydantic import BaseModel, Field, computed_field
Expand All @@ -31,7 +32,6 @@
from typing_extensions import Self

from app.config import HttpUrlStr, decrypt_value, encrypt_value
from app.db import db_models
from app.db.postgis_utils import (
geojson_to_geometry,
geometry_to_geojson,
Expand Down Expand Up @@ -241,11 +241,10 @@ class GeojsonFeature(BaseModel):
class ProjectSummary(BaseModel):
"""Project summaries."""

id: int = -1
priority: ProjectPriority = ProjectPriority.MEDIUM
priority_str: str = priority.name
id: int
priority: ProjectPriority
title: Optional[str] = None
centroid: Optional[list[float]] = None
centroid: Optional[WKBElement] = None
location_str: Optional[str] = None
description: Optional[str] = None
total_tasks: Optional[int] = None
Expand All @@ -257,42 +256,17 @@ class ProjectSummary(BaseModel):
organisation_id: Optional[int] = None
organisation_logo: Optional[str] = None

@classmethod
def from_db_project(
cls,
project: db_models.DbProject,
) -> "ProjectSummary":
"""Generate model from database obj."""
priority = project.priority
centroid_coords = []
if project.centroid:
centroid_point = read_wkb(project.centroid)
# NOTE format x,y (lon,lat) required for GeoJSON
centroid_coords = [centroid_point.x, centroid_point.y]

return cls(
id=project.id,
priority=priority,
priority_str=priority.name,
title=project.title,
centroid=centroid_coords,
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,
)

# @field_serializer("centroid")
# def get_coord_from_centroid(self, value):
# """Get the cetroid coordinates from WBKElement."""
# if value is None:
# return None
class Config:
arbitrary_types_allowed = True

@field_serializer("centroid")
def get_coord_from_centroid(self, value):
"""Get the cetroid coordinates from WBKElement."""
if value is None:
return None
centroid_point = read_wkb(value)
centroid = [centroid_point.x, centroid_point.y]
return centroid


class PaginationInfo(BaseModel):
Expand Down
1 change: 0 additions & 1 deletion src/frontend/src/api/Project.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export const ProjectById = (existingProjectList, projectId) => {
id: projectResp.id,
outline_geojson: projectResp.outline_geojson,
priority: projectResp.priority || 2,
priority_str: projectResp.priority_str || 'MEDIUM',
title: projectResp.project_info?.name,
location_str: projectResp.location_str,
description: projectResp.project_info?.description,
Expand Down
1 change: 0 additions & 1 deletion src/frontend/src/models/project/projectModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ export type projectInfoType = {
id: number;
};
priority: number;
priority_str: string;
title: string;
location_str: string;
description: string;
Expand Down
Loading