def get(self): """ Get all projects for logged in admin --- tags: - projects produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - in: header name: Accept-Language description: Language user is requesting type: string required: true default: en responses: 200: description: All mapped tasks validated 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 404: description: Admin has no projects 500: description: Internal Server Error """ try: authenticated_user_id = token_auth.current_user() orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto( authenticated_user_id ) if len(orgs_dto.organisations) < 1: raise ValueError("User not a project manager") except ValueError as e: error_msg = f"ProjectsQueriesOwnerAPI GET: {str(e)}" return {"Error": error_msg}, 403 try: search_dto = self.setup_search_dto() admin_projects = ProjectAdminService.get_projects_for_admin( authenticated_user_id, request.environ.get("HTTP_ACCEPT_LANGUAGE"), search_dto, ) return admin_projects.to_primitive(), 200 except NotFound: return {"Error": "No comments found"}, 404 except Exception as e: error_msg = f"Project GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def delete(self, campaign_id): """ Deletes an existing campaign --- tags: - campaigns produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token type: string required: true default: Token sessionTokenHere== - in: header name: Accept-Language description: Language user is requesting type: string required: true default: en - name: campaign_id in: path description: Campaign ID required: true type: integer default: 1 responses: 200: description: Campaign deleted successfully 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 500: description: Internal Server Error """ try: orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto( token_auth.current_user() ) if len(orgs_dto.organisations) < 1: raise ValueError("User not a Org Manager") except ValueError as e: error_msg = f"CampaignsRestAPI DELETE: {str(e)}" return {"Error": error_msg}, 403 try: campaign = CampaignService.get_campaign(campaign_id) CampaignService.delete_campaign(campaign.id) return {"Success": "Campaign deleted"}, 200 except NotFound: return {"Error": "Campaign not found"}, 404 except Exception as e: error_msg = f"Campaign DELETE - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def delete(self, interest_id): """ Delete a specified interest --- tags: - interests produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: interest_id in: path description: Unique interest ID required: true type: integer default: 1 responses: 200: description: Interest deleted 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 404: description: Interest not found 500: description: Internal Server Error """ try: orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto( tm.authenticated_user_id ) if len(orgs_dto.organisations) < 1: raise ValueError("User not a Org Manager") except ValueError as e: error_msg = f"InterestsAllAPI DELETE: {str(e)}" return {"Error": error_msg}, 403 try: InterestService.delete(interest_id) return {"Success": "Interest deleted"}, 200 except NotFound: return {"Error": "Interest Not Found"}, 404 except Exception as e: error_msg = f"License DELETE - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
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 """ user_id = draft_project_dto.user_id is_admin = UserService.is_user_an_admin(user_id) user_orgs = OrganisationService.get_organisations_managed_by_user_as_dto( user_id) is_org_manager = len(user_orgs.organisations) > 0 # First things first, we need to validate that the author_id is a PM. issue #1715 if not (is_admin or is_org_manager): user = UserService.get_user_by_id(user_id) raise (ProjectAdminServiceError( f"User {user.username} is not permitted to create 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, user_id) else: draft_project = Project() org = OrganisationService.get_organisation_by_id( draft_project_dto.organisation) if org is None: raise NotFound("Organisation does not exist") draft_project_dto.organisation = org 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() draft_project.set_country_info() return draft_project.id
def get(self, interest_id): """ Get an existing interest --- tags: - interests produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: interest_id in: path description: Interest ID required: true type: integer default: 1 responses: 200: description: Interest 400: description: Invalid Request 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 500: description: Internal Server Error """ try: orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto( tm.authenticated_user_id ) if len(orgs_dto.organisations) < 1: raise ValueError("User not a Org Manager") except ValueError as e: error_msg = f"InterestsRestAPI GET: {str(e)}" return {"Error": error_msg}, 403 try: interest = InterestService.get(interest_id) return interest.to_primitive(), 200 except Exception as e: error_msg = f"Interest GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def delete_project(project_id: int, authenticated_user_id: int): """ Deletes project if it has no completed tasks """ project = ProjectAdminService._get_project_by_id(project_id) is_admin = UserService.is_user_an_admin(authenticated_user_id) user_orgs = OrganisationService.get_organisations_managed_by_user_as_dto( authenticated_user_id) is_org_manager = len(user_orgs.organisations) > 0 if is_admin or is_org_manager: if project.can_be_deleted(): project.delete() else: raise ProjectAdminServiceError( "Project has mapped tasks, cannot be deleted") else: raise ProjectAdminServiceError( "User does not have permissions to delete project")
def get(self): """ List and search projects by bounding box --- tags: - projects produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - in: header name: Accept-Language description: Language user is requesting type: string default: en - in: query name: bbox description: comma separated list xmin, ymin, xmax, ymax type: string required: true default: 34.404,-1.034, 34.717,-0.624 - in: query name: srid description: srid of bbox coords type: integer default: 4326 - in: query name: createdByMe description: limit to projects created by authenticated user type: boolean required: true default: false responses: 200: description: ok 400: description: Client Error - Invalid Request 403: description: Forbidden 500: description: Internal Server Error """ try: authenticated_user_id = token_auth.current_user() orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto( authenticated_user_id ) if len(orgs_dto.organisations) < 1: raise ValueError("User not a project manager") except ValueError as e: error_msg = f"ProjectsQueriesBboxAPI GET: {str(e)}" return {"Error": error_msg}, 403 try: search_dto = ProjectSearchBBoxDTO() search_dto.bbox = map(float, request.args.get("bbox").split(",")) search_dto.input_srid = request.args.get("srid") search_dto.preferred_locale = request.environ.get("HTTP_ACCEPT_LANGUAGE") created_by_me = ( strtobool(request.args.get("createdByMe")) if request.args.get("createdByMe") else False ) if created_by_me: search_dto.project_author = authenticated_user_id search_dto.validate() except Exception as e: current_app.logger.error(f"Error validating request: {str(e)}") return {"Error": "Unable to fetch projects"}, 400 try: geojson = ProjectSearchService.get_projects_geojson(search_dto) return geojson, 200 except BBoxTooBigError: return {"Error": "Bounding Box too large"}, 403 except ProjectSearchServiceError: return {"Error": "Unable to fetch projects"}, 400 except Exception as e: error_msg = f"ProjectsQueriesBboxAPI GET - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": "Unable to fetch projects"}, 500
def patch(self, campaign_id): """ Updates an existing campaign --- tags: - campaigns produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token type: string required: true default: Token sessionTokenHere== - in: header name: Accept-Language description: Language user is requesting type: string required: true default: en - name: campaign_id in: path description: Campaign ID required: true type: integer default: 1 - in: body name: body required: true description: JSON object for updating a Campaign schema: properties: name: type: string example: HOT Campaign logo: type: string example: https://tasks.hotosm.org/assets/img/hot-tm-logo.svg url: type: string example: https://hotosm.org organisations: type: array items: type: integer default: [ 1 ] responses: 200: description: Campaign updated successfully 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 409: description: Resource duplication 500: description: Internal Server Error """ try: orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto( token_auth.current_user()) if len(orgs_dto.organisations) < 1: raise ValueError("User not a Org Manager") except ValueError as e: error_msg = f"CampaignsRestAPI PATCH: {str(e)}" return {"Error": error_msg}, 403 try: campaign_dto = CampaignDTO(request.get_json()) campaign_dto.validate() except DataError as e: current_app.logger.error(f"error validating request: {str(e)}") return str(e), 400 try: campaign = CampaignService.update_campaign(campaign_dto, campaign_id) return {"Success": "Campaign {} updated".format(campaign.id)}, 200 except NotFound: return {"Error": "Campaign not found"}, 404 except ValueError: error_msg = "Campaign PATCH - name already exists" return {"Error": error_msg}, 409 except Exception as e: error_msg = f"Campaign PATCH - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def patch(self, interest_id): """ Update an existing interest --- tags: - interests produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: interest_id in: path description: Interest ID required: true type: integer default: 1 - in: body name: body required: true description: JSON object for creating a new interest schema: properties: name: type: string default: Public Domain responses: 200: description: Interest updated 400: description: Invalid Request 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 500: description: Internal Server Error """ try: orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto( token_auth.current_user()) if len(orgs_dto.organisations) < 1: raise ValueError("User not a Org Manager") except ValueError as e: error_msg = f"InterestsAllAPI PATCH: {str(e)}" return {"Error": error_msg}, 403 try: interest_dto = InterestDTO(request.get_json()) interest_dto.validate() except DataError as e: current_app.logger.error(f"Error validating request: {str(e)}") return str(e), 400 try: update_interest = InterestService.update(interest_id, interest_dto) return update_interest.to_primitive(), 200 except Exception as e: error_msg = f"Interest PUT - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def post(self): """ Creates a new campaign --- tags: - campaigns produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token type: string required: true default: Token sessionTokenHere== - in: header name: Accept-Language description: Language user is requesting type: string required: true default: en - in: body name: body required: true description: JSON object for creating a new Campaign schema: properties: name: type: string example: HOT Campaign logo: type: string example: https://tasks.hotosm.org/assets/img/hot-tm-logo.svg url: type: string example: https://hotosm.org organisations: type: array items: type: integer default: [ 1 ] responses: 200: description: New campaign created successfully 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 500: description: Internal Server Error """ try: orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto( tm.authenticated_user_id ) if len(orgs_dto.organisations) < 1: raise ValueError("User not a Org Manager") except ValueError as e: error_msg = f"CampaignsAllAPI POST: {str(e)}" return {"Error": error_msg}, 403 try: campaign_dto = NewCampaignDTO(request.get_json()) campaign_dto.validate() except DataError as e: current_app.logger.error(f"error validating request: {str(e)}") return str(e), 400 try: campaign = CampaignService.create_campaign(campaign_dto) return {"campaignId": campaign.id}, 200 except Exception as e: error_msg = f"Campaign POST - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500
def post(self): """ Creates a new interest --- tags: - interests 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 for creating a new interest schema: properties: name: type: string default: Public Domain responses: 200: description: New interest created 400: description: Invalid Request 401: description: Unauthorized - Invalid credentials 403: description: Forbidden 500: description: Internal Server Error """ try: orgs_dto = OrganisationService.get_organisations_managed_by_user_as_dto( tm.authenticated_user_id ) if len(orgs_dto.organisations) < 1: raise ValueError("User not a Org Manager") except ValueError as e: error_msg = f"InterestsAllAPI POST: {str(e)}" return {"Error": error_msg}, 403 try: interest_dto = InterestDTO(request.get_json()) interest_dto.validate() except DataError as e: current_app.logger.error(f"Error validating request: {str(e)}") return str(e), 400 try: new_interest = InterestService.create(interest_dto.name) return new_interest.to_primitive(), 200 except IntegrityError: return ( {"error": "Value '{0}' already exists".format(interest_dto.name)}, 400, ) except Exception as e: error_msg = f"Interest POST - unhandled error: {str(e)}" current_app.logger.critical(error_msg) return {"Error": error_msg}, 500