def stop_validating_tasks( stop_validating_dto: StopValidationDTO) -> TaskDTOs: """ Unlocks supplied tasks after validation :raises ValidatatorServiceError """ reset_tasks = stop_validating_dto.reset_tasks project_id = stop_validating_dto.project_id user_id = stop_validating_dto.user_id tasks_to_unlock = ValidatorService.get_tasks_locked_by_user( project_id, reset_tasks, user_id) dtos = [] for task_to_unlock in tasks_to_unlock: task = task_to_unlock['task'] if task_to_unlock['comment']: # Parses comment to see if any users have been @'d MessageService.send_message_after_comment( user_id, task_to_unlock['comment'], task.id, project_id) task.reset_lock(user_id, task_to_unlock['comment']) dtos.append(task.as_dto()) task_dtos = TaskDTOs() task_dtos.tasks = dtos return task_dtos
def unlock_tasks_after_validation( validated_dto: UnlockAfterValidationDTO) -> TaskDTOs: """ Unlocks supplied tasks after validation :raises ValidatatorServiceError """ validated_tasks = validated_dto.validated_tasks project_id = validated_dto.project_id user_id = validated_dto.user_id tasks_to_unlock = ValidatorService.get_tasks_locked_by_user( project_id, validated_tasks, user_id) # Unlock all tasks dtos = [] message_sent_to = [] for task_to_unlock in tasks_to_unlock: task = task_to_unlock['task'] if task_to_unlock['comment']: # Parses comment to see if any users have been @'d MessageService.send_message_after_comment( validated_dto.user_id, task_to_unlock['comment'], task.id, validated_dto.project_id) if task_to_unlock[ 'new_state'] == TaskStatus.VALIDATED or task_to_unlock[ 'new_state'] == TaskStatus.INVALIDATED: # All mappers get a notification if their task has been validated or invalidated. # Only once if multiple tasks mapped if task.mapped_by not in message_sent_to: MessageService.send_message_after_validation( task_to_unlock['new_state'], validated_dto.user_id, task.mapped_by, task.id, validated_dto.project_id) message_sent_to.append(task.mapped_by) if task_to_unlock['new_state'] == TaskStatus.VALIDATED: # Set last_validation_date for the mapper to current date task.mapper.last_validation_date = timestamp() # Update stats if user setting task to a different state from previous state prev_status = TaskHistory.get_last_status(project_id, task.id) if prev_status != task_to_unlock['new_state']: StatsService.update_stats_after_task_state_change( validated_dto.project_id, validated_dto.user_id, prev_status, task_to_unlock['new_state']) task_mapping_issues = ValidatorService.get_task_mapping_issues( task_to_unlock) task.unlock_task(validated_dto.user_id, task_to_unlock['new_state'], task_to_unlock['comment'], issues=task_mapping_issues) dtos.append( task.as_dto_with_instructions(validated_dto.preferred_locale)) task_dtos = TaskDTOs() task_dtos.tasks = dtos return task_dtos
def lock_tasks_for_validation( validation_dto: LockForValidationDTO) -> TaskDTOs: """ Lock supplied tasks for validation :raises ValidatatorServiceError """ # Loop supplied tasks to check they can all be locked for validation tasks_to_lock = [] for task_id in validation_dto.task_ids: task = Task.get(task_id, validation_dto.project_id) if task is None: raise NotFound(f'Task {task_id} not found') if TaskStatus(task.task_status) not in [ TaskStatus.MAPPED, TaskStatus.VALIDATED, TaskStatus.BADIMAGERY ]: raise ValidatatorServiceError( f'Task {task_id} is not MAPPED, BADIMAGERY or VALIDATED') if not ValidatorService._user_can_validate_task( validation_dto.user_id, task.mapped_by): raise ValidatatorServiceError( f'Tasks cannot be validated by the same user who marked task as mapped or badimagery' ) tasks_to_lock.append(task) user_can_validate, error_reason = ProjectService.is_user_permitted_to_validate( validation_dto.project_id, validation_dto.user_id) if not user_can_validate: if error_reason == ValidatingNotAllowed.USER_NOT_ACCEPTED_LICENSE: raise UserLicenseError( 'User must accept license to map this task') else: raise ValidatatorServiceError( f'Mapping not allowed because: {error_reason.name}') # Lock all tasks for validation dtos = [] for task in tasks_to_lock: task.lock_task_for_validating(validation_dto.user_id) dtos.append( task.as_dto_with_instructions(validation_dto.preferred_locale)) task_dtos = TaskDTOs() task_dtos.tasks = dtos return task_dtos
def get_task_details_for_logged_in_user(project_id: int, user_id: int, preferred_locale: str): """ if the user is working on a task in the project return it """ project = ProjectService.get_project_by_id(project_id) tasks = project.get_locked_tasks_details_for_user(user_id) if len(tasks) == 0: raise NotFound() # TODO put the task details in to a DTO dtos = [] for task in tasks: dtos.append(task.as_dto_with_instructions(preferred_locale)) task_dtos = TaskDTOs() task_dtos.tasks = dtos return task_dtos
def unlock_tasks_after_validation( validated_dto: UnlockAfterValidationDTO) -> TaskDTOs: """ Unlocks supplied tasks after validation :raises ValidatatorServiceError """ validated_tasks = validated_dto.validated_tasks project_id = validated_dto.project_id user_id = validated_dto.user_id tasks_to_unlock = ValidatorService.get_tasks_locked_by_user( project_id, validated_tasks, user_id) # Unlock all tasks dtos = [] for task_to_unlock in tasks_to_unlock: task = task_to_unlock['task'] if task_to_unlock['comment']: # Parses comment to see if any users have been @'d MessageService.send_message_after_comment( validated_dto.user_id, task_to_unlock['comment'], task.id, validated_dto.project_id) if task_to_unlock['new_state'] == TaskStatus.VALIDATED: # All mappers get a thankyou if their task has been validated :) MessageService.send_message_after_validation( validated_dto.user_id, task.mapped_by, task.id, validated_dto.project_id) StatsService.update_stats_after_task_state_change( validated_dto.project_id, validated_dto.user_id, task_to_unlock['new_state'], task.id) task.unlock_task(validated_dto.user_id, task_to_unlock['new_state'], task_to_unlock['comment']) dtos.append(task.as_dto()) task_dtos = TaskDTOs() task_dtos.tasks = dtos return task_dtos
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 - splittable (splittable property is True) :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() # check it's splittable if not original_task.splittable: raise SplitServiceError('Task is not splittable') # 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) 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_dto = [] for new_task_geojson in new_tasks_geojson: # 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_task.update() new_tasks_dto.append( new_task.as_dto_with_instructions( split_task_dto.preferred_locale)) # delete original task from the database original_task.delete() # 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