def test_approval_after_initiator_is_merged_into_another_user( self, mock_enqueue): approver = factories.UserFactory() approver.add_system_tag(settings.PREREG_ADMIN_TAG) mergee = factories.UserFactory(fullname='Manny Mergee') merger = factories.UserFactory(fullname='Merve Merger') project = factories.ProjectFactory(creator=mergee) registration_schema = MetaSchema.find_one( Q('name', 'eq', 'Prereg Challenge') & Q('schema_version', 'eq', 2)) draft = factories.DraftRegistrationFactory( branched_from=project, registration_schema=registration_schema, ) merger.merge_user(mergee) approval = DraftRegistrationApproval( meta={'registration_choice': 'immediate'}) approval.save() draft.approval = approval draft.save() approval.approve(approver) draft.reload() registered_node = draft.registered_node assert registered_node.registered_user == merger
def get_file_guids(cls, materialized_path, provider, node): guids = [] materialized_path = '/' + materialized_path.lstrip('/') if materialized_path.endswith('/'): # it's a folder folder_children = cls.find( Q('provider', 'eq', provider) & Q('node', 'eq', node) & Q('_materialized_path', 'startswith', materialized_path)) for item in folder_children: if item.kind == 'file': guid = item.get_guid() if guid: guids.append(guid._id) else: # it's a file try: file_obj = cls.find_one( Q('node', 'eq', node) & Q('_materialized_path', 'eq', materialized_path)) except NoResultsFound: return guids guid = file_obj.get_guid() if guid: guids.append(guid._id) return guids
def test_on_complete_embargo_creates_registration_for_draft_initiator( self, mock_enquque): user = factories.UserFactory() end_date = timezone.now() + datetime.timedelta( days=366) # <- leap year approval = DraftRegistrationApproval( meta={ 'registration_choice': 'embargo', 'embargo_end_date': end_date.isoformat() }) approval.save() project = factories.ProjectFactory(creator=user) registration_schema = MetaSchema.find_one( Q('name', 'eq', 'Prereg Challenge') & Q('schema_version', 'eq', 2)) draft = factories.DraftRegistrationFactory( branched_from=project, registration_schema=registration_schema, ) draft.approval = approval draft.save() approval._on_complete(user) draft.reload() registered_node = draft.registered_node assert registered_node is not None assert registered_node.is_pending_embargo assert registered_node.registered_user == draft.initiator
def test_on_complete_immediate_creates_registration_for_draft_initiator(self, mock_enquque): ensure_schemas() user = factories.UserFactory() project = factories.ProjectFactory(creator=user) registration_schema = MetaSchema.find_one( Q('name', 'eq', 'Prereg Challenge') & Q('schema_version', 'eq', 2) ) draft = factories.DraftRegistrationFactory( branched_from=project, registration_schema=registration_schema, ) approval = DraftRegistrationApproval( meta={ 'registration_choice': 'immediate' } ) approval.save() draft.approval = approval draft.save() approval._on_complete(user) draft.reload() registered_node = draft.registered_node assert registered_node is not None assert registered_node.is_pending_registration assert registered_node.registered_user == draft.initiator
def get_configured_projects(user): """Filter all user subscriptions for ones that are on parent projects and return the node objects. :param user: modular odm User object :return: list of node objects for projects with no parent """ configured_projects = set() user_subscriptions = get_all_user_subscriptions( user, extra=(Q('node__type', 'ne', 'osf.collection') & Q('node__is_deleted', 'eq', False))) for subscription in user_subscriptions: if subscription is None: continue # If the user has opted out of emails skip node = subscription.owner if ((subscription.none.filter(id=user.id).exists() and not node.parent_id) or node._id not in user.notifications_configured): continue root = node.root if not root.is_deleted: configured_projects.add(root) return sorted(configured_projects, key=lambda n: n.title.lower())
def _find_matching_archive(self, save=True): """Find another version with the same sha256 as this file. If found copy its vault name and glacier id, no need to create additional backups. returns True if found otherwise false """ if 'sha256' not in self.metadata: return False # Dont bother searching for nothing if 'vault' in self.metadata and 'archive' in self.metadata: # Shouldn't ever happen, but we already have an archive return True # We've found ourself qs = self.__class__.find( Q('_id', 'ne', self._id) & Q('metadata.sha256', 'eq', self.metadata['sha256']) & Q('metadata.archive', 'ne', None) & Q('metadata.vault', 'ne', None)).limit(1) if qs.count() < 1: return False other = qs[0] try: self.metadata['vault'] = other.metadata['vault'] self.metadata['archive'] = other.metadata['archive'] except KeyError: return False if save: self.save() return True
def _create(cls, *args, **kwargs): try: models.NodeLicense.find_one(Q('name', 'eq', 'No license')) except NoResultsFound: ensure_licenses() kwargs['node_license'] = kwargs.get( 'node_license', models.NodeLicense.find_one(Q('name', 'eq', 'No license'))) return super(NodeLicenseRecordFactory, cls)._create(*args, **kwargs)
def get_targets(): logger.info('Acquiring targets...') targets = [ u for u in OSFUser.find(Q('merged_by', 'eq', None)) if Collection.find( Q('is_bookmark_collection', 'eq', True) & Q('is_deleted', 'eq', False) & Q('creator', 'eq', u)).count() == 0 ] logger.info('Found {} target users.'.format(len(targets))) return targets
def find_sent_of_same_type_and_user(self): """ Queries up for all emails of the same type as self, sent to the same user as self. Does not look for queue-up emails. :return: a list of those emails """ return self.__class__.find( Q('email_type', 'eq', self.email_type) & Q('user', 'eq', self.user) & Q('sent_at', 'ne', None) )
def get_parent_notification_type(node, event, user): """ Given an event on a node (e.g. comment on node 'xyz'), find the user's notification type on the parent project for the same event. :param obj node: event owner (Node or User object) :param str event: notification event (e.g. 'comment_replies') :param obj user: modular odm User object :return: str notification type (e.g. 'email_transactional') """ AbstractNode = apps.get_model('osf.AbstractNode') NotificationSubscription = apps.get_model('osf.NotificationSubscription') if node and isinstance( node, AbstractNode ) and node.parent_node and node.parent_node.has_permission(user, 'read'): parent = node.parent_node key = to_subscription_key(parent._id, event) try: subscription = NotificationSubscription.find_one( Q('_id', 'eq', key)) except NoResultsFound: return get_parent_notification_type(parent, event, user) for notification_type in constants.NOTIFICATION_TYPES: if getattr(subscription, notification_type).filter(id=user.id).exists(): return notification_type else: return get_parent_notification_type(parent, event, user) else: return None
def test_sanction_embargo_termination_first(self): embargo_termination_approval = factories.EmbargoTerminationApprovalFactory( ) registration = Registration.find_one( Q('embargo_termination_approval', 'eq', embargo_termination_approval)) assert registration.sanction == embargo_termination_approval
def _email_template_context(self, user, node, is_authorizer=False, urls=None): urls = urls or self.stashed_urls.get(user._id, {}) registration_link = urls.get('view', self._view_url(user._id, node)) if is_authorizer: Registration = apps.get_model('osf.Registration') approval_link = urls.get('approve', '') disapproval_link = urls.get('reject', '') approval_time_span = osf_settings.RETRACTION_PENDING_TIME.days * 24 registration = Registration.find_one(Q('retraction', 'eq', self)) return { 'is_initiator': self.initiated_by == user, 'initiated_by': self.initiated_by.fullname, 'project_name': registration.title, 'registration_link': registration_link, 'approval_link': approval_link, 'disapproval_link': disapproval_link, 'approval_time_span': approval_time_span, } else: return { 'initiated_by': self.initiated_by.fullname, 'registration_link': registration_link, }
def _on_complete(self, user): Registration = apps.get_model('osf.Registration') NodeLog = apps.get_model('osf.NodeLog') parent_registration = Registration.find_one(Q('retraction', 'eq', self)) parent_registration.registered_from.add_log( action=NodeLog.RETRACTION_APPROVED, params={ 'node': parent_registration.registered_from._id, 'retraction_id': self._id, 'registration': parent_registration._id }, auth=Auth(self.initiated_by), ) # Remove any embargoes associated with the registration if parent_registration.embargo_end_date or parent_registration.is_pending_embargo: parent_registration.embargo.state = self.REJECTED parent_registration.registered_from.add_log( action=NodeLog.EMBARGO_CANCELLED, params={ 'node': parent_registration.registered_from._id, 'registration': parent_registration._id, 'embargo_id': parent_registration.embargo._id, }, auth=Auth(self.initiated_by), ) parent_registration.embargo.save() # Ensure retracted registration is public # Pass auth=None because the registration initiator may not be # an admin on components (component admins had the opportunity # to disapprove the retraction by this point) for node in parent_registration.node_and_primary_descendants(): node.set_privacy('public', auth=None, save=True, log=False) node.update_search()
def merge(self, user_settings): """Merge `user_settings` into this instance""" if user_settings.__class__ is not self.__class__: raise TypeError('Cannot merge different addons') for node_id, data in user_settings.oauth_grants.iteritems(): if node_id not in self.oauth_grants: self.oauth_grants[node_id] = data else: node_grants = user_settings.oauth_grants[node_id].iteritems() for ext_acct, meta in node_grants: if ext_acct not in self.oauth_grants[node_id]: self.oauth_grants[node_id][ext_acct] = meta else: for k, v in meta: if k not in self.oauth_grants[node_id][ext_acct]: self.oauth_grants[node_id][ext_acct][k] = v user_settings.oauth_grants = {} user_settings.save() try: config = settings.ADDONS_AVAILABLE_DICT[ self.oauth_provider.short_name] Model = config.models['nodesettings'] except KeyError: pass else: connected = Model.find(Q('user_settings', 'eq', user_settings)) for node_settings in connected: node_settings.user_settings = self node_settings.save() self.save()
def _on_complete(self, user): DraftRegistration = apps.get_model('osf.DraftRegistration') draft = DraftRegistration.find_one( Q('approval', 'eq', self) ) auth = Auth(draft.initiator) registration = draft.register( auth=auth, save=True ) registration_choice = self.meta['registration_choice'] if registration_choice == 'immediate': sanction = functools.partial(registration.require_approval, draft.initiator) elif registration_choice == 'embargo': embargo_end_date = parse_date(self.meta.get('embargo_end_date')) if not embargo_end_date.tzinfo: embargo_end_date = embargo_end_date.replace(tzinfo=pytz.UTC) sanction = functools.partial( registration.embargo_registration, draft.initiator, embargo_end_date ) else: raise ValueError("'registration_choice' must be either 'embargo' or 'immediate'") sanction(notify_initiator_on_complete=True)
def _create(cls, *args, **kwargs): kwargs['node_license'] = kwargs.get( 'node_license', models.NodeLicense.find_one( Q('name', 'eq', 'No license') ) ) return super(NodeLicenseRecordFactory, cls)._create(*args, **kwargs)
def test_on_reject(self, mock_send_mail): user = factories.UserFactory() approval = DraftRegistrationApproval( meta={'registration_choice': 'immediate'}) approval.save() project = factories.ProjectFactory(creator=user) registration_schema = MetaSchema.find_one( Q('name', 'eq', 'Prereg Challenge') & Q('schema_version', 'eq', 2)) draft = factories.DraftRegistrationFactory( branched_from=project, registration_schema=registration_schema, ) draft.approval = approval draft.save() approval._on_reject(user) assert approval.meta == {} assert mock_send_mail.call_count == 1
def test_remove(self): session, session2 = Session(data={'auth_user_id': '123ab'}), Session(data={'auth_user_id': 'ab123'}) session.save() session2.save() assert Session.objects.count() == 2 # sanity check Session.remove(Q('data.auth_user_id', 'eq', '123ab')) assert Session.objects.count() == 1
def _on_reject(self, user, *args, **kwargs): DraftRegistration = apps.get_model('osf.DraftRegistration') # clear out previous registration options self.meta = {} self.save() draft = DraftRegistration.find_one(Q('approval', 'eq', self)) self._send_rejection_email(draft.initiator, draft)
def get_all_user_subscriptions(user, extra=None): """ Get all Subscription objects that the user is subscribed to""" NotificationSubscription = apps.get_model('osf.NotificationSubscription') for notification_type in constants.NOTIFICATION_TYPES: query = Q(notification_type, 'eq', user.pk) if extra: query &= extra queryset = NotificationSubscription.find(query) for subscription in queryset: yield subscription
def _set_external_account(self, user, info): try: # create a new ``ExternalAccount`` ... self.account = ExternalAccount( provider=self.short_name, provider_id=info['provider_id'], provider_name=self.name, ) self.account.save() except ValidationError: # ... or get the old one self.account = ExternalAccount.find_one( Q('provider', 'eq', self.short_name) & Q('provider_id', 'eq', info['provider_id']) ) assert self.account is not None # ensure that provider_name is correct self.account.provider_name = self.name # required self.account.oauth_key = info['key'] # only for OAuth1 self.account.oauth_secret = info.get('secret') # only for OAuth2 self.account.expires_at = info.get('expires_at') self.account.refresh_token = info.get('refresh_token') self.account.date_last_refreshed = timezone.now() # additional information self.account.display_name = info.get('display_name') self.account.profile_url = info.get('profile_url') self.account.save() # add it to the user's list of ``ExternalAccounts`` if not user.external_accounts.filter(id=self.account.id).exists(): user.external_accounts.add(self.account) user.save() return True
def remove_subscription_task(node_id): AbstractNode = apps.get_model('osf.AbstractNode') NotificationSubscription = apps.get_model('osf.NotificationSubscription') node = AbstractNode.load(node_id) NotificationSubscription.remove(Q('node', 'eq', node)) parent = node.parent_node if parent and parent.child_node_subscriptions: for user_id in parent.child_node_subscriptions: if node._id in parent.child_node_subscriptions[user_id]: parent.child_node_subscriptions[user_id].remove(node._id) parent.save()
def migrate(): targets = get_targets() total = len(targets) for i, user in enumerate(targets): logger.info('({}/{}) Preparing to migrate User {}'.format(i + 1, total, user._id)) bookmarks = Collection.find(Q('is_bookmark_collection', 'eq', True) & Q('creator', 'eq', user)) if sum([bool(n.nodes) for n in bookmarks]) > 1: logger.warn('Expected no users to have more than one bookmark with .nodes, {} violated. Selecting first one'.format(user._id)) bookmark_to_keep = None for n in bookmarks: if n.nodes: bookmark_to_keep = n break bookmark_to_keep = bookmark_to_keep or bookmarks[0] logger.info('Marking Collection {} as primary Bookmark Collection for User {}, preparing to delete others'.format(bookmark_to_keep._id, user._id)) for n in bookmarks: if n._id != bookmark_to_keep._id: n.is_deleted = True n.save() logger.info('Successfully migrated User {}'.format(user._id)) logger.info('Successfully migrated {} users'.format(total))
def _rejection_url_context(self, user_id): user_approval_state = self.approval_state.get(user_id, {}) rejection_token = user_approval_state.get('rejection_token') if rejection_token: Registration = apps.get_model('osf.Registration') root_registration = Registration.find_one(Q('retraction', 'eq', self)) node_id = user_approval_state.get('node_id', root_registration._id) registration = Registration.load(node_id) return { 'node_id': registration.registered_from._id, 'token': rejection_token, }
def _on_reject(self, user): Registration = apps.get_model('osf.Registration') NodeLog = apps.get_model('osf.NodeLog') parent_registration = Registration.find_one(Q('retraction', 'eq', self)) parent_registration.registered_from.add_log( action=NodeLog.RETRACTION_CANCELLED, params={ 'node': parent_registration.registered_from._id, 'registration': parent_registration._id, 'retraction_id': self._id, }, auth=Auth(user), save=True, )
def test_factory(self): draft = factories.DraftRegistrationFactory() assert draft.branched_from is not None assert draft.initiator is not None assert draft.registration_schema is not None user = factories.UserFactory() draft = factories.DraftRegistrationFactory(initiator=user) assert draft.initiator == user node = factories.ProjectFactory() draft = factories.DraftRegistrationFactory(branched_from=node) assert draft.branched_from == node assert draft.initiator == node.creator # Pick an arbitrary v2 schema schema = MetaSchema.find(Q('schema_version', 'eq', 2))[0] data = {'some': 'data'} draft = factories.DraftRegistrationFactory(registration_schema=schema, registration_metadata=data) assert draft.registration_schema == schema assert draft.registration_metadata == data
def find_child_by_name(self, name, kind=2): return self.resolve_class( self.provider, kind).find_one(Q('name', 'eq', name) & Q('parent', 'eq', self))
def files_checked_out(cls, user): """ :param user: The user with checked out files :return: A queryset of all FileNodes checked out by user """ return cls.find(Q('checkout', 'eq', user))
def test_querying_on_referent(self): user = UserFactory() guids = Guid.find(Q('referent', 'eq', user)) assert user._id in guids.values_list('_id', flat=True)
def test_is_embargoed(self): embargo = factories.EmbargoFactory() registration = Registration.find_one(Q('embargo', 'eq', embargo)) registration.embargo.state = Sanction.APPROVED registration.embargo.save() assert registration.is_embargoed