Esempio n. 1
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
Esempio n. 2
0
    def test_get_user_by_id_returns_not_found_exception(self):
        """ Get a canned user from the DB """
        if self.skip_tests:
            return

        # Arrange
        test_user_id = 9999999999999999999

        # Act
        with self.assertRaises(NotFound):
            UserService.get_user_by_id(test_user_id)
Esempio n. 3
0
    def set_counters_after_undo(project_id: int, user_id: int, current_state: TaskStatus, undo_state: TaskStatus):
        """ Resets counters after a user undoes their task"""
        project = ProjectService.get_project_by_id(project_id)
        user = UserService.get_user_by_id(user_id)

        # This is best endeavours to reset the stats and may have missed some edge cases, hopefully majority of
        # cases will be Mapped to Ready
        if current_state == TaskStatus.MAPPED and undo_state == TaskStatus.READY:
            project.tasks_mapped -= 1
            user.tasks_mapped -= 1
        if current_state == TaskStatus.MAPPED and undo_state == TaskStatus.INVALIDATED:
            user.tasks_mapped -= 1
            project.tasks_mapped -= 1
        elif current_state == TaskStatus.BADIMAGERY and undo_state == TaskStatus.READY:
            project.tasks_bad_imagery -= 1
        elif current_state == TaskStatus.BADIMAGERY and undo_state == TaskStatus.MAPPED:
            project.tasks_mapped += 1
            project.tasks_bad_imagery -= 1
        elif current_state == TaskStatus.BADIMAGERY and undo_state == TaskStatus.INVALIDATED:
            project.tasks_bad_imagery -= 1
        elif current_state == TaskStatus.INVALIDATED and undo_state == TaskStatus.MAPPED:
            user.tasks_invalidated -= 1
            project.tasks_mapped += 1
        elif current_state == TaskStatus.INVALIDATED and undo_state == TaskStatus.VALIDATED:
            user.tasks_invalidated -= 1
            project.tasks_validated += 1
        elif current_state == TaskStatus.VALIDATED and undo_state == TaskStatus.MAPPED:
            user.tasks_validated -= 1
            project.tasks_validated -= 1
        elif current_state == TaskStatus.VALIDATED and undo_state == TaskStatus.BADIMAGERY:
            user.tasks_validated -= 1
            project.tasks_validated -= 1
Esempio n. 4
0
    def update_stats_after_task_state_change(project_id: int, user_id: int,
                                             new_state: TaskStatus,
                                             task_id: int):
        """ Update stats when a task has had a state change """
        if new_state in [
                TaskStatus.READY, TaskStatus.LOCKED_FOR_VALIDATION,
                TaskStatus.LOCKED_FOR_MAPPING
        ]:
            return  # No stats to record for these states

        project = ProjectService.get_project_by_id(project_id)
        user = UserService.get_user_by_id(user_id)

        if new_state == TaskStatus.MAPPED:
            StatsService._set_counters_after_mapping(project, user)
        elif new_state == TaskStatus.INVALIDATED:
            StatsService._set_counters_after_invalidated(
                task_id, project, user)
        elif new_state == TaskStatus.VALIDATED:
            StatsService._set_counters_after_validated(project, user)
        elif new_state == TaskStatus.BADIMAGERY:
            StatsService._set_counters_after_bad_imagery(project)

        UserService.upsert_mapped_projects(user_id, project_id)
        project.last_updated = timestamp()

        # Transaction will be saved when task is saved
        return project, user
    def update_stats_after_task_state_change(
        project_id: int,
        user_id: int,
        last_state: TaskStatus,
        new_state: TaskStatus,
        action="change",
    ):
        """ Update stats when a task has had a state change """

        if new_state in [
                TaskStatus.READY,
                TaskStatus.LOCKED_FOR_VALIDATION,
                TaskStatus.LOCKED_FOR_MAPPING,
        ]:
            return  # No stats to record for these states

        project = ProjectService.get_project_by_id(project_id)
        user = UserService.get_user_by_id(user_id)

        project, user = StatsService._update_tasks_stats(
            project, user, last_state, new_state, action)
        UserService.upsert_mapped_projects(user_id, project_id)
        project.last_updated = timestamp()

        # Transaction will be saved when task is saved
        return project, user
    def is_valid_token(token, token_expiry):
        """
        Validates if the supplied token is valid, and hasn't expired.
        :param token: Token to check
        :param token_expiry: When the token expires
        :return: True if token is valid
        """
        serializer = URLSafeTimedSerializer(current_app.secret_key)

        try:
            tokenised_user_id = serializer.loads(token, max_age=token_expiry)
            dmis.authenticated_user_id = tokenised_user_id
        except SignatureExpired:
            current_app.logger.debug('Token has expired')
            return False
        except BadSignature:
            current_app.logger.debug('Bad Token Signature')
            return False

        # Ensure user is Admin priv to access admin only endpoints
        if dmis.is_admin_only_resource:
            user = UserService.get_user_by_id(tokenised_user_id)
            if UserRole(user.role) != UserRole.ADMIN:
                current_app.logger.debug(f'User {tokenised_user_id} is not an Admin {request.base_url}')
                return False

        return True
Esempio n. 7
0
    def send_message_to_all_contributors(project_id: int,
                                         message_dto: MessageDTO):
        """  Sends supplied message to all contributors on specified project.  Message all contributors can take
             over a minute to run, so this method is expected to be called on its own thread """

        app = create_app(
        )  # Because message-all run on background thread it needs it's own app context

        with app.app_context():
            contributors = Message.get_all_contributors(project_id)

            project_link = MessageService.get_project_link(project_id)

            message_dto.message = f'{project_link}<br/><br/>' + message_dto.message  # Append project link to end of message

            msg_count = 0
            for contributor in contributors:
                message = Message.from_dto(contributor[0], message_dto)
                message.save()
                user = UserService.get_user_by_id(contributor[0])
                SMTPService.send_email_alert(user.email_address, user.username)
                msg_count += 1
                if msg_count == 10:
                    time.sleep(
                        0.5
                    )  # Sleep for 0.5 seconds to avoid hitting AWS rate limits every 10 messages
                    msg_count = 0
Esempio n. 8
0
    def send_message_after_validation(status: int, validated_by: int,
                                      mapped_by: int, task_id: int,
                                      project_id: int):
        """ Sends mapper a notification after their task has been marked valid or invalid """
        if validated_by == mapped_by:
            return  # No need to send a message to yourself

        user = UserService.get_user_by_id(mapped_by)
        if user.validation_message == False:
            return  # No need to send validation message

        text_template = get_template('invalidation_message_en.txt' if status == TaskStatus.INVALIDATED \
                                                                   else 'validation_message_en.txt')
        status_text = 'marked invalid' if status == TaskStatus.INVALIDATED else 'validated'
        task_link = MessageService.get_task_link(project_id, task_id)

        text_template = text_template.replace('[USERNAME]', user.username)
        text_template = text_template.replace('[TASK_LINK]', task_link)

        validation_message = Message()
        validation_message.from_user_id = validated_by
        validation_message.to_user_id = mapped_by
        validation_message.subject = f'Your mapping in Project {project_id} on {task_link} has just been {status_text}'
        validation_message.message = text_template
        validation_message.add_message()

        SMTPService.send_email_alert(user.email_address, user.username)
    def send_message_to_all_contributors(project_id: int, message_dto: MessageDTO):
        """ Sends supplied message to all contributors on specified project """
        contributors = Message.get_all_contributors(project_id)

        for contributor in contributors:
            message = Message.from_dto(contributor[0], message_dto)
            message.save()
            user = UserService.get_user_by_id(contributor[0])
            SMTPService.send_email_alert(user.email_address, user.username)
Esempio n. 10
0
    def test_get_user_by_id(self):
        """ Get a canned user from the DB """
        if self.skip_tests:
            return

        # Arrange

        # Act
        found_user = UserService.get_user_by_id(TEST_USER_ID)

        self.assertIsNotNone(found_user,
                             f'Did not find user by ID {TEST_USER_ID}')
Esempio n. 11
0
    def send_message_to_all_contributors(project_id: int, message_dto: MessageDTO):
        """ Sends supplied message to all contributors on specified project """
        contributors = Message.get_all_contributors(project_id)

        project_link = MessageService.get_project_link(project_id)

        message_dto.message = f'{project_link}<br/><br/>' + message_dto.message  # Append project link to end of message

        for contributor in contributors:
            message = Message.from_dto(contributor[0], message_dto)
            message.save()
            user = UserService.get_user_by_id(contributor[0])
            SMTPService.send_email_alert(user.email_address, user.username)
Esempio n. 12
0
    def login_user(user_id: int) -> SessionDTO:
        """
        Method gets relevant user details for a successfully authenticated customer and generates a session
        token that can be used in place of username and password for the remainder of the user session
        :param user_id: The account username
        """
        user = UserService.get_user_by_id(user_id)

        session = SessionDTO()
        session.username = user.username
        session.role = UserRole(user.role).name
        session.token = AuthenticationService.generate_timed_token(user_id)

        return session
    def send_message_after_validation(validated_by: int, mapped_by: int, task_id: int, project_id: int):
        """ Sends mapper a thank you, after their task has been marked as valid """
        if validated_by == mapped_by:
            return  # No need to send a thankyou to yourself

        text_template = get_template('validation_message_en.txt')
        task_link = MessageService.get_task_link(project_id, task_id)

        user = UserService.get_user_by_id(mapped_by)
        text_template = text_template.replace('[USERNAME]', user.username)
        text_template = text_template.replace('[TASK_LINK]', task_link)

        validation_message = Message()
        validation_message.from_user_id = validated_by
        validation_message.to_user_id = mapped_by
        validation_message.subject = f'Your mapping on {task_link} has just been validated'
        validation_message.message = text_template
        validation_message.add_message()

        SMTPService.send_email_alert(user.email_address, user.username)
    def send_message_to_all_contributors(project_id: int,
                                         message_dto: MessageDTO):
        """ Sends supplied message to all contributors on specified project """
        contributors = Message.get_all_contributors(project_id)

        project_link = MessageService.get_project_link(project_id)

        message_dto.message = f'{project_link}<br/><br/>' + message_dto.message  # Append project link to end of message

        msg_count = 0
        for contributor in contributors:
            message = Message.from_dto(contributor[0], message_dto)
            message.save()
            user = UserService.get_user_by_id(contributor[0])
            SMTPService.send_email_alert(user.email_address, user.username)
            msg_count += 1
            if msg_count == 5:
                time.sleep(
                    0.5
                )  # Sleep for 0.5 seconds to avoid hitting AWS rate limits every 5 messages
                msg_count = 0
    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)

        transfering_user = UserService.get_user_by_id(transfering_user_id)
        new_owner = UserService.get_user_by_username(username)
        is_pm = new_owner.role in (UserRole.PROJECT_MANAGER.value, UserRole.ADMIN.value)

        if not is_pm:
            raise Exception("User must be a project manager")

        if transfering_user.role == UserRole.PROJECT_MANAGER.value:
            if project.author_id == transfering_user_id:
                project.author_id = new_owner.id
                project.save()
            else:
                raise Exception("Invalid owner_id")
        elif transfering_user.role == UserRole.ADMIN.value:
            project.author_id = new_owner.id
            project.save()
        else:
            raise Exception("Normal users cannot transfer projects")
Esempio n. 16
0
 def resend_email_validation(user_id: int):
     """ Resends the email validation email to the logged in user """
     user = UserService.get_user_by_id(user_id)
     SMTPService.send_verification_email(user.email_address, user.username)