def search_projects( search_dto: ProjectSearchDTO) -> ProjectSearchResultsDTO: """ Searches all projects for matches to the criteria provided by the user """ all_results, paginated_results = ProjectSearchService._filter_projects( search_dto) if paginated_results.total == 0: raise NotFound() features = [] for project in all_results: # This loop creates a geojson feature collection so you can see all active projects on the map properties = { "projectId": project.id, "priority": ProjectPriority(project.priority).name } centroid = project.centroid feature = geojson.Feature(geometry=geojson.loads(project.centroid), properties=properties) features.append(feature) feature_collection = geojson.FeatureCollection(features) dto = ProjectSearchResultsDTO() dto.map_results = feature_collection for project in paginated_results.items: # This loop loads the paginated text results # TODO would be nice to get this for an array rather than individually would be more efficient project_info_dto = ProjectInfo.get_dto_for_locale( project.id, search_dto.preferred_locale, project.default_locale) list_dto = ListSearchResultDTO() list_dto.project_id = project.id list_dto.locale = project_info_dto.locale list_dto.name = project_info_dto.name list_dto.priority = ProjectPriority(project.priority).name list_dto.mapper_level = MappingLevel(project.mapper_level).name list_dto.short_description = project_info_dto.short_description list_dto.organisation_tag = project.organisation_tag list_dto.campaign_tag = project.campaign_tag list_dto.percent_mapped = Project.calculate_tasks_percent( 'mapped', project.total_tasks, project.tasks_mapped, project.tasks_validated, project.tasks_bad_imagery) list_dto.percent_validated = Project.calculate_tasks_percent( 'validated', project.total_tasks, project.tasks_mapped, project.tasks_validated, project.tasks_bad_imagery) list_dto.status = ProjectStatus(project.status).name list_dto.active_mappers = Project.get_active_mappers(project.id) dto.results.append(list_dto) dto.pagination = Pagination(paginated_results) return dto
def test_get_intersecting_projects(self, get_dto_for_locale, _get_intersecting_projects, get_user_by_username, validate_bbox_area, _make_4326_polygon_from_bbox): if self.skip_tests: return # arrange _make_4326_polygon_from_bbox mock _make_4326_polygon_from_bbox.return_value = Polygon([ (34.68826225820438, -12.59912449955007), (34.68826225820438, -11.57858317689196), (32.50198296132938, -11.57858317689196), (32.50198296132938, -12.59912449955007), (34.68826225820438, -12.59912449955007) ]) # arrange validate_bbox_area mock validate_bbox_area.return_value = True # arrange get_user_by_username mock get_user_by_username.return_value = User(id=3488526) # arrange _get_intersecting_projects mock polygon = json.dumps(get_canned_json('search_bbox_feature.json')) project = Project(id=2274, status=0, default_locale='en', geometry=polygon) projects = [project] _get_intersecting_projects.return_value = projects # arrange get_dto_for_locale mock get_dto_for_locale.return_value = ProjectInfo( name='PEPFAR Kenya: Homa Bay') # arrange dto dto = ProjectSearchBBoxDTO() dto.bbox = map(float, '34.404,-1.034, 34.717,-0.624'.split(',')) dto.preferred_locale = 'en' dto.input_srid = 4326 dto.project_author = 3488526 dto.validate() # arrange expected result expected = json.dumps(get_canned_json('search_bbox_result.json')) # act result = ProjectSearchService.get_projects_geojson(dto) # assert self.assertEqual(str(expected), str(expected))
def get_projects_geojson( search_bbox_dto: ProjectSearchBBoxDTO ) -> geojson.FeatureCollection: """ search for projects meeting criteria provided return as a geojson feature collection""" # make a polygon from provided bounding box polygon = ProjectSearchService._make_4326_polygon_from_bbox( search_bbox_dto.bbox, search_bbox_dto.input_srid) # validate the bbox area is less than or equal to the max area allowed to prevent # abuse of the api or performance issues from large requests if not ProjectSearchService.validate_bbox_area(polygon): raise BBoxTooBigError('Requested bounding box is too large') # get projects intersecting the polygon for created by the author_id intersecting_projects = ProjectSearchService._get_intersecting_projects( polygon, search_bbox_dto.project_author) # allow an empty feature collection to be returned if no intersecting features found, since this is primarily # for returning data to show on a map features = [] for project in intersecting_projects: try: localDTO = ProjectInfo.get_dto_for_locale( project.id, search_bbox_dto.preferred_locale, project.default_locale) except Exception as e: pass properties = { "projectId": project.id, "projectStatus": ProjectStatus(project.status).name, "projectName": localDTO.name } feature = geojson.Feature(geometry=geojson.loads(project.geometry), properties=properties) features.append(feature) return geojson.FeatureCollection(features)
def search_projects( search_dto: ProjectSearchDTO) -> ProjectSearchResultsDTO: """ Searches all projects for matches to the criteria provided by the user """ filtered_projects = ProjectSearchService._filter_projects(search_dto) if filtered_projects.total == 0: raise NotFound() dto = ProjectSearchResultsDTO() for project in filtered_projects.items: # TODO would be nice to get this for an array rather than individually would be more efficient project_info_dto = ProjectInfo.get_dto_for_locale( project.id, search_dto.preferred_locale, project.default_locale) result_dto = ProjectSearchResultDTO() result_dto.project_id = project.id result_dto.locale = project_info_dto.locale result_dto.name = project_info_dto.name result_dto.priority = ProjectPriority(project.priority).name result_dto.mapper_level = MappingLevel(project.mapper_level).name result_dto.short_description = project_info_dto.short_description result_dto.aoi_centroid = geojson.loads(project.centroid) result_dto.organisation_tag = project.organisation_tag result_dto.campaign_tag = project.campaign_tag result_dto.percent_mapped = round( (project.tasks_mapped / (project.total_tasks - project.tasks_bad_imagery)) * 100, 0) result_dto.percent_validated = round( ((project.tasks_validated + project.tasks_bad_imagery) / project.total_tasks) * 100, 0) dto.results.append(result_dto) dto.pagination = Pagination(filtered_projects) return dto