def generate_osm_xml(project_id: int, task_ids_str: str) -> str: """ Generate xml response suitable for loading into JOSM. A sample output file is in /backend/helpers/testfiles/osm-sample.xml """ # Note XML created with upload No to ensure it will be rejected by OSM if uploaded by mistake root = ET.Element( "osm", attrib=dict(version="0.6", upload="never", creator="HOT Tasking Manager"), ) if task_ids_str: task_ids = map(int, task_ids_str.split(",")) tasks = Task.get_tasks(project_id, task_ids) if not tasks or len(tasks) == 0: raise NotFound() else: tasks = Task.get_all_tasks(project_id) if not tasks or len(tasks) == 0: raise NotFound() fake_id = -1 # We use fake-ids to ensure XML will not be validated by OSM for task in tasks: task_geom = shape.to_shape(task.geometry) way = ET.SubElement( root, "way", attrib=dict(id=str((task.id * -1)), action="modify", visible="true"), ) for poly in task_geom: for point in poly.exterior.coords: ET.SubElement( root, "node", attrib=dict( action="modify", visible="true", id=str(fake_id), lon=str(point[0]), lat=str(point[1]), ), ) ET.SubElement(way, "nd", attrib=dict(ref=str(fake_id))) fake_id -= 1 xml_gpx = ET.tostring(root, encoding="utf8") return xml_gpx
def generate_gpx(project_id: int, task_ids_str: str, timestamp=None): """ Creates a GPX file for supplied tasks. Timestamp is for unit testing only. You can use the following URL to test locally: http://www.openstreetmap.org/edit?editor=id&#map=11/31.50362930069913/34.628906243797054&comment=CHANGSET_COMMENT&gpx=http://localhost:5000/api/v2/projects/{project_id}/tasks/queries/gpx%3Ftasks=2 """ if timestamp is None: timestamp = datetime.datetime.utcnow() root = ET.Element( "gpx", attrib=dict( xmlns="http://www.topografix.com/GPX/1/1", version="1.1", creator="HOT Tasking Manager", ), ) # Create GPX Metadata element metadata = ET.Element("metadata") link = ET.SubElement( metadata, "link", attrib=dict(href="https://github.com/hotosm/tasking-manager"), ) ET.SubElement(link, "text").text = "HOT Tasking Manager" ET.SubElement(metadata, "time").text = timestamp.isoformat() root.append(metadata) # Create trk element trk = ET.Element("trk") root.append(trk) ET.SubElement( trk, "name" ).text = f"Task for project {project_id}. Do not edit outside of this area!" # Construct trkseg elements if task_ids_str is not None: task_ids = map(int, task_ids_str.split(",")) tasks = Task.get_tasks(project_id, task_ids) if not tasks or len(tasks) == 0: raise NotFound() else: tasks = Task.get_all_tasks(project_id) if not tasks or len(tasks) == 0: raise NotFound() for task in tasks: task_geom = shape.to_shape(task.geometry) for poly in task_geom: trkseg = ET.SubElement(trk, "trkseg") for point in poly.exterior.coords: ET.SubElement( trkseg, "trkpt", attrib=dict(lon=str(point[0]), lat=str(point[1])), ) # Append wpt elements to end of doc wpt = ET.Element("wpt", attrib=dict(lon=str(point[0]), lat=str(point[1]))) root.append(wpt) xml_gpx = ET.tostring(root, encoding="utf8") return xml_gpx
def post(self, project_id: int, annotation_type: str): """ Store new task annotations for tasks of a project --- tags: - annotations produces: - application/json parameters: - in: header name: Content-Type description: Content type for post body required: true type: string default: application/json - name: project_id in: path description: Unique project ID required: true type: integer - name: annotation_type in: path description: Annotation type required: true type: string - name: Application-Token in: header description: Application token registered with TM required: true type: string - in: body name: body required: true description: JSON object for creating draft project schema: projectId: type: integer required: true annotationType: type: string required: true tasks: type: array required: true items: schema: taskId: type: integer required: true annotationSource: type: string annotationMarkdown: type: string properties: description: JSON object with properties responses: 200: description: Project updated 400: description: Client Error - Invalid Request 404: description: Project or task not found 500: description: Internal Server Error """ if "Application-Token" in request.headers: application_token = request.headers["Application-Token"] try: is_valid_token = ApplicationService.check_token( # noqa application_token) except NotFound: current_app.logger.error("Invalid token") return {"Error": "Invalid token"}, 500 else: current_app.logger.error("No token supplied") return {"Error": "No token supplied"}, 500 try: annotations = request.get_json() or {} except DataError as e: current_app.logger.error(f"Error validating request: {str(e)}") try: ProjectService.get_project_by_id(project_id) except NotFound as e: current_app.logger.error(f"Error validating project: {str(e)}") task_ids = [t["taskId"] for t in annotations["tasks"]] # check if task ids are valid tasks = Task.get_tasks(project_id, task_ids) tasks_ids_db = [t.id for t in tasks] if len(task_ids) != len(tasks_ids_db): return {"Error": "Invalid task id"}, 500 for annotation in annotations["tasks"]: try: TaskAnnotationsService.add_or_update_annotation( annotation, project_id, annotation_type) except DataError as e: current_app.logger.error( f"Error creating annotations: {str(e)}") return {"Error": "Error creating annotations"}, 500 return project_id, 200