def post(self): """ Resends the validation user to the logged in user --- tags: - messaging produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== responses: 200: description: Resends the user their email verification email 500: description: Internal Server Error """ try: MessageService.resend_email_validation(tm.authenticated_user_id) return {"Success": "Verification email resent"}, 200 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 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 login_user(osm_user_details, redirect_to, user_element='user') -> str: """ Generates authentication details for user, creating in DB if user is unknown to us :param osm_user_details: XML response from OSM :param redirect_to: Route to redirect user to, from callback url :param user_element: Exists for unit testing :raises AuthServiceError :returns Authorized URL with authentication details in query string """ osm_user = osm_user_details.find(user_element) if osm_user is None: raise AuthServiceError('User element not found in OSM response') osm_id = int(osm_user.attrib['id']) username = osm_user.attrib['display_name'] try: UserService.get_user_by_id(osm_id) except NotFound: # User not found, so must be new user changesets = osm_user.find('changesets') changeset_count = int(changesets.attrib['count']) new_user = UserService.register_user(osm_id, username, changeset_count) MessageService.send_welcome_message(new_user) session_token = AuthenticationService.generate_session_token_for_user( osm_id) authorized_url = AuthenticationService.generate_authorized_url( username, session_token, redirect_to) return authorized_url
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 post(self, project_id): """ Send message to all contributors to a project --- tags: - messages produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: project_id in: path description: The unique project ID required: true type: integer default: 1 - in: body name: body required: true description: JSON object for creating draft project schema: properties: subject: type: string default: Thanks required: true message: type: string default: Thanks for your contribution required: true responses: 200: description: All mapped tasks validated 401: description: Unauthorized - Invalid credentials 500: description: Internal Server Error """ try: message_dto = MessageDTO(request.get_json()) message_dto.from_user_id = tm.authenticated_user_id message_dto.validate() except DataError as e: current_app.logger.error(f'Error validating request: {str(e)}') return str(e), 400 try: MessageService.send_message_to_all_contributors( project_id, message_dto) return {"Success": "Messages sent"}, 200 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 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 post_message(chat_dto: ChatMessageDTO) -> ProjectChatDTO: """ Save message to DB and return latest chat""" current_app.logger.debug('Posting Chat Message') chat_message = ProjectChat.create_from_dto(chat_dto) MessageService.send_message_after_chat(chat_dto.user_id, chat_message.message, chat_dto.project_id) db.session.commit() # Ensure we return latest messages after post return ProjectChat.get_messages(chat_dto.project_id, 1)
def stop_mapping_task(stop_task: StopMappingTaskDTO) -> TaskDTO: """ Unlocks the task and sets the task history appropriately """ task = MappingService.get_task_locked_by_user(stop_task.project_id, stop_task.task_id, stop_task.user_id) if stop_task.comment: # Parses comment to see if any users have been @'d MessageService.send_message_after_comment(stop_task.user_id, stop_task.comment, task.id, stop_task.project_id) task.reset_lock(stop_task.user_id, stop_task.comment) return task.as_dto_with_instructions(stop_task.preferred_locale)
def test_welcome_message_sent(self): if self.skip_tests: return # Act message_id = MessageService.send_welcome_message(self.test_user) message = MessageService.get_message(message_id, self.test_user.id) # Assert self.assertTrue(message, 'Message should be saved to DB') # Tidyup MessageService.delete_message(message_id, self.test_user.id)
def post_message(chat_dto: ChatMessageDTO) -> ProjectChatDTO: """ Save message to DB and return latest chat""" current_app.logger.debug('Posting Chat Message') if UserService.is_user_blocked(tm.authenticated_user_id): return 'User is on read only mode', 403 chat_message = ProjectChat.create_from_dto(chat_dto) MessageService.send_message_after_chat(chat_dto.user_id, chat_message.message, chat_dto.project_id) db.session.commit() # Ensure we return latest messages after post return ProjectChat.get_messages(chat_dto.project_id, 1)
def add_task_comment(task_comment: TaskCommentDTO) -> TaskDTO: """ Adds the comment to the task history """ task = Task.get(task_comment.task_id, task_comment.project_id) if task is None: raise MappingServiceError(f'Task {task_id} not found') task.set_task_history(TaskAction.COMMENT, task_comment.user_id, task_comment.comment) # Parse comment to see if any users have been @'d MessageService.send_message_after_comment(task_comment.user_id, task_comment.comment, task.id, task_comment.project_id) task.update() return task.as_dto_with_instructions(task_comment.preferred_locale)
def get(self): """ Gets count of unread messages --- tags: - messaging produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== responses: 200: description: Message info 500: description: Internal Server Error """ try: unread_messages = MessageService.has_user_new_messages( tm.authenticated_user_id) return unread_messages, 200 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 get(self): """ Get all messages for logged in user --- tags: - messaging produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== responses: 200: description: Messages found 404: description: User has no messages 500: description: Internal Server Error """ try: user_messages = MessageService.get_all_messages( tm.authenticated_user_id) return user_messages.to_primitive(), 200 except NotFound: return {"Error": "No messages found"}, 404 except Exception as e: error_msg = f'Messages GET all - unhandled error: {str(e)}' current_app.logger.critical(error_msg) return {"error": error_msg}, 500
def test_message_service_identifies_all_users(self): # Act usernames = MessageService._parse_comment_for_username( 'Hello @[Iain Hunter] and "[LindaA1]') # Assert self.assertEqual(usernames[0], 'Iain Hunter') self.assertEqual(usernames[1], 'LindaA1')
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 delete(self): """ Delete specified messages for logged in user --- tags: - messaging 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 containing message ids to delete schema: properties: messageIds: type: array items: integer required: true responses: 200: description: Messages deleted 500: description: Internal Server Error """ try: message_ids = request.get_json()['messageIds'] if message_ids: MessageService.delete_multiple_messages( message_ids, tm.authenticated_user_id) return {"Success": "Messages deleted"}, 200 except Exception as e: error_msg = f'DeleteMultipleMessages - unhandled error: {str(e)}' current_app.logger.critical(error_msg) return {"error": error_msg}, 500
def delete(self, message_id): """ Deletes the specified message --- tags: - messaging produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - name: message_id in: path description: The unique message required: true type: integer default: 1 responses: 200: description: Messages found 403: description: Forbidden, if user attempting to ready other messages 404: description: Not found 500: description: Internal Server Error """ try: MessageService.delete_message(message_id, tm.authenticated_user_id) return {"Success": "Message deleted"}, 200 except MessageServiceError as e: return {"Error": str(e)}, 403 except NotFound: return {"Error": "No messages found"}, 404 except Exception as e: error_msg = f'Messages GET all - unhandled error: {str(e)}' current_app.logger.critical(error_msg) return {"error": error_msg}, 500
def test_message_service_generates_hyperlink(self): # Act link = MessageService.get_task_link( 1, 1, 'http://tasking-manager-staging.eu-west-1.elasticbeanstalk.com') # Assert self.assertEqual( link, '<a href="http://tasking-manager-staging.eu-west-1.elasticbeanstalk.com/project/1/?task=1">Task 1</a>' )
def get(self): """ Get all messages for logged in user --- tags: - messaging produces: - application/json parameters: - in: header name: Authorization description: Base64 encoded session token required: true type: string default: Token sessionTokenHere== - in: query name: messageType description: Optional message-type filter type: integer - in: query name: from description: Optional from username filter type: string - in: query name: project description: Optional project filter type: string - in: query name: taskId description: Optional task filter type: integer - in: query name: sortBy description: field to sort by, defaults to date type: string - in: query name: sortDirection description: direction of sort, defaults to desc type: string - in: query name: page description: Page of results user requested type: integer - in: query name: pageSize description: Size of page, defaults to 10 type: integer responses: 200: description: Messages found 404: description: User has no messages 500: description: Internal Server Error """ try: preferred_locale = request.environ.get('HTTP_ACCEPT_LANGUAGE') page = request.args.get('page', 1, int) page_size = request.args.get('pageSize', 10, int) sort_by = request.args.get('sortBy') sort_direction = request.args.get('sortDirection') message_type = request.args.get('messageType', None, int) from_username = request.args.get('from') project = request.args.get('project') task_id = request.args.get('taskId', None, int) user_messages = MessageService.get_all_messages( tm.authenticated_user_id, preferred_locale, page, page_size, sort_by, sort_direction, message_type, from_username, project, task_id) return user_messages.to_primitive(), 200 except NotFound: return {"Error": "No messages found"}, 404 except Exception as e: error_msg = f'Messages GET all - unhandled error: {str(e)}' current_app.logger.critical(error_msg) return {"error": error_msg}, 500