Exemplo n.º 1
0
 def test_temporary_disconnect(self):
     self.signal_.connect(self.listener)
     with util.disconnected_from(self.signal_, self.listener):
         self.signal_.send()
     assert_false(self.mock_listener.called)
Exemplo n.º 2
0
    def merge_user(self, user):
        """Merge a registered user into this account. This user will be
        a contributor on any project. if the registered user and this account
        are both contributors of the same project. Then it will remove the
        registered user and set this account to the highest permission of the two
        and set this account to be visible if either of the two are visible on
        the project.

        :param user: A User object to be merged.
        """
        # Fail if the other user has conflicts.
        if not user.can_be_merged:
            raise MergeConflictError("Users cannot be merged")
        # Move over the other user's attributes
        # TODO: confirm
        for system_tag in user.system_tags:
            if system_tag not in self.system_tags:
                self.system_tags.append(system_tag)

        self.is_claimed = self.is_claimed or user.is_claimed
        self.is_invited = self.is_invited or user.is_invited

        # copy over profile only if this user has no profile info
        if user.jobs and not self.jobs:
            self.jobs = user.jobs

        if user.schools and not self.schools:
            self.schools = user.schools

        if user.social and not self.social:
            self.social = user.social

        unclaimed = user.unclaimed_records.copy()
        unclaimed.update(self.unclaimed_records)
        self.unclaimed_records = unclaimed
        # - unclaimed records should be connected to only one user
        user.unclaimed_records = {}

        security_messages = user.security_messages.copy()
        security_messages.update(self.security_messages)
        self.security_messages = security_messages

        for key, value in user.mailchimp_mailing_lists.iteritems():
            # subscribe to each list if either user was subscribed
            subscription = value or self.mailchimp_mailing_lists.get(key)
            signals.user_merged.send(self,
                                     list_name=key,
                                     subscription=subscription)

            # clear subscriptions for merged user
            signals.user_merged.send(user,
                                     list_name=key,
                                     subscription=False,
                                     send_goodbye=False)

        for node_id, timestamp in user.comments_viewed_timestamp.iteritems():
            if not self.comments_viewed_timestamp.get(node_id):
                self.comments_viewed_timestamp[node_id] = timestamp
            elif timestamp > self.comments_viewed_timestamp[node_id]:
                self.comments_viewed_timestamp[node_id] = timestamp

        self.emails.extend(user.emails)
        user.emails = []

        for k, v in user.email_verifications.iteritems():
            email_to_confirm = v['email']
            if k not in self.email_verifications and email_to_confirm != user.username:
                self.email_verifications[k] = v
        user.email_verifications = {}

        # FOREIGN FIELDS
        for watched in user.watched:
            if watched not in self.watched:
                self.watched.append(watched)
        user.watched = []

        for account in user.external_accounts:
            if account not in self.external_accounts:
                self.external_accounts.append(account)
        user.external_accounts = []

        # - addons
        # Note: This must occur before the merged user is removed as a
        #       contributor on the nodes, as an event hook is otherwise fired
        #       which removes the credentials.
        for addon in user.get_addons():
            user_settings = self.get_or_add_addon(addon.config.short_name)
            user_settings.merge(addon)
            user_settings.save()

        # Disconnect signal to prevent emails being sent about being a new contributor when merging users
        # be sure to reconnect it at the end of this code block. Import done here to prevent circular import error.
        from website.project.signals import contributor_added
        from website.project.views.contributor import notify_added_contributor
        from website.util import disconnected_from

        # - projects where the user was a contributor
        with disconnected_from(signal=contributor_added,
                               listener=notify_added_contributor):
            for node in user.node__contributed:
                # Skip dashboard node
                if node.is_dashboard:
                    continue
                # if both accounts are contributor of the same project
                if node.is_contributor(self) and node.is_contributor(user):
                    if node.permissions[user._id] > node.permissions[self._id]:
                        permissions = node.permissions[user._id]
                    else:
                        permissions = node.permissions[self._id]
                    node.set_permissions(user=self, permissions=permissions)

                    visible1 = self._id in node.visible_contributor_ids
                    visible2 = user._id in node.visible_contributor_ids
                    if visible1 != visible2:
                        node.set_visible(user=self,
                                         visible=True,
                                         log=True,
                                         auth=Auth(user=self))

                else:
                    node.add_contributor(
                        contributor=self,
                        permissions=node.get_permissions(user),
                        visible=node.get_visible(user),
                        log=False,
                    )

                try:
                    node.remove_contributor(
                        contributor=user,
                        auth=Auth(user=self),
                        log=False,
                    )
                except ValueError:
                    logger.error(
                        'Contributor {0} not in list on node {1}'.format(
                            user._id, node._id))
                node.save()

        # - projects where the user was the creator
        for node in user.node__created:
            node.creator = self
            node.save()

        # - file that the user has checked_out, import done here to prevent import error
        from website.files.models.base import FileNode
        for file_node in FileNode.files_checked_out(user=user):
            file_node.checkout = self
            file_node.save()

        # finalize the merge

        remove_sessions_for_user(user)

        # - username is set to None so the resultant user can set it primary
        #   in the future.
        user.username = None
        user.password = None
        user.verification_key = None
        user.osf_mailing_lists = {}
        user.merged_by = self

        user.save()
Exemplo n.º 3
0
 def test_temporary_disconnect(self):
     self.signal_.connect(self.listener)
     with util.disconnected_from(self.signal_, self.listener):
         self.signal_.send()
     self.mock_listener.assert_not_called()
Exemplo n.º 4
0
    def merge_user(self, user):
        """Merge a registered user into this account. This user will be
        a contributor on any project. if the registered user and this account
        are both contributors of the same project. Then it will remove the
        registered user and set this account to the highest permission of the two
        and set this account to be visible if either of the two are visible on
        the project.

        :param user: A User object to be merged.
        """
        # Fail if the other user has conflicts.
        if not user.can_be_merged:
            raise MergeConflictError("Users cannot be merged")
        # Move over the other user's attributes
        # TODO: confirm
        for system_tag in user.system_tags:
            if system_tag not in self.system_tags:
                self.system_tags.append(system_tag)

        self.is_claimed = self.is_claimed or user.is_claimed
        self.is_invited = self.is_invited or user.is_invited

        # copy over profile only if this user has no profile info
        if user.jobs and not self.jobs:
            self.jobs = user.jobs

        if user.schools and not self.schools:
            self.schools = user.schools

        if user.social and not self.social:
            self.social = user.social

        unclaimed = user.unclaimed_records.copy()
        unclaimed.update(self.unclaimed_records)
        self.unclaimed_records = unclaimed
        # - unclaimed records should be connected to only one user
        user.unclaimed_records = {}

        security_messages = user.security_messages.copy()
        security_messages.update(self.security_messages)
        self.security_messages = security_messages

        for key, value in user.mailchimp_mailing_lists.iteritems():
            # subscribe to each list if either user was subscribed
            subscription = value or self.mailchimp_mailing_lists.get(key)
            signals.user_merged.send(self, list_name=key, subscription=subscription)

            # clear subscriptions for merged user
            signals.user_merged.send(user, list_name=key, subscription=False, send_goodbye=False)

        for node_id, timestamp in user.comments_viewed_timestamp.iteritems():
            if not self.comments_viewed_timestamp.get(node_id):
                self.comments_viewed_timestamp[node_id] = timestamp
            elif timestamp > self.comments_viewed_timestamp[node_id]:
                self.comments_viewed_timestamp[node_id] = timestamp

        self.emails.extend(user.emails)
        user.emails = []

        for k, v in user.email_verifications.iteritems():
            email_to_confirm = v['email']
            if k not in self.email_verifications and email_to_confirm != user.username:
                self.email_verifications[k] = v
        user.email_verifications = {}

        # FOREIGN FIELDS
        for watched in user.watched:
            if watched not in self.watched:
                self.watched.append(watched)
        user.watched = []

        for account in user.external_accounts:
            if account not in self.external_accounts:
                self.external_accounts.append(account)
        user.external_accounts = []

        # - addons
        # Note: This must occur before the merged user is removed as a
        #       contributor on the nodes, as an event hook is otherwise fired
        #       which removes the credentials.
        for addon in user.get_addons():
            user_settings = self.get_or_add_addon(addon.config.short_name)
            user_settings.merge(addon)
            user_settings.save()

        # Disconnect signal to prevent emails being sent about being a new contributor when merging users
        # be sure to reconnect it at the end of this code block. Import done here to prevent circular import error.
        from website.project.signals import contributor_added
        from website.project.views.contributor import notify_added_contributor
        from website.util import disconnected_from

        # - projects where the user was a contributor
        with disconnected_from(signal=contributor_added, listener=notify_added_contributor):
            for node in user.node__contributed:
                # Skip dashboard node
                if node.is_dashboard:
                    continue
                # if both accounts are contributor of the same project
                if node.is_contributor(self) and node.is_contributor(user):
                    if node.permissions[user._id] > node.permissions[self._id]:
                        permissions = node.permissions[user._id]
                    else:
                        permissions = node.permissions[self._id]
                    node.set_permissions(user=self, permissions=permissions)

                    visible1 = self._id in node.visible_contributor_ids
                    visible2 = user._id in node.visible_contributor_ids
                    if visible1 != visible2:
                        node.set_visible(user=self, visible=True, log=True, auth=Auth(user=self))

                else:
                    node.add_contributor(
                        contributor=self,
                        permissions=node.get_permissions(user),
                        visible=node.get_visible(user),
                        log=False,
                    )

                try:
                    node.remove_contributor(
                        contributor=user,
                        auth=Auth(user=self),
                        log=False,
                    )
                except ValueError:
                    logger.error('Contributor {0} not in list on node {1}'.format(
                        user._id, node._id
                    ))
                node.save()

        # - projects where the user was the creator
        for node in user.node__created:
            node.creator = self
            node.save()

        # - file that the user has checked_out, import done here to prevent import error
        from website.files.models.base import FileNode
        for file_node in FileNode.files_checked_out(user=user):
            file_node.checkout = self
            file_node.save()

        # finalize the merge

        remove_sessions_for_user(user)

        # - username is set to None so the resultant user can set it primary
        #   in the future.
        user.username = None
        user.password = None
        user.verification_key = None
        user.osf_mailing_lists = {}
        user.merged_by = self

        user.save()