def test_cant_create_aoi_with_invalid_multipolygon(self): bad_multipolygon = geojson.MultiPolygon([[(2.38, 57.322), (23.194, -20.28), (-120.43, 19.15), (2.38)]]) bad_feature = geojson.Feature(geometry=bad_multipolygon) bad_feature_collection = geojson.FeatureCollection([bad_feature]) # Act / Assert with self.assertRaises(InvalidGeoJson): # Only geometries of type MultiPolygon are valid GridService.merge_to_multi_polygon(geojson.dumps(bad_feature_collection), dissolve=True)
def test_raises_InvalidGeoJson_when_geometry_is_linestring(self): # arrange grid_json = get_canned_json('CHAI-Escuintla-West2.json') grid_dto = GridDTO(grid_json) grid_dto.clip_to_aoi = True # Act / Assert with self.assertRaises(InvalidGeoJson): GridService.merge_to_multi_polygon(grid_dto.area_of_interest, dissolve=True)
def create_draft_project(draft_project_dto: DraftProjectDTO) -> int: """ Validates and then persists draft projects in the DB :param draft_project_dto: Draft Project DTO with data from API :raises InvalidGeoJson :returns ID of new draft project """ # If we're cloning we'll copy all the project details from the clone, otherwise create brand new project if draft_project_dto.cloneFromProjectId: draft_project = Project.clone(draft_project_dto.cloneFromProjectId, draft_project_dto.user_id) else: draft_project = Project() draft_project.create_draft_project(draft_project_dto) draft_project.set_project_aoi(draft_project_dto) # if arbitrary_tasks requested, create tasks from aoi otherwise use tasks in DTO if draft_project_dto.has_arbitrary_tasks: tasks = GridService.tasks_from_aoi_features( draft_project_dto.area_of_interest) draft_project.task_creation_mode = TaskCreationMode.ARBITRARY.value else: tasks = draft_project_dto.tasks ProjectAdminService._attach_tasks_to_project(draft_project, tasks) if draft_project_dto.cloneFromProjectId: draft_project.save() # Update the clone else: draft_project.create() # Create the new project draft_project.set_default_changeset_comment() return draft_project.id
def set_project_aoi(self, draft_project_dto: DraftProjectDTO): """ Sets the AOI for the supplied project """ aoi_geojson = geojson.loads(json.dumps(draft_project_dto.area_of_interest)) aoi_geometry = GridService.merge_to_multi_polygon(aoi_geojson, dissolve=True) valid_geojson = geojson.dumps(aoi_geometry) self.geometry = ST_SetSRID(ST_GeomFromGeoJSON(valid_geojson), 4326) self.centroid = ST_Centroid(self.geometry)
def test_tasks_from_aoi_features(self): # arrange grid_json = get_canned_json('test_grid.json') grid_dto = GridDTO(grid_json) expected = geojson.loads(json.dumps(get_canned_json('tasks_from_aoi_features.json'))) # act result = GridService.tasks_from_aoi_features(grid_dto.area_of_interest) # assert self.assertEquals(str(expected), str(result))
def test_feature_collection_multi_polygon_with_zcoord_dissolve(self): # arrange project_json = get_canned_json('canned_kml_project.json') project_dto = DraftProjectDTO(project_json) expected = geojson.loads(json.dumps(get_canned_json('2d_multi_polygon.json'))) aoi_geojson = geojson.loads(json.dumps(project_dto.area_of_interest)) # act result = GridService.merge_to_multi_polygon(aoi_geojson, dissolve=True) # assert self.assertEquals(str(expected), str(result))
def test_feature_collection_to_multi_polygon_nodissolve(self): # arrange grid_json = get_canned_json('test_grid.json') grid_dto = GridDTO(grid_json) expected = geojson.loads(json.dumps(get_canned_json('multi_polygon.json'))) aoi_geojson = geojson.loads(json.dumps(grid_dto.area_of_interest)) # act result = GridService.merge_to_multi_polygon(aoi_geojson, False) # assert self.assertEquals(str(expected), str(result))
def test_trim_grid_to_aoi_clip(self): # arrange grid_json = get_canned_json('test_grid.json') grid_dto = GridDTO(grid_json) expected = geojson.loads(json.dumps(get_canned_json('clipped_feature_collection.json'))) grid_dto.clip_to_aoi = True # act result = GridService.trim_grid_to_aoi(grid_dto) # assert self.assertEquals(str(expected), str(result))
def create_draft_project(draft_project_dto: DraftProjectDTO) -> int: """ Validates and then persists draft projects in the DB :param draft_project_dto: Draft Project DTO with data from API :raises InvalidGeoJson :returns ID of new draft project """ # First things first, we need to validate that the author_id is a PM. issue #1715 if not UserService.is_user_a_project_manager( draft_project_dto.user_id): raise (ProjectAdminServiceError( f'User {UserService.get_user_by_id(draft_project_dto.user_id).username} is not a project manager' )) # If we're cloning we'll copy all the project details from the clone, otherwise create brand new project if draft_project_dto.cloneFromProjectId: draft_project = Project.clone(draft_project_dto.cloneFromProjectId, draft_project_dto.user_id) else: draft_project = Project() draft_project.create_draft_project(draft_project_dto) draft_project.set_project_aoi(draft_project_dto) # if arbitrary_tasks requested, create tasks from aoi otherwise use tasks in DTO if draft_project_dto.has_arbitrary_tasks: tasks = GridService.tasks_from_aoi_features( draft_project_dto.area_of_interest) draft_project.task_creation_mode = TaskCreationMode.ARBITRARY.value else: tasks = draft_project_dto.tasks ProjectAdminService._attach_tasks_to_project(draft_project, tasks) if draft_project_dto.cloneFromProjectId: draft_project.save() # Update the clone else: draft_project.create() # Create the new project draft_project.set_default_changeset_comment() return draft_project.id
def put(self): """ Gets the tiles intersecting the aoi --- tags: - grid produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - in: body name: body required: true description: JSON object containing aoi and tasks and bool flag for controlling clip grid to aoi schema: properties: clipToAoi: type: boolean default: true areaOfInterest: schema: properties: type: type: string default: FeatureCollection features: type: array items: schema: $ref: "#/definitions/GeoJsonFeature" grid: schema: properties: type: type: string default: FeatureCollection features: type: array items: schema: $ref: "#/definitions/GeoJsonFeature" responses: 200: description: Intersecting tasks found successfully 400: description: Client Error - Invalid Request 500: description: Internal Server Error """ try: grid_dto = GridDTO(request.get_json()) grid_dto.validate() except DataError as e: current_app.logger.error(f'error validating request: {str(e)}') return str(e), 400 try: grid = GridService.trim_grid_to_aoi(grid_dto) return grid, 200 except InvalidGeoJson as e: return {"error": f'{str(e)}'}, 400 except Exception as e: error_msg = f'IntersectingTiles GET API - unhandled error: {str(e)}' current_app.logger.critical(error_msg) return {"error": error_msg}, 500