def init_counters(app): """ Initialise homepage counters so that users don't see 0 users on first load of application""" from server.services.stats_service import StatsService app.logger.debug('Initialising Homepage Counters') with app.app_context(): StatsService.get_homepage_stats()
def unlock_task_after_mapping(mapped_task: MappedTaskDTO) -> TaskDTO: """ Unlocks the task and sets the task history appropriately """ task = MappingService.get_task_locked_by_user(mapped_task.project_id, mapped_task.task_id, mapped_task.user_id) new_state = TaskStatus[mapped_task.status.upper()] if new_state not in [ TaskStatus.MAPPED, TaskStatus.BADIMAGERY, TaskStatus.READY ]: raise MappingServiceError( 'Can only set status to MAPPED, BADIMAGERY, READY after mapping' ) # Update stats around the change of state last_state = TaskHistory.get_last_status(mapped_task.project_id, mapped_task.task_id, True) StatsService.update_stats_after_task_state_change( mapped_task.project_id, mapped_task.user_id, last_state, new_state) if mapped_task.comment: # Parses comment to see if any users have been @'d MessageService.send_message_after_comment(mapped_task.user_id, mapped_task.comment, task.id, mapped_task.project_id) task.unlock_task(mapped_task.user_id, new_state, mapped_task.comment) return task.as_dto_with_instructions(mapped_task.preferred_locale)
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 test_update_after_flagging_bad_imagery(self): # Arrange test_project = Project() test_project.tasks_bad_imagery = 0 # Act StatsService._set_counters_after_bad_imagery(test_project) # Assert self.assertEqual(test_project.tasks_bad_imagery, 1)
def test_update_after_mapping_increments_counter(self): # Arrange test_project = Project() test_project.tasks_mapped = 0 test_user = User() test_user.tasks_mapped = 0 # Act StatsService._set_counters_after_mapping(test_project, test_user) # Assert self.assertEqual(test_project.tasks_mapped, 1) self.assertEqual(test_user.tasks_mapped, 1)
def undo_mapping(project_id: int, task_id: int, user_id: int, preferred_locale: str = 'en') -> TaskDTO: """ Allows a user to Undo the task state they updated """ task = MappingService.get_task(task_id, project_id) if not MappingService._is_task_undoable(user_id, task): raise MappingServiceError('Undo not allowed for this user') current_state = TaskStatus(task.task_status) undo_state = TaskHistory.get_last_status(project_id, task_id, True) StatsService.set_counters_after_undo(project_id, user_id, current_state, undo_state) task.unlock_task(user_id, undo_state, f'Undo state from {current_state.name} to {undo_state.name}', True) return task.as_dto_with_instructions(preferred_locale)
def test_update_after_mapping_increments_counter(self): # Arrange test_project = Project() test_project.tasks_mapped = 0 test_user = User() test_user.tasks_mapped = 0 # Act StatsService._update_tasks_stats(test_project, test_user, TaskStatus.READY, TaskStatus.MAPPED) # Assert self.assertEqual(test_project.tasks_mapped, 1) self.assertEqual(test_user.tasks_mapped, 1)
def test_update_after_flagging_bad_imagery(self): # Arrange test_project = Project() test_project.tasks_bad_imagery = 0 test_user = User() test_user.tasks_invalidated = 0 # Act StatsService._update_tasks_stats(test_project, test_user, TaskStatus.READY, TaskStatus.BADIMAGERY) # Assert self.assertEqual(test_project.tasks_bad_imagery, 1)
def get(self, project_id): """ Get all user contributions on a project --- tags: - stats produces: - application/json parameters: - name: project_id in: path required: true type: integer default: 1 responses: 200: description: User contributions 404: description: No contributions 500: description: Internal Server Error """ try: contributions = StatsService.get_user_contributions(project_id) return contributions.to_primitive(), 200 except NotFound: return {"Error": "No contributions on project"}, 404 except Exception as e: error_msg = f'User GET - unhandled error: {str(e)}' current_app.logger.critical(error_msg) return {"error": error_msg}, 500
def test_update_after_invalidating_bad_imagery_task_sets_counters_correctly(self, last_status): # Arrange test_project = Project() test_project.tasks_bad_imagery = 1 test_user = User() test_user.tasks_invalidated = 0 last_status.return_value = TaskStatus.BADIMAGERY # Act StatsService._set_counters_after_invalidated(1, test_project, test_user) # Assert self.assertEqual(test_project.tasks_bad_imagery, 0) self.assertEqual(test_user.tasks_invalidated, 1)
def test_update_after_invalidating_mapped_task_sets_counters_correctly(self, last_status): # Arrange test_project = Project() test_project.tasks_mapped = 1 test_user = User() test_user.tasks_invalidated = 0 last_status.return_value = TaskStatus.MAPPED # Act StatsService._set_counters_after_invalidated(1, test_project, test_user) # Assert self.assertEqual(test_project.tasks_mapped, 0) self.assertEqual(test_user.tasks_invalidated, 1)
def test_update_after_invalidating_validated_task_sets_counters_correctly( self): # Arrange test_project = Project() test_project.tasks_validated = 1 test_user = User() test_user.tasks_invalidated = 0 # Act StatsService._update_tasks_stats(test_project, test_user, TaskStatus.VALIDATED, TaskStatus.INVALIDATED) # Assert self.assertEqual(test_project.tasks_validated, 0) self.assertEqual(test_user.tasks_invalidated, 1)
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 test_homepage_stats_returns_results(self): if self.skip_tests: return # Act stats = StatsService.get_homepage_stats() # Assert self.assertGreaterEqual(stats.mappers_online, 0) self.assertGreater(stats.tasks_mapped, 0) self.assertGreater(stats.total_mappers, 0)
def test_homepage_stats_returns_results(self): if self.skip_tests: return # Arrange test_project, test_user = create_canned_project() # Act stats = StatsService.get_homepage_stats() # Assert self.assertGreater(stats.mappers_online, 0) self.assertGreater(stats.tasks_mapped, 0) self.assertGreater(stats.total_mappers, 0) # Tidy up test_project.delete() test_user.delete()
def get(self): """ Get HomePage Stats --- tags: - stats produces: - application/json responses: 200: description: Project stats 500: description: Internal Server Error """ try: stats = StatsService.get_homepage_stats() return stats.to_primitive(), 200 except Exception as e: error_msg = f'Unhandled error: {str(e)}' current_app.logger.critical(error_msg) return {"error": error_msg}, 500
def get(self, project_id): """ Get user actvity on a project --- tags: - stats produces: - application/json parameters: - name: project_id in: path required: true type: integer default: 1 - in: query name: page description: Page of results user requested type: integer responses: 200: description: Project activity 404: description: No activity 500: description: Internal Server Error """ try: page = int( request.args.get('page')) if request.args.get('page') else 1 activity = StatsService.get_latest_activity(project_id, page) return activity.to_primitive(), 200 except NotFound: return {"Error": "No activity on project"}, 404 except Exception as e: error_msg = f'User GET - unhandled error: {str(e)}' current_app.logger.critical(error_msg) return {"error": error_msg}, 500
def refresh_project_stats(): print("Started updating project stats...") StatsService.update_all_project_stats() print("Project stats updated")
def test_tasks_state_representation(self): # Arrange test_project = Project() test_project.tasks_mapped = 0 test_project.tasks_validated = 0 test_project.tasks_bad_imagery = 0 test_mapper = User() test_mapper.tasks_mapped = 0 test_mapper.tasks_validated = 0 test_mapper.tasks_invalidated = 0 test_validator = User() test_validator.tasks_mapped = 0 test_validator.tasks_validated = 0 test_validator.tasks_invalidated = 0 test_admin = User() test_admin.tasks_mapped = 0 test_admin.tasks_validated = 0 test_admin.tasks_invalidated = 0 # Mapper marks task as mapped StatsService._update_tasks_stats(test_project, test_mapper, TaskStatus.READY, TaskStatus.MAPPED) # Validator marks task as bad imagery StatsService._update_tasks_stats(test_project, test_validator, TaskStatus.MAPPED, TaskStatus.BADIMAGERY) # Admin undos marking task as bad imagery StatsService._update_tasks_stats(test_project, test_admin, TaskStatus.BADIMAGERY, TaskStatus.MAPPED, 'undo') # Validator marks task as invalid StatsService._update_tasks_stats(test_project, test_validator, TaskStatus.MAPPED, TaskStatus.INVALIDATED) # Mapper marks task as mapped StatsService._update_tasks_stats(test_project, test_mapper, TaskStatus.INVALIDATED, TaskStatus.MAPPED) # Admin undos marking task as mapped (test_mapper is given to the function though, as the author of the # last_change - compare with MappingServer.undo_mapping() method) StatsService._update_tasks_stats(test_project, test_mapper, TaskStatus.MAPPED, TaskStatus.INVALIDATED, 'undo') # Mapper marks task as mapped StatsService._update_tasks_stats(test_project, test_mapper, TaskStatus.INVALIDATED, TaskStatus.MAPPED) # Validator marks task as valid StatsService._update_tasks_stats(test_project, test_validator, TaskStatus.MAPPED, TaskStatus.VALIDATED) # Assert self.assertEqual(test_project.tasks_mapped, 0) self.assertEqual(test_project.tasks_validated, 1) self.assertEqual(test_project.tasks_bad_imagery, 0) self.assertEqual(test_mapper.tasks_mapped, 2) self.assertEqual(test_mapper.tasks_validated, 0) self.assertEqual(test_mapper.tasks_invalidated, 0) self.assertEqual(test_validator.tasks_mapped, 0) self.assertEqual(test_validator.tasks_validated, 1) self.assertEqual(test_validator.tasks_invalidated, 1) self.assertEqual(test_admin.tasks_mapped, 0) self.assertEqual(test_admin.tasks_validated, 0) self.assertEqual(test_admin.tasks_invalidated, 0)