def is_user_action_permitted_on_project(authenticated_user_id: int, project_id: int) -> bool: """ Is user action permitted on project""" project = Project.get(project_id) author_id = project.author_id allowed_roles = [TeamRoles.PROJECT_MANAGER.value] is_admin = UserService.is_user_an_admin(authenticated_user_id) is_author = UserService.is_user_the_project_author( authenticated_user_id, author_id) is_org_manager = False if hasattr(project, "organisation_id") and project.organisation_id: org_id = project.organisation_id org = OrganisationService.get_organisation_by_id_as_dto( org_id, authenticated_user_id) if org.is_manager: is_org_manager = True is_manager_team = None if hasattr(project, "project_teams") and project.project_teams: teams_dto = TeamService.get_project_teams_as_dto(project_id) if teams_dto.teams: teams_allowed = [ team_dto for team_dto in teams_dto.teams if team_dto.role in allowed_roles ] user_membership = [ team_dto.team_id for team_dto in teams_allowed if TeamService.is_user_member_of_team( team_dto.team_id, authenticated_user_id) ] if user_membership: is_manager_team = True return is_admin or is_author or is_org_manager or is_manager_team
def _get_project_by_id(project_id: int) -> Project: project = Project.get(project_id) if project is None: raise NotFound() return project
def delete_tasks(project_id: int, tasks_ids): # Validate project exists. project = Project.get(project_id) if project is None: raise NotFound({"project": project_id}) tasks = [{"id": i, "obj": Task.get(i, project_id)} for i in tasks_ids] # In case a task is not found. not_found = [t["id"] for t in tasks if t["obj"] is None] if len(not_found) > 0: raise NotFound({"tasks": not_found}) # Delete task one by one. [t["obj"].delete() for t in tasks]
def transfer_project_to(project_id: int, transfering_user_id: int, username: str): """ Transfers project from old owner (transfering_user_id) to new owner (username) """ project = Project.get(project_id) # Check permissions for the user (transferring_user_id) who initiatied the action if not ProjectAdminService.is_user_action_permitted_on_project( transfering_user_id, project_id): raise ValueError("User action not permitted") new_owner = UserService.get_user_by_username(username) # Check permissions for the new owner - must be an admin or project's org manager or a PM team member if not ProjectAdminService.is_user_action_permitted_on_project( new_owner.id, project_id): raise ValueError("User action not permitted") else: project.save()
def test_project_can_be_cloned(self): self.test_project, self.test_user = create_canned_project() # Arrange self.update_project_with_info() # Act original_id = copy.copy(self.test_project.id) cloned_project = Project.clone(original_id, self.test_user.id) self.assertTrue(cloned_project) self.assertEqual(cloned_project.project_info[0].name, "Thinkwhere Test") # Tidy Up cloned_project.delete() original_project = Project.get( original_id ) # SQLAlchemy is hanging on to a ref to the old project original_project.delete()
def is_user_action_permitted_on_project(authenticated_user_id: int, project_id: int) -> bool: """ Is user action permitted on project""" project = Project.get(project_id) author_id = project.author_id allowed_roles = [TeamRoles.PROJECT_MANAGER.value] is_admin = UserService.is_user_an_admin(authenticated_user_id) is_author = UserService.is_user_the_project_author( authenticated_user_id, author_id) is_org_manager = False is_manager_team = False if not (is_admin or is_author): if hasattr(project, "organisation_id") and project.organisation_id: org_id = project.organisation_id is_org_manager = OrganisationService.is_user_an_org_manager( org_id, authenticated_user_id) if not is_org_manager: is_manager_team = TeamService.check_team_membership( project_id, allowed_roles, authenticated_user_id) return is_admin or is_author or is_org_manager or is_manager_team
def split_task(split_task_dto: SplitTaskDTO) -> TaskDTOs: """ Replaces a task square with 4 smaller tasks at the next OSM tile grid zoom level Validates that task is: - locked for mapping by current user :param split_task_dto: :return: new tasks in a DTO """ # get the task to be split original_task = Task.get(split_task_dto.task_id, split_task_dto.project_id) if original_task is None: raise NotFound() original_geometry = shape.to_shape(original_task.geometry) # check its locked for mapping by the current user if TaskStatus( original_task.task_status) != TaskStatus.LOCKED_FOR_MAPPING: raise SplitServiceError( "Status must be LOCKED_FOR_MAPPING to split") if original_task.locked_by != split_task_dto.user_id: raise SplitServiceError( "Attempting to split a task owned by another user") # create new geometries from the task geometry try: new_tasks_geojson = SplitService._create_split_tasks( original_task.x, original_task.y, original_task.zoom, original_task) except Exception as e: raise SplitServiceError(f"Error splitting task{str(e)}") # create new tasks from the new geojson i = Task.get_max_task_id_for_project(split_task_dto.project_id) new_tasks = [] new_tasks_dto = [] for new_task_geojson in new_tasks_geojson: # Sanity check: ensure the new task geometry intersects the original task geometry new_geometry = shapely_shape(new_task_geojson.geometry) if not new_geometry.intersects(original_geometry): raise InvalidGeoJson( "New split task does not intersect original task") # insert new tasks into database i = i + 1 new_task = Task.from_geojson_feature(i, new_task_geojson) new_task.project_id = split_task_dto.project_id new_task.task_status = TaskStatus.READY.value new_task.create() new_task.task_history.extend(original_task.copy_task_history()) if new_task.task_history: new_task.clear_task_lock() # since we just copied the lock new_task.set_task_history(TaskAction.STATE_CHANGE, split_task_dto.user_id, None, TaskStatus.SPLIT) new_task.set_task_history(TaskAction.STATE_CHANGE, split_task_dto.user_id, None, TaskStatus.READY) new_task.task_status = TaskStatus.READY.value new_tasks.append(new_task) new_task.update() new_tasks_dto.append( new_task.as_dto_with_instructions( split_task_dto.preferred_locale)) # delete original task from the database try: original_task.delete() except Exception: db.session.rollback() # Ensure the new tasks are cleaned up for new_task in new_tasks: new_task.delete() db.session.commit() raise # update project task counts project = Project.get(split_task_dto.project_id) project.total_tasks = project.tasks.count() # update bad imagery because we may have split a bad imagery tile project.tasks_bad_imagery = project.tasks.filter( Task.task_status == TaskStatus.BADIMAGERY.value).count() project.save() # return the new tasks in a DTO task_dtos = TaskDTOs() task_dtos.tasks = new_tasks_dto return task_dtos