Example #1
0
 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
Example #3
0
    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)
Example #11
0
    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)
Example #12
0
 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
Example #14
0
    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
Example #16
0
    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
Example #17
0
 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
Example #18
0
    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>'
        )
Example #19
0
 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