def node(self, user_admin_contrib, user_write_contrib, user_read_contrib): node = RegistrationFactory(creator=user_admin_contrib, is_public=False) node.add_contributor(user_write_contrib, auth=Auth(user_admin_contrib)) node.add_contributor( user_read_contrib, auth=Auth(user_admin_contrib), permissions=['read']) node.save() return node
def node(self, user, write_contrib, read_contrib): registration = RegistrationFactory(creator=user) registration.add_contributor( write_contrib, permissions=[ permissions.READ, permissions.WRITE]) registration.add_contributor(read_contrib, permissions=[permissions.READ]) registration.save() return registration
def project(self, admin_contributor_bib, write_contributor_non_bib, read_contributor_bib): project = ProjectFactory(creator=admin_contributor_bib) reg = RegistrationFactory( creator=admin_contributor_bib, project=project ) reg.add_contributor(write_contributor_non_bib, [READ, WRITE], visible=False) reg.add_contributor(read_contributor_bib, [READ]) reg.save() return reg
def test_can_create_linked_registration_relationship_to_private_registration_if_read_only(self): registration = RegistrationFactory() registration.add_contributor(self.admin_contributor, auth=Auth(registration.creator), permissions=['read']) registration.save() res = self.make_request( node_id=self.private_node._id, reg_id=registration._id, auth=self.admin_contributor.auth ) assert_equal(res.status_code, 201) linked_registrations = [r['id'] for r in res.json['data']] assert_in(registration._id, linked_registrations)
def private_registration( self, user, private_project, read_only_contributor, read_write_contributor): private_registration = RegistrationFactory( project=private_project, creator=user) private_registration.add_contributor( read_only_contributor, permissions=[ permissions.READ]) private_registration.add_contributor( read_write_contributor, permissions=[ permissions.WRITE]) private_registration.save() return private_registration
def test_can_create_linked_registration_relationship_to_private_registration_if_rw( self, make_request, user_admin_contrib, node_private): registration = RegistrationFactory() registration.add_contributor( user_admin_contrib, auth=Auth(registration.creator)) registration.save() res = make_request( node_id=node_private._id, reg_id=registration._id, auth=user_admin_contrib.auth ) assert res.status_code == 201 linked_registrations = [r['id'] for r in res.json['data']] assert registration._id in linked_registrations
def test_total_biographic_contributor_in_registration(self): user3 = AuthUserFactory() registration = RegistrationFactory(is_public=True, creator=self.user) registration.add_contributor(self.user_two, auth=Auth(self.user)) registration.add_contributor( user3, auth=Auth(self.user), visible=False) registration.save() registration_url = '/{0}registrations/{1}/?embed=contributors'.format( API_BASE, registration._id) res = self.app.get(registration_url) assert_true( res.json['data']['embeds']['contributors']['links']['meta']['total_bibliographic'] ) assert_equal( res.json['data']['embeds']['contributors']['links']['meta']['total_bibliographic'], 2)
def test_metadata_for_node_only_includes_visible_contribs(self, datacite_client): visible_contrib = AuthUserFactory() visible_contrib2 = AuthUserFactory() visible_contrib2.given_name = u'ヽ༼ ಠ益ಠ ༽ノ' visible_contrib2.family_name = u'ლ(´◉❥◉`ლ)' visible_contrib2.save() invisible_contrib = AuthUserFactory() invisible_contrib.given_name = 'Shady' invisible_contrib.family_name = 'McCoy' invisible_contrib.save() registration = RegistrationFactory(is_public=True) registration.add_contributor(visible_contrib, visible=True) registration.add_contributor(invisible_contrib, visible=False) registration.add_contributor(visible_contrib2, visible=True) registration.save() metadata_xml = datacite_client.build_metadata(registration) # includes visible contrib name assert u'<givenName>{}</givenName>'.format(visible_contrib.given_name) in metadata_xml assert u'<familyName>{}</familyName>'.format(visible_contrib.family_name) in metadata_xml # doesn't include invisible contrib name assert u'<givenName>{}</givenName>'.format(invisible_contrib.given_name) not in metadata_xml assert u'<familyName>{}</familyName>'.format(invisible_contrib.family_name) not in metadata_xml
class TestInstitutionRegistrationList(ApiTestCase): def setUp(self): super(TestInstitutionRegistrationList, self).setUp() self.institution = InstitutionFactory() self.registration1 = RegistrationFactory(is_public=True) self.registration1.affiliated_institutions.add(self.institution) self.registration1.save() self.user1 = AuthUserFactory() self.user2 = AuthUserFactory() self.registration2 = RegistrationFactory(creator=self.user1, is_public=False) self.registration2.affiliated_institutions.add(self.institution) self.registration2.add_contributor(self.user2, auth=Auth(self.user1)) self.registration2.save() self.registration3 = RegistrationFactory(creator=self.user2, is_public=False) self.registration3.affiliated_institutions.add(self.institution) self.registration3.save() self.institution_node_url = '/{0}institutions/{1}/registrations/'.format( API_BASE, self.institution._id) def test_return_all_public_nodes(self): res = self.app.get(self.institution_node_url) assert_equal(res.status_code, 200) ids = [each['id'] for each in res.json['data']] assert_in(self.registration1._id, ids) assert_not_in(self.registration2._id, ids) assert_not_in(self.registration3._id, ids) def test_does_not_return_private_nodes_with_auth(self): res = self.app.get(self.institution_node_url, auth=self.user1.auth) assert_equal(res.status_code, 200) ids = [each['id'] for each in res.json['data']] assert_in(self.registration1._id, ids) assert_not_in(self.registration2._id, ids) assert_not_in(self.registration3._id, ids) def test_doesnt_return_retractions_without_auth(self): self.registration2.is_public = True self.registration2.save() retraction = WithdrawnRegistrationFactory( registration=self.registration2, user=self.user1) assert_true(self.registration2.is_retracted) res = self.app.get(self.institution_node_url) assert_equal(res.status_code, 200) ids = [each['id'] for each in res.json['data']] assert_not_in(self.registration2._id, ids) def test_doesnt_return_retractions_with_auth(self): retraction = WithdrawnRegistrationFactory( registration=self.registration2, user=self.user1) assert_true(self.registration2.is_retracted) res = self.app.get(self.institution_node_url, auth=self.user1.auth) assert_equal(res.status_code, 200) ids = [each['id'] for each in res.json['data']] assert_not_in(self.registration2._id, ids) def test_total_biographic_contributor_in_institution_registration(self): user3 = AuthUserFactory() registration3 = RegistrationFactory(is_public=True, creator=self.user1) registration3.affiliated_institutions.add(self.institution) registration3.add_contributor(self.user2, auth=Auth(self.user1)) registration3.add_contributor(user3, auth=Auth(self.user1), visible=False) registration3.save() registration3_url = '/{0}registrations/{1}/?embed=contributors'.format( API_BASE, registration3._id) res = self.app.get(registration3_url) assert_true(res.json['data']['embeds']['contributors']['links']['meta'] ['total_bibliographic']) assert_equal( res.json['data']['embeds']['contributors']['links']['meta'] ['total_bibliographic'], 2)
def private_registration(self, user, private_project, read_only_contributor, read_write_contributor): private_registration = RegistrationFactory(project=private_project, creator=user) private_registration.add_contributor(read_only_contributor, permissions=[permissions.READ]) private_registration.add_contributor(read_write_contributor, permissions=[permissions.WRITE]) private_registration.save() return private_registration
class TestMetadataGeneration(OsfTestCase): def setUp(self): OsfTestCase.setUp(self) self.visible_contrib = AuthUserFactory() visible_contrib2 = AuthUserFactory(given_name=u'ヽ༼ ಠ益ಠ ༽ノ', family_name=u'ლ(´◉❥◉`ლ)') self.invisible_contrib = AuthUserFactory() self.node = RegistrationFactory(is_public=True) self.identifier = Identifier(referent=self.node, category='catid', value='cat:7') self.node.add_contributor(self.visible_contrib, visible=True) self.node.add_contributor(self.invisible_contrib, visible=False) self.node.add_contributor(visible_contrib2, visible=True) self.node.save() # This test is not used as datacite is currently used for nodes, leaving here for future reference def test_datacite_metadata_for_preprint_has_correct_structure(self): provider = PreprintProviderFactory() license = NodeLicense.objects.get(name='CC-By Attribution 4.0 International') license_details = { 'id': license.license_id, 'year': '2017', 'copyrightHolders': ['Jeff Hardy', 'Matt Hardy'] } preprint = PreprintFactory(provider=provider, project=self.node, is_published=True, license_details=license_details) metadata_xml = metadata.datacite_metadata_for_preprint(preprint, doi=preprint.get_identifier('doi').value, pretty_print=True) root = lxml.etree.fromstring(metadata_xml) xsi_location = '{http://www.w3.org/2001/XMLSchema-instance}schemaLocation' expected_location = 'http://datacite.org/schema/kernel-4 http://schema.datacite.org/meta/kernel-4/metadata.xsd' assert root.attrib[xsi_location] == expected_location identifier = root.find('{%s}identifier' % metadata.NAMESPACE) assert identifier.attrib['identifierType'] == 'DOI' assert identifier.text == preprint.get_identifier('doi').value creators = root.find('{%s}creators' % metadata.NAMESPACE) assert len(creators.getchildren()) == len(self.node.visible_contributors) subjects = root.find('{%s}subjects' % metadata.NAMESPACE) assert subjects.getchildren() publisher = root.find('{%s}publisher' % metadata.NAMESPACE) assert publisher.text == provider.name pub_year = root.find('{%s}publicationYear' % metadata.NAMESPACE) assert pub_year.text == str(preprint.date_published.year) dates = root.find('{%s}dates' % metadata.NAMESPACE).getchildren()[0] assert dates.text == preprint.modified.isoformat() assert dates.attrib['dateType'] == 'Updated' alternate_identifier = root.find('{%s}alternateIdentifiers' % metadata.NAMESPACE).getchildren()[0] assert alternate_identifier.text == settings.DOMAIN + preprint._id assert alternate_identifier.attrib['alternateIdentifierType'] == 'URL' descriptions = root.find('{%s}descriptions' % metadata.NAMESPACE).getchildren()[0] assert descriptions.text == preprint.node.description rights = root.find('{%s}rightsList' % metadata.NAMESPACE).getchildren()[0] assert rights.text == preprint.license.name # This test is not used as datacite is currently used for nodes, leaving here for future reference def test_datacite_format_creators_for_preprint(self): preprint = PreprintFactory(project=self.node, is_published=True) verified_user = AuthUserFactory(external_identity={'ORCID': {'1234-1234-1234-1234': 'VERIFIED'}}) linked_user = AuthUserFactory(external_identity={'ORCID': {'1234-nope-1234-nope': 'LINK'}}) self.node.add_contributor(verified_user, visible=True) self.node.add_contributor(linked_user, visible=True) self.node.save() formatted_creators = metadata.format_creators(preprint) contributors_with_orcids = 0 guid_identifiers = [] for creator_xml in formatted_creators: assert creator_xml.find('creatorName').text != u'{}, {}'.format(self.invisible_contrib.family_name, self.invisible_contrib.given_name) name_identifiers = creator_xml.findall('nameIdentifier') for name_identifier in name_identifiers: if name_identifier.attrib['nameIdentifierScheme'] == 'ORCID': assert name_identifier.attrib['schemeURI'] == 'http://orcid.org/' contributors_with_orcids += 1 else: guid_identifiers.append(name_identifier.text) assert name_identifier.attrib['nameIdentifierScheme'] == 'OSF' assert name_identifier.attrib['schemeURI'] == settings.DOMAIN assert contributors_with_orcids >= 1 assert len(formatted_creators) == len(self.node.visible_contributors) assert sorted(guid_identifiers) == sorted([contrib.absolute_url for contrib in self.node.visible_contributors]) # This test is not used as datacite is currently used for nodes, leaving here for future reference def test_datacite_format_subjects_for_preprint(self): subject = SubjectFactory() subject_1 = SubjectFactory(parent=subject) subject_2 = SubjectFactory(parent=subject) subjects = [[subject._id, subject_1._id], [subject._id, subject_2._id]] preprint = PreprintFactory(subjects=subjects, project=self.node, is_published=True) formatted_subjects = metadata.format_subjects(preprint) assert len(formatted_subjects) == Subject.objects.all().count()
class RegistrationRetractionViewsTestCase(OsfTestCase): def setUp(self): super(RegistrationRetractionViewsTestCase, self).setUp() self.user = AuthUserFactory() self.registered_from = ProjectFactory(creator=self.user, is_public=True) self.registration = RegistrationFactory(project=self.registered_from, is_public=True) self.retraction_post_url = self.registration.api_url_for( 'node_registration_retraction_post') self.retraction_get_url = self.registration.web_url_for( 'node_registration_retraction_get') self.justification = fake.sentence() def test_GET_retraction_page_when_pending_retraction_returns_HTTPError_BAD_REQUEST( self): self.registration.retract_registration(self.user) self.registration.save() res = self.app.get( self.retraction_get_url, auth=self.user.auth, expect_errors=True, ) assert_equal(res.status_code, http.BAD_REQUEST) def test_POST_retraction_to_private_registration_returns_HTTPError_FORBIDDEN( self): self.registration.is_public = False self.registration.save() res = self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, expect_errors=True, ) assert_equal(res.status_code, http.FORBIDDEN) self.registration.reload() assert_is_none(self.registration.retraction) @mock.patch('website.mails.send_mail') def test_POST_retraction_does_not_send_email_to_unregistered_admins( self, mock_send_mail): unreg = UnregUserFactory() self.registration.add_contributor( unreg, auth=Auth(self.user), permissions=['read', 'write', 'admin']) self.registration.save() self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) # Only the creator gets an email; the unreg user does not get emailed assert_equal(mock_send_mail.call_count, 1) def test_POST_pending_embargo_returns_HTTPError_HTTPOK(self): self.registration.embargo_registration( self.user, (timezone.now() + datetime.timedelta(days=10)), for_existing_registration=True) self.registration.save() assert_true(self.registration.is_pending_embargo) res = self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, expect_errors=True, ) assert_equal(res.status_code, http.OK) self.registration.reload() assert_true(self.registration.is_pending_retraction) def test_POST_active_embargo_returns_HTTPOK(self): self.registration.embargo_registration( self.user, (timezone.now() + datetime.timedelta(days=10)), for_existing_registration=True) self.registration.save() assert_true(self.registration.is_pending_embargo) approval_token = self.registration.embargo.approval_state[ self.user._id]['approval_token'] self.registration.embargo.approve(self.user, approval_token) assert_true(self.registration.embargo_end_date) res = self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, expect_errors=True, ) assert_equal(res.status_code, http.OK) self.registration.reload() assert_true(self.registration.is_pending_retraction) def test_POST_retraction_by_non_admin_retract_HTTPError_UNAUTHORIZED(self): res = self.app.post_json(self.retraction_post_url, expect_errors=True) assert_equals(res.status_code, http.UNAUTHORIZED) self.registration.reload() assert_is_none(self.registration.retraction) @mock.patch('website.mails.send_mail') def test_POST_retraction_without_justification_returns_HTTPOK( self, mock_send): res = self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) assert_equal(res.status_code, http.OK) self.registration.reload() assert_false(self.registration.is_retracted) assert_true(self.registration.is_pending_retraction) assert_is_none(self.registration.retraction.justification) @mock.patch('website.mails.send_mail') def test_valid_POST_retraction_adds_to_parent_projects_log( self, mock_send): initial_project_logs = self.registration.registered_from.logs.count() self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) self.registration.registered_from.reload() # Logs: Created, registered, retraction initiated assert_equal(self.registration.registered_from.logs.count(), initial_project_logs + 1) @mock.patch('website.mails.send_mail') def test_valid_POST_retraction_when_pending_retraction_raises_400( self, mock_send): self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) res = self.app.post_json(self.retraction_post_url, {'justification': ''}, auth=self.user.auth, expect_errors=True) assert_equal(res.status_code, 400) @mock.patch('website.mails.send_mail') def test_valid_POST_calls_send_mail_with_username(self, mock_send): self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) assert_true(mock_send.called) args, kwargs = mock_send.call_args assert_true(self.user.username in args) def test_non_contributor_GET_approval_returns_HTTPError_UNAUTHORIZED(self): non_contributor = AuthUserFactory() self.registration.retract_registration(self.user) approval_token = self.registration.retraction.approval_state[ self.user._id]['approval_token'] approval_url = self.registration.web_url_for('view_project', token=approval_token) res = self.app.get(approval_url, auth=non_contributor.auth, expect_errors=True) assert_equal(res.status_code, http.UNAUTHORIZED) assert_true(self.registration.is_pending_retraction) assert_false(self.registration.is_retracted) def test_non_contributor_GET_disapproval_returns_HTTPError_UNAUTHORIZED( self): non_contributor = AuthUserFactory() self.registration.retract_registration(self.user) rejection_token = self.registration.retraction.approval_state[ self.user._id]['rejection_token'] disapproval_url = self.registration.web_url_for('view_project', token=rejection_token) res = self.app.get(disapproval_url, auth=non_contributor.auth, expect_errors=True) assert_equal(res.status_code, http.UNAUTHORIZED) assert_true(self.registration.is_pending_retraction) assert_false(self.registration.is_retracted)
class TestInstitutionRegistrationList(ApiTestCase): def setUp(self): super(TestInstitutionRegistrationList, self).setUp() self.institution = InstitutionFactory() self.registration1 = RegistrationFactory(is_public=True) self.registration1.affiliated_institutions.add(self.institution) self.registration1.save() self.user1 = AuthUserFactory() self.user2 = AuthUserFactory() self.registration2 = RegistrationFactory( creator=self.user1, is_public=False) self.registration2.affiliated_institutions.add(self.institution) self.registration2.add_contributor(self.user2, auth=Auth(self.user1)) self.registration2.save() self.registration3 = RegistrationFactory( creator=self.user2, is_public=False) self.registration3.affiliated_institutions.add(self.institution) self.registration3.save() self.institution_node_url = '/{0}institutions/{1}/registrations/'.format( API_BASE, self.institution._id) def test_return_all_public_nodes(self): res = self.app.get(self.institution_node_url) assert_equal(res.status_code, 200) ids = [each['id'] for each in res.json['data']] assert_in(self.registration1._id, ids) assert_not_in(self.registration2._id, ids) assert_not_in(self.registration3._id, ids) def test_does_not_return_private_nodes_with_auth(self): res = self.app.get(self.institution_node_url, auth=self.user1.auth) assert_equal(res.status_code, 200) ids = [each['id'] for each in res.json['data']] assert_in(self.registration1._id, ids) assert_not_in(self.registration2._id, ids) assert_not_in(self.registration3._id, ids) def test_doesnt_return_retractions_without_auth(self): self.registration2.is_public = True self.registration2.save() retraction = WithdrawnRegistrationFactory( registration=self.registration2, user=self.user1) assert_true(self.registration2.is_retracted) res = self.app.get(self.institution_node_url) assert_equal(res.status_code, 200) ids = [each['id'] for each in res.json['data']] assert_not_in(self.registration2._id, ids) def test_doesnt_return_retractions_with_auth(self): retraction = WithdrawnRegistrationFactory( registration=self.registration2, user=self.user1) assert_true(self.registration2.is_retracted) res = self.app.get(self.institution_node_url, auth=self.user1.auth) assert_equal(res.status_code, 200) ids = [each['id'] for each in res.json['data']] assert_not_in(self.registration2._id, ids) @pytest.mark.enable_quickfiles_creation def test_total_biographic_contributor_in_institution_registration(self): user3 = AuthUserFactory() registration3 = RegistrationFactory(is_public=True, creator=self.user1) registration3.affiliated_institutions.add(self.institution) registration3.add_contributor(self.user2, auth=Auth(self.user1)) registration3.add_contributor( user3, auth=Auth(self.user1), visible=False) registration3.save() registration3_url = '/{0}registrations/{1}/?embed=contributors'.format( API_BASE, registration3._id) res = self.app.get(registration3_url) assert_true( res.json['data']['embeds']['contributors']['links']['meta']['total_bibliographic'] ) assert_equal( res.json['data']['embeds']['contributors']['links']['meta']['total_bibliographic'], 2 )
class RegistrationEmbargoViewsTestCase(OsfTestCase): def setUp(self): super(RegistrationEmbargoViewsTestCase, self).setUp() self.user = AuthUserFactory() self.project = ProjectFactory(creator=self.user) self.draft = DraftRegistrationFactory(branched_from=self.project) self.registration = RegistrationFactory(project=self.project, creator=self.user) current_month = timezone.now().strftime('%B') current_year = timezone.now().strftime('%Y') self.valid_make_public_payload = json.dumps({ u'embargoEndDate': u'Fri, 01, {month} {year} 00:00:00 GMT'.format( month=current_month, year=current_year ), u'registrationChoice': 'immediate', u'summary': unicode(fake.sentence()) }) valid_date = timezone.now() + datetime.timedelta(days=180) self.valid_embargo_payload = json.dumps({ u'embargoEndDate': unicode(valid_date.strftime('%a, %d, %B %Y %H:%M:%S')) + u' GMT', u'registrationChoice': 'embargo', u'summary': unicode(fake.sentence()) }) self.invalid_embargo_date_payload = json.dumps({ u'embargoEndDate': u"Thu, 01 {month} {year} 05:00:00 GMT".format( month=current_month, year=str(int(current_year) - 1) ), u'registrationChoice': 'embargo', u'summary': unicode(fake.sentence()) }) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_register_draft_without_embargo_creates_registration_approval(self, mock_enqueue): res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_make_public_payload, content_type='application/json', auth=self.user.auth ) assert_equal(res.status_code, 202) registration = Registration.find().order_by('-registered_date').first() assert_not_equal(registration.registration_approval, None) # Regression test for https://openscience.atlassian.net/browse/OSF-5039 @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_register_make_public_immediately_creates_private_pending_registration_for_public_project(self, mock_enqueue): self.project.is_public = True self.project.save() NodeFactory( # component creator=self.user, parent=self.project, title='Component', is_public=True ) subproject = ProjectFactory( creator=self.user, parent=self.project, title='Subproject', is_public=True ) NodeFactory( # subproject's component creator=self.user, parent=subproject, title='Subcomponent', is_public=True ) res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_make_public_payload, content_type='application/json', auth=self.user.auth ) self.project.reload() assert_equal(res.status_code, 202) assert_equal(res.json['urls']['registrations'], self.project.web_url_for('node_registrations')) # Last node directly registered from self.project registration = AbstractNode.objects.filter(registered_from=self.project).order_by('-registered_date')[0] assert_true(registration.is_registration) assert_false(registration.is_public) for node in registration.get_descendants_recursive(): assert_true(node.is_registration) assert_false(node.is_public) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_register_make_public_does_not_make_children_public(self, mock_enqueue): NodeFactory( # component creator=self.user, parent=self.project, title='Component' ) subproject = ProjectFactory( creator=self.user, parent=self.project, title='Subproject' ) NodeFactory( # subproject component creator=self.user, parent=subproject, title='Subcomponent' ) self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_make_public_payload, content_type='application/json', auth=self.user.auth ) self.project.reload() # Last node directly registered from self.project registration = self.project.registrations.order_by('-registered_date').first() assert_false(registration.is_public) for node in registration.get_descendants_recursive(): assert_true(node.is_registration) assert_false(node.is_public) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_register_embargo_is_not_public(self, mock_enqueue): res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_embargo_payload, content_type='application/json', auth=self.user.auth ) assert_equal(res.status_code, 202) registration = Registration.find().order_by('-registered_date').first() assert_false(registration.is_public) assert_true(registration.is_pending_embargo_for_existing_registration) assert_is_not_none(registration.embargo) # Regression test for https://openscience.atlassian.net/browse/OSF-5071 @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_register_embargo_does_not_make_project_or_children_public(self, mock_enqueue): self.project.is_public = True self.project.save() NodeFactory( # component creator=self.user, parent=self.project, title='Component', is_public=True ) subproject = ProjectFactory( creator=self.user, parent=self.project, title='Subproject', is_public=True ) NodeFactory( # subproject's component creator=self.user, parent=subproject, title='Subcomponent', is_public=True ) res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_embargo_payload, content_type='application/json', auth=self.user.auth ) self.project.reload() assert_equal(res.status_code, 202) assert_equal(res.json['urls']['registrations'], self.project.web_url_for('node_registrations')) # Last node directly registered from self.project registration = AbstractNode.objects.filter(registered_from=self.project).order_by('-registered_date')[0] assert_true(registration.is_registration) assert_false(registration.is_public) assert_true(registration.is_pending_embargo_for_existing_registration) assert_is_not_none(registration.embargo) for node in registration.get_descendants_recursive(): assert_true(node.is_registration) assert_false(node.is_public) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_invalid_embargo_end_date_returns_HTTPBad_Request(self, mock_enqueue): res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.invalid_embargo_date_payload, content_type='application/json', auth=self.user.auth, expect_errors=True ) assert_equal(res.status_code, 400) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_valid_POST_embargo_adds_to_parent_projects_log(self, mock_enquque): initial_project_logs = self.project.logs.count() self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_embargo_payload, content_type='application/json', auth=self.user.auth ) self.project.reload() # Logs: Created, registered, embargo initiated assert_equal(self.project.logs.count(), initial_project_logs + 1) @mock.patch('osf.models.sanctions.TokenApprovableSanction.ask') def test_embargoed_registration_set_privacy_requests_embargo_termination(self, mock_ask): # Initiate and approve embargo for i in range(3): c = AuthUserFactory() self.registration.add_contributor(c, [permissions.ADMIN], auth=Auth(self.user)) self.registration.save() self.registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) for user_id, embargo_tokens in self.registration.embargo.approval_state.iteritems(): approval_token = embargo_tokens['approval_token'] self.registration.embargo.approve_embargo(OSFUser.load(user_id), approval_token) self.registration.save() self.registration.set_privacy('public', Auth(self.registration.creator)) for reg in self.registration.node_and_primary_descendants(): reg.reload() assert_false(reg.is_public) assert_true(reg.embargo_termination_approval) assert_true(reg.embargo_termination_approval.is_pending_approval) def test_cannot_request_termination_on_component_of_embargo(self): node = ProjectFactory() ProjectFactory(parent=node, creator=node.creator) # child project with utils.mock_archive(node, embargo=True, autocomplete=True, autoapprove=True) as reg: with assert_raises(NodeStateError): reg._nodes.first().request_embargo_termination(Auth(node.creator)) @mock.patch('website.mails.send_mail') def test_embargoed_registration_set_privacy_sends_mail(self, mock_send_mail): """ Integration test for https://github.com/CenterForOpenScience/osf.io/pull/5294#issuecomment-212613668 """ # Initiate and approve embargo for i in range(3): c = AuthUserFactory() self.registration.add_contributor(c, [permissions.ADMIN], auth=Auth(self.user)) self.registration.save() self.registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) for user_id, embargo_tokens in self.registration.embargo.approval_state.iteritems(): approval_token = embargo_tokens['approval_token'] self.registration.embargo.approve_embargo(OSFUser.load(user_id), approval_token) self.registration.save() self.registration.set_privacy('public', Auth(self.registration.creator)) for admin in self.registration.admin_contributors: assert_true(any([each[0][0] == admin.username for each in mock_send_mail.call_args_list])) @mock.patch('osf.models.sanctions.TokenApprovableSanction.ask') def test_make_child_embargoed_registration_public_asks_all_admins_in_tree(self, mock_ask): # Initiate and approve embargo node = NodeFactory(creator=self.user) c1 = AuthUserFactory() child = NodeFactory(parent=node, creator=c1) c2 = AuthUserFactory() NodeFactory(parent=child, creator=c2) registration = RegistrationFactory(project=node) registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) for user_id, embargo_tokens in registration.embargo.approval_state.iteritems(): approval_token = embargo_tokens['approval_token'] registration.embargo.approve_embargo(OSFUser.load(user_id), approval_token) self.registration.save() registration.set_privacy('public', Auth(self.registration.creator)) asked_admins = [(admin._id, n._id) for admin, n in mock_ask.call_args[0][0]] for admin, node in registration.get_admin_contributors_recursive(): assert_in((admin._id, node._id), asked_admins) def test_non_contributor_GET_approval_returns_HTTPError(self): non_contributor = AuthUserFactory() self.registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) self.registration.save() assert_true(self.registration.is_pending_embargo) approval_token = self.registration.embargo.approval_state[self.user._id]['approval_token'] approval_url = self.registration.web_url_for('view_project', token=approval_token) res = self.app.get(approval_url, auth=non_contributor.auth, expect_errors=True) self.registration.reload() assert_equal(http.UNAUTHORIZED, res.status_code) assert_true(self.registration.is_pending_embargo) assert_equal(self.registration.embargo.state, Embargo.UNAPPROVED) def test_non_contributor_GET_disapproval_returns_HTTPError(self): non_contributor = AuthUserFactory() self.registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) self.registration.save() assert_true(self.registration.is_pending_embargo) rejection_token = self.registration.embargo.approval_state[self.user._id]['rejection_token'] approval_url = self.registration.web_url_for('view_project', token=rejection_token) res = self.app.get(approval_url, auth=non_contributor.auth, expect_errors=True) assert_equal(http.UNAUTHORIZED, res.status_code) assert_true(self.registration.is_pending_embargo) assert_equal(self.registration.embargo.state, Embargo.UNAPPROVED)
class TestMetadataGeneration(OsfTestCase): def setUp(self): OsfTestCase.setUp(self) self.visible_contrib = AuthUserFactory() visible_contrib2 = AuthUserFactory(given_name=u'ヽ༼ ಠ益ಠ ༽ノ', family_name=u'ლ(´◉❥◉`ლ)') self.invisible_contrib = AuthUserFactory() self.node = RegistrationFactory(is_public=True) self.identifier = Identifier(referent=self.node, category='catid', value='cat:7') self.node.add_contributor(self.visible_contrib, visible=True) self.node.add_contributor(self.invisible_contrib, visible=False) self.node.add_contributor(visible_contrib2, visible=True) self.node.save() # This test is not used as datacite is currently used for nodes, leaving here for future reference def test_datacite_metadata_for_preprint_has_correct_structure(self): provider = PreprintProviderFactory() license = NodeLicense.objects.get( name='CC-By Attribution 4.0 International') license_details = { 'id': license.license_id, 'year': '2017', 'copyrightHolders': ['Jeff Hardy', 'Matt Hardy'] } preprint = PreprintFactory(provider=provider, project=self.node, is_published=True, license_details=license_details) metadata_xml = metadata.datacite_metadata_for_preprint( preprint, doi=preprint.get_identifier('doi').value, pretty_print=True) root = lxml.etree.fromstring(metadata_xml) xsi_location = '{http://www.w3.org/2001/XMLSchema-instance}schemaLocation' expected_location = 'http://datacite.org/schema/kernel-4 http://schema.datacite.org/meta/kernel-4/metadata.xsd' assert root.attrib[xsi_location] == expected_location identifier = root.find('{%s}identifier' % metadata.NAMESPACE) assert identifier.attrib['identifierType'] == 'DOI' assert identifier.text == preprint.get_identifier('doi').value creators = root.find('{%s}creators' % metadata.NAMESPACE) assert len(creators.getchildren()) == len( self.node.visible_contributors) subjects = root.find('{%s}subjects' % metadata.NAMESPACE) assert subjects.getchildren() publisher = root.find('{%s}publisher' % metadata.NAMESPACE) assert publisher.text == provider.name pub_year = root.find('{%s}publicationYear' % metadata.NAMESPACE) assert pub_year.text == str(preprint.date_published.year) dates = root.find('{%s}dates' % metadata.NAMESPACE).getchildren()[0] assert dates.text == preprint.modified.isoformat() assert dates.attrib['dateType'] == 'Updated' alternate_identifier = root.find('{%s}alternateIdentifiers' % metadata.NAMESPACE).getchildren()[0] assert alternate_identifier.text == settings.DOMAIN + preprint._id assert alternate_identifier.attrib['alternateIdentifierType'] == 'URL' descriptions = root.find('{%s}descriptions' % metadata.NAMESPACE).getchildren()[0] assert descriptions.text == preprint.node.description rights = root.find('{%s}rightsList' % metadata.NAMESPACE).getchildren()[0] assert rights.text == preprint.license.name # This test is not used as datacite is currently used for nodes, leaving here for future reference def test_datacite_format_creators_for_preprint(self): preprint = PreprintFactory(project=self.node, is_published=True) verified_user = AuthUserFactory( external_identity={'ORCID': { '1234-1234-1234-1234': 'VERIFIED' }}) linked_user = AuthUserFactory( external_identity={'ORCID': { '1234-nope-1234-nope': 'LINK' }}) self.node.add_contributor(verified_user, visible=True) self.node.add_contributor(linked_user, visible=True) self.node.save() formatted_creators = metadata.format_creators(preprint) contributors_with_orcids = 0 guid_identifiers = [] for creator_xml in formatted_creators: assert creator_xml.find('creatorName').text != u'{}, {}'.format( self.invisible_contrib.family_name, self.invisible_contrib.given_name) name_identifiers = creator_xml.findall('nameIdentifier') for name_identifier in name_identifiers: if name_identifier.attrib['nameIdentifierScheme'] == 'ORCID': assert name_identifier.attrib[ 'schemeURI'] == 'http://orcid.org/' contributors_with_orcids += 1 else: guid_identifiers.append(name_identifier.text) assert name_identifier.attrib[ 'nameIdentifierScheme'] == 'OSF' assert name_identifier.attrib[ 'schemeURI'] == settings.DOMAIN assert contributors_with_orcids >= 1 assert len(formatted_creators) == len(self.node.visible_contributors) assert sorted(guid_identifiers) == sorted([ contrib.absolute_url for contrib in self.node.visible_contributors ]) # This test is not used as datacite is currently used for nodes, leaving here for future reference def test_datacite_format_subjects_for_preprint(self): subject = SubjectFactory() subject_1 = SubjectFactory(parent=subject) subject_2 = SubjectFactory(parent=subject) subjects = [[subject._id, subject_1._id], [subject._id, subject_2._id]] preprint = PreprintFactory(subjects=subjects, project=self.node, is_published=True) formatted_subjects = metadata.format_subjects(preprint) assert len(formatted_subjects) == Subject.objects.all().count()
def registration(self, admin, contrib): registration = RegistrationFactory(creator=admin) registration.add_contributor(admin, 'admin') registration.add_contributor(contrib, 'write') update_provider_auth_groups() return registration
class RegistrationEmbargoViewsTestCase(OsfTestCase): def setUp(self): super(RegistrationEmbargoViewsTestCase, self).setUp() self.user = AuthUserFactory() self.project = ProjectFactory(creator=self.user) self.draft = DraftRegistrationFactory(branched_from=self.project) self.registration = RegistrationFactory(project=self.project, creator=self.user) current_month = timezone.now().strftime('%B') current_year = timezone.now().strftime('%Y') self.valid_make_public_payload = json.dumps({ u'embargoEndDate': u'Fri, 01, {month} {year} 00:00:00 GMT'.format( month=current_month, year=current_year ), u'registrationChoice': 'immediate', u'summary': unicode(fake.sentence()) }) valid_date = timezone.now() + datetime.timedelta(days=180) self.valid_embargo_payload = json.dumps({ u'embargoEndDate': unicode(valid_date.strftime('%a, %d, %B %Y %H:%M:%S')) + u' GMT', u'registrationChoice': 'embargo', u'summary': unicode(fake.sentence()) }) self.invalid_embargo_date_payload = json.dumps({ u'embargoEndDate': u"Thu, 01 {month} {year} 05:00:00 GMT".format( month=current_month, year=str(int(current_year) - 1) ), u'registrationChoice': 'embargo', u'summary': unicode(fake.sentence()) }) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_register_draft_without_embargo_creates_registration_approval(self, mock_enqueue): res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_make_public_payload, content_type='application/json', auth=self.user.auth ) assert_equal(res.status_code, 202) registration = Registration.objects.all().order_by('-registered_date').first() assert_not_equal(registration.registration_approval, None) # Regression test for https://openscience.atlassian.net/browse/OSF-5039 @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_register_make_public_immediately_creates_private_pending_registration_for_public_project(self, mock_enqueue): self.project.is_public = True self.project.save() NodeFactory( # component creator=self.user, parent=self.project, title='Component', is_public=True ) subproject = ProjectFactory( creator=self.user, parent=self.project, title='Subproject', is_public=True ) NodeFactory( # subproject's component creator=self.user, parent=subproject, title='Subcomponent', is_public=True ) res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_make_public_payload, content_type='application/json', auth=self.user.auth ) self.project.reload() assert_equal(res.status_code, 202) assert_equal(res.json['urls']['registrations'], self.project.web_url_for('node_registrations')) # Last node directly registered from self.project registration = AbstractNode.objects.filter(registered_from=self.project).order_by('-registered_date')[0] assert_true(registration.is_registration) assert_false(registration.is_public) for node in registration.get_descendants_recursive(): assert_true(node.is_registration) assert_false(node.is_public) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_register_make_public_does_not_make_children_public(self, mock_enqueue): NodeFactory( # component creator=self.user, parent=self.project, title='Component' ) subproject = ProjectFactory( creator=self.user, parent=self.project, title='Subproject' ) NodeFactory( # subproject component creator=self.user, parent=subproject, title='Subcomponent' ) self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_make_public_payload, content_type='application/json', auth=self.user.auth ) self.project.reload() # Last node directly registered from self.project registration = self.project.registrations.order_by('-registered_date').first() assert_false(registration.is_public) for node in registration.get_descendants_recursive(): assert_true(node.is_registration) assert_false(node.is_public) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_register_embargo_is_not_public(self, mock_enqueue): res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_embargo_payload, content_type='application/json', auth=self.user.auth ) assert_equal(res.status_code, 202) registration = Registration.objects.order_by('-registered_date').first() assert_false(registration.is_public) assert_true(registration.is_pending_embargo_for_existing_registration) assert_is_not_none(registration.embargo) # Regression test for https://openscience.atlassian.net/browse/OSF-5071 @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_register_embargo_does_not_make_project_or_children_public(self, mock_enqueue): self.project.is_public = True self.project.save() NodeFactory( # component creator=self.user, parent=self.project, title='Component', is_public=True ) subproject = ProjectFactory( creator=self.user, parent=self.project, title='Subproject', is_public=True ) NodeFactory( # subproject's component creator=self.user, parent=subproject, title='Subcomponent', is_public=True ) res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_embargo_payload, content_type='application/json', auth=self.user.auth ) self.project.reload() assert_equal(res.status_code, 202) assert_equal(res.json['urls']['registrations'], self.project.web_url_for('node_registrations')) # Last node directly registered from self.project registration = AbstractNode.objects.filter(registered_from=self.project).order_by('-registered_date')[0] assert_true(registration.is_registration) assert_false(registration.is_public) assert_true(registration.is_pending_embargo_for_existing_registration) assert_is_not_none(registration.embargo) for node in registration.get_descendants_recursive(): assert_true(node.is_registration) assert_false(node.is_public) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_POST_invalid_embargo_end_date_returns_HTTPBad_Request(self, mock_enqueue): res = self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.invalid_embargo_date_payload, content_type='application/json', auth=self.user.auth, expect_errors=True ) assert_equal(res.status_code, 400) @mock.patch('framework.celery_tasks.handlers.enqueue_task') def test_valid_POST_embargo_adds_to_parent_projects_log(self, mock_enquque): initial_project_logs = self.project.logs.count() self.app.post( self.project.api_url_for('register_draft_registration', draft_id=self.draft._id), self.valid_embargo_payload, content_type='application/json', auth=self.user.auth ) self.project.reload() # Logs: Created, registered, embargo initiated assert_equal(self.project.logs.count(), initial_project_logs + 1) @mock.patch('osf.models.sanctions.TokenApprovableSanction.ask') def test_embargoed_registration_set_privacy_requests_embargo_termination(self, mock_ask): # Initiate and approve embargo for i in range(3): c = AuthUserFactory() self.registration.add_contributor(c, [permissions.ADMIN], auth=Auth(self.user)) self.registration.save() self.registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) for user_id, embargo_tokens in self.registration.embargo.approval_state.iteritems(): approval_token = embargo_tokens['approval_token'] self.registration.embargo.approve_embargo(OSFUser.load(user_id), approval_token) self.registration.save() self.registration.set_privacy('public', Auth(self.registration.creator)) for reg in self.registration.node_and_primary_descendants(): reg.reload() assert_false(reg.is_public) assert_true(reg.embargo_termination_approval) assert_true(reg.embargo_termination_approval.is_pending_approval) def test_cannot_request_termination_on_component_of_embargo(self): node = ProjectFactory() ProjectFactory(parent=node, creator=node.creator) # child project with utils.mock_archive(node, embargo=True, autocomplete=True, autoapprove=True) as reg: with assert_raises(NodeStateError): reg._nodes.first().request_embargo_termination(Auth(node.creator)) @mock.patch('website.mails.send_mail') def test_embargoed_registration_set_privacy_sends_mail(self, mock_send_mail): """ Integration test for https://github.com/CenterForOpenScience/osf.io/pull/5294#issuecomment-212613668 """ # Initiate and approve embargo for i in range(3): c = AuthUserFactory() self.registration.add_contributor(c, [permissions.ADMIN], auth=Auth(self.user)) self.registration.save() self.registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) for user_id, embargo_tokens in self.registration.embargo.approval_state.iteritems(): approval_token = embargo_tokens['approval_token'] self.registration.embargo.approve_embargo(OSFUser.load(user_id), approval_token) self.registration.save() self.registration.set_privacy('public', Auth(self.registration.creator)) for admin in self.registration.admin_contributors: assert_true(any([each[0][0] == admin.username for each in mock_send_mail.call_args_list])) @mock.patch('osf.models.sanctions.TokenApprovableSanction.ask') def test_make_child_embargoed_registration_public_asks_all_admins_in_tree(self, mock_ask): # Initiate and approve embargo node = NodeFactory(creator=self.user) c1 = AuthUserFactory() child = NodeFactory(parent=node, creator=c1) c2 = AuthUserFactory() NodeFactory(parent=child, creator=c2) registration = RegistrationFactory(project=node) registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) for user_id, embargo_tokens in registration.embargo.approval_state.iteritems(): approval_token = embargo_tokens['approval_token'] registration.embargo.approve_embargo(OSFUser.load(user_id), approval_token) self.registration.save() registration.set_privacy('public', Auth(self.registration.creator)) asked_admins = [(admin._id, n._id) for admin, n in mock_ask.call_args[0][0]] for admin, node in registration.get_admin_contributors_recursive(): assert_in((admin._id, node._id), asked_admins) def test_non_contributor_GET_approval_returns_HTTPError(self): non_contributor = AuthUserFactory() self.registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) self.registration.save() assert_true(self.registration.is_pending_embargo) approval_token = self.registration.embargo.approval_state[self.user._id]['approval_token'] approval_url = self.registration.web_url_for('view_project', token=approval_token) res = self.app.get(approval_url, auth=non_contributor.auth, expect_errors=True) self.registration.reload() assert_equal(http.UNAUTHORIZED, res.status_code) assert_true(self.registration.is_pending_embargo) assert_equal(self.registration.embargo.state, Embargo.UNAPPROVED) def test_non_contributor_GET_disapproval_returns_HTTPError(self): non_contributor = AuthUserFactory() self.registration.embargo_registration( self.user, timezone.now() + datetime.timedelta(days=10) ) self.registration.save() assert_true(self.registration.is_pending_embargo) rejection_token = self.registration.embargo.approval_state[self.user._id]['rejection_token'] approval_url = self.registration.web_url_for('view_project', token=rejection_token) res = self.app.get(approval_url, auth=non_contributor.auth, expect_errors=True) assert_equal(http.UNAUTHORIZED, res.status_code) assert_true(self.registration.is_pending_embargo) assert_equal(self.registration.embargo.state, Embargo.UNAPPROVED)
class RegistrationRetractionViewsTestCase(OsfTestCase): def setUp(self): super(RegistrationRetractionViewsTestCase, self).setUp() self.mock_registration_update = mock.patch('website.project.tasks.on_registration_updated') self.mock_registration_update.start() self.user = AuthUserFactory() self.registered_from = ProjectFactory(creator=self.user, is_public=True) self.registration = RegistrationFactory(project=self.registered_from, is_public=True) self.retraction_post_url = self.registration.api_url_for('node_registration_retraction_post') self.retraction_get_url = self.registration.web_url_for('node_registration_retraction_get') self.justification = fake.sentence() def tearDown(self): self.mock_registration_update.stop() super(RegistrationRetractionViewsTestCase, self).tearDown() def test_GET_retraction_page_when_pending_retraction_returns_HTTPError_BAD_REQUEST(self): self.registration.retract_registration(self.user) self.registration.save() res = self.app.get( self.retraction_get_url, auth=self.user.auth, expect_errors=True, ) assert_equal(res.status_code, http.BAD_REQUEST) def test_POST_retraction_to_private_registration_returns_HTTPError_FORBIDDEN(self): self.registration.is_public = False self.registration.save() res = self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, expect_errors=True, ) assert_equal(res.status_code, http.FORBIDDEN) self.registration.reload() assert_is_none(self.registration.retraction) @mock.patch('website.mails.send_mail') def test_POST_retraction_does_not_send_email_to_unregistered_admins(self, mock_send_mail): unreg = UnregUserFactory() self.registration.add_contributor( unreg, auth=Auth(self.user), permissions=['read', 'write', 'admin'] ) self.registration.save() self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) # Only the creator gets an email; the unreg user does not get emailed assert_equal(mock_send_mail.call_count, 1) def test_POST_pending_embargo_returns_HTTPError_HTTPOK(self): self.registration.embargo_registration( self.user, (timezone.now() + datetime.timedelta(days=10)), for_existing_registration=True ) self.registration.save() assert_true(self.registration.is_pending_embargo) res = self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, expect_errors=True, ) assert_equal(res.status_code, http.OK) self.registration.reload() assert_true(self.registration.is_pending_retraction) def test_POST_active_embargo_returns_HTTPOK(self): self.registration.embargo_registration( self.user, (timezone.now() + datetime.timedelta(days=10)), for_existing_registration=True ) self.registration.save() assert_true(self.registration.is_pending_embargo) approval_token = self.registration.embargo.approval_state[self.user._id]['approval_token'] self.registration.embargo.approve(self.user, approval_token) assert_true(self.registration.embargo_end_date) res = self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, expect_errors=True, ) assert_equal(res.status_code, http.OK) self.registration.reload() assert_true(self.registration.is_pending_retraction) def test_POST_retraction_by_non_admin_retract_HTTPError_UNAUTHORIZED(self): res = self.app.post_json(self.retraction_post_url, expect_errors=True) assert_equals(res.status_code, http.UNAUTHORIZED) self.registration.reload() assert_is_none(self.registration.retraction) @mock.patch('website.mails.send_mail') def test_POST_retraction_without_justification_returns_HTTPOK(self, mock_send): res = self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) assert_equal(res.status_code, http.OK) self.registration.reload() assert_false(self.registration.is_retracted) assert_true(self.registration.is_pending_retraction) assert_is_none(self.registration.retraction.justification) @mock.patch('website.mails.send_mail') def test_valid_POST_retraction_adds_to_parent_projects_log(self, mock_send): initial_project_logs = self.registration.registered_from.logs.count() self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) self.registration.registered_from.reload() # Logs: Created, registered, retraction initiated assert_equal(self.registration.registered_from.logs.count(), initial_project_logs + 1) @mock.patch('website.mails.send_mail') def test_valid_POST_retraction_when_pending_retraction_raises_400(self, mock_send): self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) res = self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, expect_errors=True ) assert_equal(res.status_code, 400) @mock.patch('website.mails.send_mail') def test_valid_POST_calls_send_mail_with_username(self, mock_send): self.app.post_json( self.retraction_post_url, {'justification': ''}, auth=self.user.auth, ) assert_true(mock_send.called) args, kwargs = mock_send.call_args assert_true(self.user.username in args) def test_non_contributor_GET_approval_returns_HTTPError_UNAUTHORIZED(self): non_contributor = AuthUserFactory() self.registration.retract_registration(self.user) approval_token = self.registration.retraction.approval_state[self.user._id]['approval_token'] approval_url = self.registration.web_url_for('view_project', token=approval_token) res = self.app.get(approval_url, auth=non_contributor.auth, expect_errors=True) assert_equal(res.status_code, http.UNAUTHORIZED) assert_true(self.registration.is_pending_retraction) assert_false(self.registration.is_retracted) def test_non_contributor_GET_disapproval_returns_HTTPError_UNAUTHORIZED(self): non_contributor = AuthUserFactory() self.registration.retract_registration(self.user) rejection_token = self.registration.retraction.approval_state[self.user._id]['rejection_token'] disapproval_url = self.registration.web_url_for('view_project', token=rejection_token) res = self.app.get(disapproval_url, auth=non_contributor.auth, expect_errors=True) assert_equal(res.status_code, http.UNAUTHORIZED) assert_true(self.registration.is_pending_retraction) assert_false(self.registration.is_retracted)
class TestMetadataGeneration(OsfTestCase): def setUp(self): OsfTestCase.setUp(self) self.visible_contrib = AuthUserFactory() visible_contrib2 = AuthUserFactory(given_name=u'ヽ༼ ಠ益ಠ ༽ノ', family_name=u'ლ(´◉❥◉`ლ)') self.invisible_contrib = AuthUserFactory() self.node = RegistrationFactory(is_public=True) self.identifier = Identifier(referent=self.node, category='catid', value='cat:7') self.node.add_contributor(self.visible_contrib, visible=True) self.node.add_contributor(self.invisible_contrib, visible=False) self.node.add_contributor(visible_contrib2, visible=True) self.node.save() def test_metadata_for_node_only_includes_visible_contribs(self): metadata_xml = metadata.datacite_metadata_for_node(self.node, doi=self.identifier.value) # includes visible contrib name assert_in(u'{}, {}'.format( self.visible_contrib.family_name, self.visible_contrib.given_name), metadata_xml) # doesn't include invisible contrib name assert_not_in(self.invisible_contrib.family_name, metadata_xml) assert_in(self.identifier.value, metadata_xml) def test_metadata_for_node_has_correct_structure(self): metadata_xml = metadata.datacite_metadata_for_node(self.node, doi=self.identifier.value) root = lxml.etree.fromstring(metadata_xml) xsi_location = '{http://www.w3.org/2001/XMLSchema-instance}schemaLocation' expected_location = 'http://datacite.org/schema/kernel-4 http://schema.datacite.org/meta/kernel-4/metadata.xsd' assert_equal(root.attrib[xsi_location], expected_location) identifier = root.find('{%s}identifier' % metadata.NAMESPACE) assert_equal(identifier.attrib['identifierType'], 'DOI') assert_equal(identifier.text, self.identifier.value) creators = root.find('{%s}creators' % metadata.NAMESPACE) assert_equal(len(creators.getchildren()), len(self.node.visible_contributors)) publisher = root.find('{%s}publisher' % metadata.NAMESPACE) assert_equal(publisher.text, 'Open Science Framework') pub_year = root.find('{%s}publicationYear' % metadata.NAMESPACE) assert_equal(pub_year.text, str(self.node.registered_date.year)) def test_metadata_for_preprint_has_correct_structure(self): provider = PreprintProviderFactory() license = NodeLicense.objects.get(name="CC-By Attribution 4.0 International") license_details = { 'id': license.license_id, 'year': '2017', 'copyrightHolders': ['Jeff Hardy', 'Matt Hardy'] } preprint = PreprintFactory(provider=provider, project=self.node, is_published=True, license_details=license_details) metadata_xml = metadata.datacite_metadata_for_preprint(preprint, doi=preprint.get_identifier('doi').value, pretty_print=True) root = lxml.etree.fromstring(metadata_xml) xsi_location = '{http://www.w3.org/2001/XMLSchema-instance}schemaLocation' expected_location = 'http://datacite.org/schema/kernel-4 http://schema.datacite.org/meta/kernel-4/metadata.xsd' assert root.attrib[xsi_location] == expected_location identifier = root.find('{%s}identifier' % metadata.NAMESPACE) assert identifier.attrib['identifierType'] == 'DOI' assert identifier.text == preprint.get_identifier('doi').value creators = root.find('{%s}creators' % metadata.NAMESPACE) assert len(creators.getchildren()) == len(self.node.visible_contributors) subjects = root.find('{%s}subjects' % metadata.NAMESPACE) assert subjects.getchildren() publisher = root.find('{%s}publisher' % metadata.NAMESPACE) assert publisher.text == provider.name pub_year = root.find('{%s}publicationYear' % metadata.NAMESPACE) assert pub_year.text == str(preprint.date_published.year) dates = root.find('{%s}dates' % metadata.NAMESPACE).getchildren()[0] assert dates.text == preprint.date_modified.isoformat() assert dates.attrib['dateType'] == 'Updated' alternate_identifier = root.find('{%s}alternateIdentifiers' % metadata.NAMESPACE).getchildren()[0] assert alternate_identifier.text == settings.DOMAIN + preprint._id assert alternate_identifier.attrib['alternateIdentifierType'] == 'URL' descriptions = root.find('{%s}descriptions' % metadata.NAMESPACE).getchildren()[0] assert descriptions.text == preprint.node.description rights = root.find('{%s}rightsList' % metadata.NAMESPACE).getchildren()[0] assert rights.text == preprint.license.name def test_format_creators_for_preprint(self): preprint = PreprintFactory(project=self.node, is_published=True) verified_user = AuthUserFactory(external_identity={'ORCID': {'1234-1234-1234-1234': 'VERIFIED'}}) linked_user = AuthUserFactory(external_identity={'ORCID': {'1234-nope-1234-nope': 'LINK'}}) self.node.add_contributor(verified_user, visible=True) self.node.add_contributor(linked_user, visible=True) self.node.save() formatted_creators = metadata.format_creators(preprint) contributors_with_orcids = 0 for creator_xml in formatted_creators: assert creator_xml.find('creatorName').text != u'{}, {}'.format(self.invisible_contrib.family_name, self.invisible_contrib.given_name) if creator_xml.find('nameIdentifier') is not None: assert creator_xml.find('nameIdentifier').attrib['nameIdentifierScheme'] == 'ORCID' assert creator_xml.find('nameIdentifier').attrib['schemeURI'] == 'http://orcid.org/' contributors_with_orcids += 1 assert contributors_with_orcids >= 1 assert len(formatted_creators) == len(self.node.visible_contributors) def test_format_subjects_for_preprint(self): subject = SubjectFactory() subject_1 = SubjectFactory(parent=subject) subject_2 = SubjectFactory(parent=subject) subjects = [[subject._id, subject_1._id], [subject._id, subject_2._id]] preprint = PreprintFactory(subjects=subjects, project=self.node, is_published=True) formatted_subjects = metadata.format_subjects(preprint) assert len(formatted_subjects) == Subject.objects.all().count()
class TestRegistrationUpdate(ApiTestCase): def setUp(self): self.maxDiff = None super(TestRegistrationUpdate, self).setUp() self.user = AuthUserFactory() self.user_two = AuthUserFactory() self.user_three = AuthUserFactory() self.registration_approval = RegistrationApprovalFactory(state='unapproved', approve=False, user=self.user) self.unapproved_registration = Registration.find_one(Q('registration_approval', 'eq', self.registration_approval)) self.unapproved_url = '/{}registrations/{}/'.format(API_BASE, self.unapproved_registration._id) self.public_project = ProjectFactory(title="Project One", is_public=True, creator=self.user) self.private_project = ProjectFactory(title="Project Two", is_public=False, creator=self.user) self.public_registration = RegistrationFactory(project=self.public_project, creator=self.user, is_public=True) self.private_registration = RegistrationFactory(project=self.private_project, creator=self.user) self.public_url = '/{}registrations/{}/'.format(API_BASE, self.public_registration._id) self.private_url = '/{}registrations/{}/'.format(API_BASE, self.private_registration._id) self.private_registration.add_contributor(self.user_two, permissions=[permissions.READ]) self.private_registration.add_contributor(self.user_three, permissions=[permissions.WRITE]) self.private_registration.save() self.payload = { "data": { "id": self.private_registration._id, "type": "registrations", "attributes": { "public": True, } } } def make_payload(self, registration_id, attributes): return { "data": { "id": registration_id, "type": "registrations", "attributes": attributes } } def test_update_private_registration_logged_out(self): res = self.app.put_json_api(self.private_url, self.payload, expect_errors=True) assert_equal(res.status_code, 401) def test_update_private_registration_logged_in_admin(self): res = self.app.put_json_api(self.private_url, self.payload, auth=self.user.auth) assert_equal(res.status_code, 200) assert_equal(res.json['data']['attributes']['public'], True) def test_update_private_registration_logged_in_read_only_contributor(self): res = self.app.put_json_api(self.private_url, self.payload, auth=self.user_two.auth, expect_errors=True) assert_equal(res.status_code, 403) def test_update_private_registration_logged_in_read_write_contributor(self): res = self.app.put_json_api(self.private_url, self.payload, auth=self.user_three.auth, expect_errors=True) assert_equal(res.status_code, 403) def test_update_public_registration_to_private(self): payload = { "data": { "id": self.public_registration._id, "type": "registrations", "attributes": { "public": False, } } } res = self.app.put_json_api(self.public_url, payload, auth=self.user.auth, expect_errors=True) assert_equal(res.status_code, 400) assert_equal(res.json['errors'][0]['detail'], 'Registrations can only be turned from private to public.') def test_public_field_has_invalid_value(self): payload = { "data": { "id": self.public_registration._id, "type": "registrations", "attributes": { "public": "Yes" } } } res = self.app.put_json_api(self.public_url, payload, auth=self.user.auth, expect_errors=True) assert_equal(res.status_code, 400) assert_equal(res.json['errors'][0]['detail'], '"Yes" is not a valid boolean.') def test_fields_other_than_public_are_ignored(self): payload = { "data": { "id": self.private_registration._id, "type": "registrations", "attributes": { "public": True, "category": "instrumentation", "title": "New title", "description": "New description" } } } res = self.app.put_json_api(self.private_url, payload, auth=self.user.auth) assert_equal(res.status_code, 200) assert_equal(res.json['data']['attributes']['public'], True) assert_equal(res.json['data']['attributes']['category'], 'project') assert_equal(res.json['data']['attributes']['description'], self.private_registration.description) assert_equal(res.json['data']['attributes']['title'], self.private_registration.title) def test_type_field_must_match(self): payload = { "data": { "id": self.private_registration._id, "type": "nodes", "attributes": { "public": True, "category": "instrumentation", "title": "New title", "description": "New description" } } } res = self.app.put_json_api(self.private_url, payload, auth=self.user.auth, expect_errors=True) assert_equal(res.status_code, 409) def test_id_field_must_match(self): payload = { "data": { "id": '12345', "type": "registrations", "attributes": { "public": True, "category": "instrumentation", "title": "New title", "description": "New description" } } } res = self.app.put_json_api(self.private_url, payload, auth=self.user.auth, expect_errors=True) assert_equal(res.status_code, 409) def test_turning_private_registrations_public(self): node2 = ProjectFactory(creator=self.user, is_public=False) node1 = RegistrationFactory(project=node2, creator=self.user, is_public=False) payload = { "data": { "id": node1._id, "type": "registrations", "attributes": { "public": True, } } } url = '/{}registrations/{}/'.format(API_BASE, node1._id) res = self.app.put_json_api(url, payload, auth=self.user.auth) assert_equal(res.json['data']['attributes']['public'], True) node1.reload() assert_true(node1.is_public) def test_registration_fields_are_read_only(self): writeable_fields = ['type', 'public', 'draft_registration', 'registration_choice', 'lift_embargo' ] for field in RegistrationSerializer._declared_fields: reg_field = RegistrationSerializer._declared_fields[field] if field not in writeable_fields: assert_equal(getattr(reg_field, 'read_only', False), True) def test_registration_detail_fields_are_read_only(self): writeable_fields = ['type', 'public', 'draft_registration', 'registration_choice', 'lift_embargo' ] for field in RegistrationDetailSerializer._declared_fields: reg_field = RegistrationSerializer._declared_fields[field] if field not in writeable_fields: assert_equal(getattr(reg_field, 'read_only', False), True) def test_user_cannot_delete_registration(self): res = self.app.delete_json_api(self.private_url, expect_errors=True, auth=self.user.auth) assert_equal(res.status_code, 405) def test_make_public_unapproved_registration_raises_error(self): payload = self.make_payload( self.unapproved_registration._id, { "public": True, "withdrawn": True } ) res = self.app.put_json_api(self.unapproved_url, payload, auth=self.user.auth, expect_errors=True) assert_equal(res.status_code, 400) assert_equal(res.json['errors'][0]['detail'], 'An unapproved registration cannot be made public.')