def test_deposit_create_permission(app, test_users, login_user, test_communities): """Test record draft creation.""" headers = [('Content-Type', 'application/json'), ('Accept', 'application/json')] with app.app_context(): community_name = 'MyTestCommunity1' record_data = generate_record_data(community=community_name) community_id = test_communities[community_name] community = Community.get(community_id) creator = create_user('creator') need = create_deposit_need_factory(str(community_id)) allowed = create_user('allowed', permissions=[need]) com_member = create_user('com_member', roles=[community.member_role]) com_admin = create_user('com_admin', roles=[community.admin_role]) deposit, pid, record = create_record(record_data, creator) def restrict_creation(restricted): community.update({'restricted_submission':restricted}) db.session.commit() def test_creation(expected_code, user=None, version_of=None): with app.test_client() as client: if user is not None: login_user(user, client) draft_create_res = client.post( url_for('b2share_records_rest.b2rec_list', version_of=version_of), data=json.dumps(record_data), headers=headers ) assert draft_create_res.status_code == expected_code # test creating a deposit with anonymous user restrict_creation(False) test_creation(401) restrict_creation(True) test_creation(401) # test creating a deposit with a logged in user restrict_creation(False) test_creation(201, creator) restrict_creation(True) test_creation(403, creator) # test with a use who is allowed test_creation(201, allowed) # test with a community member and admin test_creation(201, com_member) test_creation(201, com_admin) # test creating a new version test_creation(401, None, version_of=pid.pid_value) test_creation(403, com_member, version_of=pid.pid_value) restrict_creation(True) test_creation(403, creator, version_of=pid.pid_value) restrict_creation(False) test_creation(201, creator, version_of=pid.pid_value)
def test_modify_metadata_published_record_permissions(app, test_communities, login_user, test_users): """Test record's metadata modification with REST API.""" admin = test_users['admin'] with app.app_context(): creator = create_user('creator') non_creator = create_user('non-creator') record_data = generate_record_data(open_access=True) community = Community.get(id=record_data['community']) com_admin = create_user('com_admin', roles=[community.admin_role]) com_member = create_user('com_member', roles=[community.member_role]) def test_modify(status, user=None): patch = [{ "op": "replace", "path": "/titles", "value": [{'title':'newtitle'}] }] with app.test_client() as client: _, record_pid, record = create_record(record_data, creator) if user is not None: login_user(user, client) # test patching the document headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] request_res = client.patch( url_for('b2share_records_rest.b2rec_item', pid_value=record_pid.pid_value), data=json.dumps(patch), headers=headers) assert request_res.status_code == status # _, record_pid, record = create_record(record_data, creator) # test putting the document # data = dict(record) # apply_patch(data, patch) # headers = [('Content-Type', 'application/json'), # ('Accept', 'application/json')] # request_res = client.put( # url_for('b2share_records_rest.b2rec_item', # pid_value=record_pid.pid_value), # data=json.dumps(data), # headers=headers) # assert request_res.status_code == status # test with anonymous user test_modify(401) test_modify(403, non_creator) test_modify(200, creator) test_modify(403, com_member) test_modify(200, com_admin) test_modify(200, admin)
def test_deposit_files(app, test_communities, login_user, test_users): """Test uploading and reading deposit files.""" with app.app_context(): admin = test_users['admin'] creator = create_user('creator') uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2', 'replaced.dat': b'old_content', } test_record_data = generate_record_data() # test with anonymous user deposit = create_deposit(test_record_data, creator, uploaded_files) uploaded_file_name = 'additional.dat' uploaded_file_content = b'additional content' # Test file upload headers = [('Accept', '*/*')] with app.test_client() as client: login_user(creator, client) # try uploading a new file file_url = url_for_file(deposit.files.bucket.id, uploaded_file_name) file_put_res = client.put( file_url, input_stream=BytesIO(uploaded_file_content), headers=headers ) uploaded_files[uploaded_file_name] = uploaded_file_content # try replacing an existing file file_url = url_for_file(deposit.files.bucket.id, 'replaced.dat') file_put_res = client.put( file_url, input_stream=BytesIO(b'new_content'), headers=headers ) uploaded_files['replaced.dat'] = b'new_content' # try removing a file file_url2 = url_for_file(deposit.files.bucket.id, 'myfile2.dat') file_put_res = client.delete( file_url2, input_stream=BytesIO(uploaded_file_content), headers=headers ) del uploaded_files['myfile2.dat'] # check that the files can be retrieved properly subtest_file_bucket_content(client, deposit.files.bucket, uploaded_files)
def test_record_content(app, test_communities, login_user, test_users): """Test record read with REST API.""" uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2' } admin = test_users['admin'] with app.app_context(): creator = create_user('creator') non_creator = create_user('non-creator') record_data = generate_record_data() _, record_pid, record = create_record( record_data, creator, files=uploaded_files ) with app.test_client() as client: login_user(creator, client) headers = [('Accept', 'application/json')] request_res = client.get( url_for('b2share_records_rest.b2rec_item', pid_value=record_pid.pid_value), headers=headers) assert request_res.status_code == 200 request_data = json.loads( request_res.get_data(as_text=True)) assert 'created' in request_data expected_metadata = build_expected_metadata( record_data, PublicationStates.published.name, owners=[creator.id], PID=request_data['metadata'].get('ePIC_PID'), DOI=request_data['metadata'].get('DOI'), ) assert request_data['metadata'] == expected_metadata # check that the link to the bucket is correctly generated expected_bucket_link = url_for_bucket(record.files.bucket) assert request_data['links']['files'] == expected_bucket_link # test self link subtest_self_link(request_data, request_res.headers, client)
def test_deposit_modify_published_permissions(app, login_user, test_communities, test_users): """Test deposit edition after its publication. FIXME: This test should evolve when we allow deposit edition. """ with app.app_context(): community_name = 'MyTestCommunity1' record_data = generate_record_data(community=community_name) admin = test_users['admin'] creator = create_user('creator') non_creator = create_user('non-creator') community = Community.get(name=community_name) com_member = create_user('com_member', roles=[community.member_role]) com_admin = create_user('com_admin', roles=[community.admin_role]) deposit = create_deposit(record_data, creator) deposit.submit() deposit.publish() def test_edit(status, user=None): headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] with app.test_client() as client: if user is not None: login_user(user, client) request_res = client.patch(url_for( 'b2share_deposit_rest.b2dep_item', pid_value=deposit.pid.pid_value), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.draft.name }]), headers=headers) assert request_res.status_code == status # test with anonymous user test_edit(401) test_edit(403, non_creator) test_edit(403, creator) test_edit(403, admin) test_edit(403, com_member) test_edit(403, com_admin)
def test_deposit_create_permission(app, test_users, login_user, test_communities): """Test record draft creation.""" headers = [('Content-Type', 'application/json'), ('Accept', 'application/json')] with app.app_context(): community_name = 'MyTestCommunity1' record_data = generate_record_data(community=community_name) community_id = test_communities[community_name] community = Community.get(community_id) creator = create_user('creator') need = create_deposit_need_factory(str(community_id)) allowed = create_user('allowed', permissions=[need]) com_member = create_user('com_member', roles=[community.member_role]) com_admin = create_user('com_admin', roles=[community.admin_role]) def restrict_creation(restricted): community.update({'restricted_submission':restricted}) db.session.commit() def test_creation(expected_code, user=None): with app.test_client() as client: if user is not None: login_user(user, client) draft_create_res = client.post( url_for('b2share_records_rest.b2rec_list'), data=json.dumps(record_data), headers=headers ) assert draft_create_res.status_code == expected_code # test creating a deposit with anonymous user restrict_creation(False) test_creation(401) restrict_creation(True) test_creation(401) # test creating a deposit with a logged in user restrict_creation(False) test_creation(201, creator) restrict_creation(True) test_creation(403, creator) # test with a use who is allowed test_creation(201, allowed) # test with a community member and admin test_creation(201, com_member) test_creation(201, com_admin)
def test_modify_metadata_published_record_permissions(app, test_communities, login_user, test_users): """Test record's metadata modification with REST API.""" admin = test_users['admin'] with app.app_context(): creator = create_user('creator') non_creator = create_user('non-creator') record_data = generate_record_data(open_access=True) def test_modify(status, user=None): patch = [{ "op": "replace", "path": "/titles", "value": [{'title':'newtitle'}] }] with app.test_client() as client: _, record_pid, record = create_record(record_data, creator) if user is not None: login_user(user, client) # test patching the document headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] request_res = client.patch( url_for('b2share_records_rest.b2rec_item', pid_value=record_pid.pid_value), data=json.dumps(patch), headers=headers) assert request_res.status_code == status # _, record_pid, record = create_record(record_data, creator) # test putting the document # data = dict(record) # apply_patch(data, patch) # headers = [('Content-Type', 'application/json'), # ('Accept', 'application/json')] # request_res = client.put( # url_for('b2share_records_rest.b2rec_item', # pid_value=record_pid.pid_value), # data=json.dumps(data), # headers=headers) # assert request_res.status_code == status # test with anonymous user test_modify(401) test_modify(403, non_creator) test_modify(403, creator) test_modify(200, admin)
def test_deposit(app, test_communities, login_user, authentication): """Test record submission with classic login and access token.""" with app.app_context(): allowed_user = create_user('allowed') scopes = current_oauth2server.scope_choices() allowed_token = Token.create_personal('allowed_token', allowed_user.id, scopes=[s[0] for s in scopes]) # application authentication token header allowed_headers = [('Authorization', 'Bearer {}'.format(allowed_token.access_token))] other_user = create_user('other') other_token = Token.create_personal('other_token', other_user.id, scopes=[s[0] for s in scopes]) # application authentication token header other_headers = [('Authorization', 'Bearer {}'.format(other_token.access_token))] community_name = 'MyTestCommunity1' community = Community.get(name=community_name) com_admin = create_user('com_admin', roles=[community.admin_role]) com_admin_token = Token.create_personal('com_admin_token', com_admin.id, scopes=[s[0] for s in scopes]) # application authentication token header com_admin_headers = [ ('Authorization', 'Bearer {}'.format(com_admin_token.access_token)) ] test_records_data = [ generate_record_data(community=community_name) for idx in range(1, 3) ] db.session.commit() if authentication == 'user/password': subtest_deposit(app, test_communities, allowed_user, other_user, com_admin, [], [], [], login_user, test_records_data) else: subtest_deposit(app, test_communities, allowed_user, other_user, com_admin, allowed_headers, other_headers, com_admin_headers, lambda u, c: 42, test_records_data)
def test_deposit(app, test_communities, login_user, authentication): """Test record submission with classic login and access token.""" with app.app_context(): allowed_user = create_user('allowed') scopes = current_oauth2server.scope_choices() allowed_token = Token.create_personal( 'allowed_token', allowed_user.id, scopes=[s[0] for s in scopes] ) # application authentication token header allowed_headers = [('Authorization', 'Bearer {}'.format(allowed_token.access_token))] other_user = create_user('other') other_token = Token.create_personal( 'other_token', other_user.id, scopes=[s[0] for s in scopes] ) # application authentication token header other_headers = [('Authorization', 'Bearer {}'.format(other_token.access_token))] community_name = 'MyTestCommunity1' community = Community.get(name=community_name) com_admin = create_user('com_admin', roles=[community.admin_role]) com_admin_token = Token.create_personal( 'com_admin_token', com_admin.id, scopes=[s[0] for s in scopes] ) # application authentication token header com_admin_headers = [('Authorization', 'Bearer {}'.format(com_admin_token.access_token))] test_records_data = [generate_record_data(community=community_name) for idx in range(1,3)] db.session.commit() if authentication == 'user/password': subtest_deposit(app, test_communities, allowed_user, other_user, com_admin, [], [], [], login_user, test_records_data) else: subtest_deposit(app, test_communities, allowed_user, other_user, com_admin, allowed_headers, other_headers, com_admin_headers, lambda u, c: 42, test_records_data)
def test_deposit_modify_published_permissions(app, login_user, test_communities, test_users): """Test deposit edition after its publication. FIXME: This test should evolve when we allow deposit edition. """ with app.app_context(): community_name = 'MyTestCommunity1' record_data = generate_record_data(community=community_name) admin = test_users['admin'] creator = create_user('creator') non_creator = create_user('non-creator') community = Community.get(name=community_name) com_member = create_user('com_member', roles=[community.member_role]) com_admin = create_user('com_admin', roles=[community.admin_role]) deposit = create_deposit(record_data, creator) deposit.submit() deposit.publish() def test_edit(status, user=None): headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] with app.test_client() as client: if user is not None: login_user(user, client) request_res = client.patch( url_for('b2share_deposit_rest.b2dep_item', pid_value=deposit.pid.pid_value), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.draft.name }]), headers=headers) assert request_res.status_code == status # test with anonymous user test_edit(401) test_edit(403, non_creator) test_edit(403, creator) test_edit(403, admin) test_edit(403, com_member) test_edit(403, com_admin)
def test_deposit_publish_permissions(app, login_user, test_communities, test_users): """Test deposit publication with HTTP PATCH.""" with app.app_context(): community_name = 'MyTestCommunity1' record_data = generate_record_data(community=community_name) admin = test_users['admin'] creator = create_user('creator') non_creator = create_user('non-creator') community = Community.get(name=community_name) com_member = create_user('com_member', roles=[community.member_role]) com_admin = create_user('com_admin', roles=[community.admin_role]) def test_publish(status, user=None): deposit = create_deposit(record_data, creator) deposit.submit() headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] with app.test_client() as client: if user is not None: login_user(user, client) request_res = client.patch( url_for('b2share_deposit_rest.b2dep_item', pid_value=deposit.pid.pid_value), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.published.name }, { "op": "replace", "path": "/titles", "value": [{'title':'newtitle'}] }]), headers=headers) assert request_res.status_code == status # test with anonymous user test_publish(401) test_publish(403, non_creator) test_publish(403, creator) test_publish(200, admin) test_publish(403, com_member) test_publish(200, com_admin)
def test_record_publish_with_external_pids( app, login_user, records_data_with_external_pids): #test_users, test_communities """Test record external files and handle allocation.""" uploaded_files = {'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2'} with app.app_context(): app.config.update({'FAKE_EPIC_PID': True}) creator = create_user('creator') external_pids = records_data_with_external_pids['external_pids'] record_data = generate_record_data(external_pids=external_pids) _, record_pid, record = create_record(record_data, creator, files=uploaded_files) with app.test_client() as client: login_user(creator, client) headers = [('Accept', 'application/json')] request_res = client.get(url_for('b2share_records_rest.b2rec_item', pid_value=record_pid.pid_value), headers=headers) assert request_res.status_code == 200 record = json.loads(request_res.get_data(as_text=True)) assert len( record['files']) == len(external_pids) + len(uploaded_files) for f in record['files']: assert f['ePIC_PID'] if f['key'] in uploaded_files: # uploaded (internal) file assert '0000' in f[ 'ePIC_PID'] # freshly allocated fake pid else: # external file assert f['b2safe'] x_pid = [ rec for rec in external_pids if rec['key'] == f['key'] ][0] assert f['ePIC_PID'] == x_pid['ePIC_PID']
def test_record_publish_with_external_pids(app, login_user, records_data_with_external_pids): #test_users, test_communities """Test record external files and handle allocation.""" uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2' } with app.app_context(): app.config.update({'FAKE_EPIC_PID': True}) creator = create_user('creator') external_pids = records_data_with_external_pids['external_pids'] record_data = generate_record_data(external_pids=external_pids) _, record_pid, record = create_record( record_data, creator, files=uploaded_files ) with app.test_client() as client: login_user(creator, client) headers = [('Accept', 'application/json')] request_res = client.get( url_for('b2share_records_rest.b2rec_item', pid_value=record_pid.pid_value), headers=headers) assert request_res.status_code == 200 record = json.loads(request_res.get_data(as_text=True)) assert len(record['files']) == len(external_pids) + len(uploaded_files) for f in record['files']: assert f['ePIC_PID'] if f['key'] in uploaded_files: # uploaded (internal) file assert '0000' in f['ePIC_PID'] # freshly allocated fake pid else: # external file assert f['b2safe'] x_pid = [rec for rec in external_pids if rec['key'] == f['key']][0] assert f['ePIC_PID'] == x_pid['ePIC_PID']
def test_deposit_read_permissions(app, login_user, test_users, test_communities): """Test deposit read with HTTP GET.""" with app.app_context(): community_name = 'MyTestCommunity1' record_data = generate_record_data(community=community_name) community = Community.get(name=community_name) admin = test_users['admin'] creator = create_user('creator') non_creator = create_user('non-creator') com_member = create_user('com_member', roles=[community.member_role]) com_admin = create_user('com_admin', roles=[community.admin_role]) def test_get(deposit, status, user=None): with app.test_client() as client: if user is not None: login_user(user, client) headers = [('Accept', 'application/json')] request_res = client.get( url_for('b2share_deposit_rest.b2dep_item', pid_value=deposit.pid.pid_value), headers=headers) assert request_res.status_code == status # test with anonymous user deposit = create_deposit(record_data, creator) test_get(deposit, 401) deposit.submit() test_get(deposit, 401) deposit.publish() test_get(deposit, 401) deposit = create_deposit(record_data, creator) test_get(deposit, 403, non_creator) deposit.submit() test_get(deposit, 403, non_creator) deposit.publish() test_get(deposit, 403, non_creator) deposit = create_deposit(record_data, creator) test_get(deposit, 200, creator) deposit.submit() test_get(deposit, 200, creator) deposit.publish() test_get(deposit, 200, creator) deposit = create_deposit(record_data, creator) test_get(deposit, 200, admin) deposit.submit() test_get(deposit, 200, admin) deposit.publish() test_get(deposit, 200, admin) deposit = create_deposit(record_data, creator) test_get(deposit, 403, com_member) deposit.submit() test_get(deposit, 403, com_member) deposit.publish() test_get(deposit, 403, com_member) deposit = create_deposit(record_data, creator) test_get(deposit, 403, com_admin) deposit.submit() test_get(deposit, 200, com_admin) deposit.publish() test_get(deposit, 200, com_admin)
def test_update_expired_embargo(app, test_communities, login_user, cli_cmd): """Test record embargo update.""" uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2' } with app.app_context(): creator = create_user('creator') non_creator = create_user('non-creator') # create a record with a finishing embargo released_record_data = generate_record_data( open_access=False, embargo_date=datetime.utcnow().isoformat(), ) _, _, released_record = create_record( released_record_data, creator, files=uploaded_files ) released_record_id = released_record.id # create a record with anot finished embargo closed_record_data = generate_record_data( open_access=False, # embargo finishes tomorrow embargo_date=(datetime.utcnow() + timedelta(days=1)).isoformat(), ) _, _, closed_record = create_record( closed_record_data, creator, files=uploaded_files ) closed_record_id = closed_record.id db.session.commit() # refresh index to make records searchable current_search._client.indices.refresh() def check_embargo(record_id, is_embargoed): with app.app_context(): with app.test_client() as client: login_user(non_creator, client) # test open_access field in record's metadata record = Record.get_record(record_id) assert record['open_access'] != is_embargoed # test record's file access subtest_file_bucket_permissions( client, record.files.bucket, access_level=None if is_embargoed else 'read', is_authenticated=True ) # check that both records are under embargo check_embargo(released_record_id, is_embargoed=True) check_embargo(closed_record_id, is_embargoed=True) with app.app_context(): if not cli_cmd: update_expired_embargoes.delay() else: script_info = ScriptInfo(create_app=lambda info: app) runner = CliRunner() result = runner.invoke(b2records, ['update_expired_embargoes'], obj=script_info) assert result.exit_code == 0 # refresh index to make records searchable current_search._client.indices.refresh() # check that only the released record is not under embargo check_embargo(released_record_id, is_embargoed=False) check_embargo(closed_record_id, is_embargoed=True)
def test_verify_checksum_in_deposit(app, test_communities, login_user, test_users): """Test checksum for files uploaded in a draft.""" with app.app_context(): creator = create_user('creator') uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2', 'replaced.dat': b'old_content', } test_record_data = generate_record_data() deposit = create_deposit(test_record_data, creator, uploaded_files) uploaded_file_name = 'additional.dat' uploaded_file_content = b'additional content' headers = [('Accept', '*/*')] with app.test_client() as client: login_user(creator, client) # try uploading a new file file_url = url_for_file(deposit.files.bucket.id, uploaded_file_name) client.put( file_url, input_stream=BytesIO(uploaded_file_content), headers=headers ) uploaded_files[uploaded_file_name] = uploaded_file_content # get file content by its uri file_instance = deposit.files['replaced.dat'].obj.file file_reader = urlopen('file://' + file_instance.uri) content = file_reader.read() assert content == b'old_content' # first make it writeable file_instance.writable = True file_instance.set_contents(BytesIO(b'test')) db.session.add(file_instance) db.session.commit() # changing the contents this way should be okay # as the checksum is updated after writing verify_checksum.apply([str(file_instance.id)]) assert file_instance.last_check # directly changing the contents at the uri with open(file_instance.uri, 'w') as file_writer: file_writer.write('modified content') with app.extensions['mail'].record_messages() as outbox: verify_checksum.apply([str(file_instance.id)]) # last_check=False as the checksum will be different now assert not file_instance.last_check schedule_failed_checksum_files( max_count=0, max_size=0, batch_interval={'seconds': 1}, frequency={'seconds': 1} ) assert len(outbox) == 1 # assert that an email is sent afterwards to the support email # mentioning the uri of the file with the different checksum email = outbox[0] assert file_instance.uri in email.body assert current_app.config['SUPPORT_EMAIL'] in email.recipients
def test_deposit_publish(app, test_users, test_communities, login_user): """Test record draft publication with HTTP PATCH.""" with app.app_context(): community_name = 'MyTestCommunity1' creator = test_users['deposits_creator'] record_data = generate_record_data(community=community_name) community = Community.get(name=community_name) com_admin = create_user('com_admin', roles=[community.admin_role]) deposit = create_deposit(record_data, creator) deposit_id = deposit.id deposit.submit() db.session.commit() with app.test_client() as client: login_user(com_admin, client) headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] draft_patch_res = client.patch( url_for('b2share_deposit_rest.b2dep_item', pid_value=deposit.pid.pid_value), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.published.name }]), headers=headers) assert draft_patch_res.status_code == 200 draft_patch_data = json.loads( draft_patch_res.get_data(as_text=True)) expected_metadata = build_expected_metadata( record_data, PublicationStates.published.name, owners=[creator.id], draft=True, PID=draft_patch_data['metadata'].get('ePIC_PID'), DOI=draft_patch_data['metadata'].get('DOI'), ) with app.app_context(): deposit = Deposit.get_record(deposit_id) with app.test_client() as client: login_user(creator, client) assert expected_metadata == draft_patch_data['metadata'] assert (deposit['publication_state'] == PublicationStates.published.name) subtest_self_link(draft_patch_data, draft_patch_res.headers, client) pid, published = deposit.fetch_published() # check that the published record and the deposit are equal except # for the schema cleaned_deposit = {f: v for f, v in deposit.items() if f != '$schema'} cleaned_published = {f: v for f, v in deposit.items() if f != '$schema'} assert cleaned_published == cleaned_deposit # check "published" link assert draft_patch_data['links']['publication'] == \ url_for('b2share_records_rest.{0}_item'.format( RecordUUIDProvider.pid_type ), pid_value=pid.pid_value, _external=True) # check that the published record content match the deposit headers = [('Accept', 'application/json')] self_response = client.get( draft_patch_data['links']['publication'], headers=headers ) assert self_response.status_code == 200 published_data = json.loads(self_response.get_data( as_text=True)) # we don't want to compare the links and dates cleaned_published_data = deepcopy(published_data) # the published record has an extra empty 'files' array assert cleaned_published_data['files'] == [] del cleaned_published_data['files'] cleaned_draft_data = deepcopy(draft_patch_data) for item in [cleaned_published_data, cleaned_draft_data]: del item['links'] del item['created'] del item['updated'] del item['metadata']['$schema'] assert cleaned_draft_data == cleaned_published_data
def test_record_read_permissions(app, test_communities, login_user, test_users): """Test record read with REST API.""" uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2' } admin = test_users['admin'] with app.app_context(): creator = create_user('creator') non_creator = create_user('non-creator') open_record_data = generate_record_data(open_access=True) _, open_record_pid, open_record = create_record( open_record_data, creator, files=uploaded_files ) closed_record_data = generate_record_data(open_access=False) _, closed_record_pid, closed_record = create_record( closed_record_data, creator, files=uploaded_files) with app.test_client() as client: login_user(creator, client) subtest_file_bucket_content(client, open_record.files.bucket, uploaded_files) subtest_file_bucket_content(client, closed_record.files.bucket, uploaded_files) def test_get(pid, record, status, user=None, files_access=None): with app.test_client() as client: if user is not None: login_user(user, client) headers = [('Accept', 'application/json')] request_res = client.get( url_for('b2share_records_rest.b2rec_item', pid_value=pid.pid_value), headers=headers) request_data = json.loads( request_res.get_data(as_text=True)) assert request_res.status_code == status # check that the permissions to the file bucket is correct subtest_file_bucket_permissions( client, record.files.bucket, access_level=files_access, is_authenticated=user is not None ) # test with anonymous user test_get(open_record_pid, open_record, 200, files_access='read') test_get(closed_record_pid, closed_record, 200) test_get(open_record_pid, open_record, 200, non_creator, files_access='read') test_get(closed_record_pid, closed_record, 200, non_creator) test_get(open_record_pid, open_record, 200, creator, files_access='read') test_get(closed_record_pid, closed_record, 200, creator, files_access='read') test_get(open_record_pid, open_record, 200, admin, files_access='read') test_get(closed_record_pid, closed_record, 200, admin, files_access='read')
def test_make_record_with_no_file_and_search(app, test_communities, login_user): '''Test for issue https://github.com/EUDAT-B2SHARE/b2share/issues/1073''' def url_for(*args, **kwargs): with app.app_context(): return flask_url_for(*args, **kwargs) with app.app_context(): community_name = 'MyTestCommunity1' record_data = generate_record_data(community=community_name) allowed_user = create_user('allowed') community = Community.get(name=community_name) com_admin = create_user('com_admin', roles=[community.admin_role]) db.session.commit() with app.test_client() as client: login_user(allowed_user, client) headers = [('Content-Type', 'application/json'), ('Accept', 'application/json')] patch_headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] # create record without files draft_create_res = client.post( url_for('b2share_records_rest.b2rec_list'), data=json.dumps(record_data), headers=headers) assert draft_create_res.status_code == 201 draft_create_data = json.loads(draft_create_res.get_data(as_text=True)) # submit the record draft_submit_res = client.patch(url_for( 'b2share_deposit_rest.b2dep_item', pid_value=draft_create_data['id']), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.submitted.name }]), headers=patch_headers) assert draft_submit_res.status_code == 200 with app.test_client() as client: login_user(com_admin, client) # publish record draft_publish_res = client.patch(url_for( 'b2share_deposit_rest.b2dep_item', pid_value=draft_create_data['id']), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.published.name }]), headers=patch_headers) assert draft_publish_res.status_code == 200 draft_publish_data = json.loads( draft_publish_res.get_data(as_text=True)) # get record record_get_res = client.get(url_for( 'b2share_records_rest.b2rec_item', pid_value=draft_publish_data['id']), headers=headers) assert record_get_res.status_code == 200 record_get_data = json.loads(record_get_res.get_data(as_text=True)) with app.test_client() as client: # refresh index to make records searchable with app.app_context(): current_search._client.indices.refresh() with app.test_client() as client: # test search, for crashes record_search_res = client.get( url_for('b2share_records_rest.b2rec_list'), data='', headers=headers) assert record_search_res.status_code == 200 record_search_data = json.loads( record_search_res.get_data(as_text=True)) assert len(record_search_data['hits']['hits']) == 1 record_hit = record_search_data['hits']['hits'][0] # TODO: the following assert should work: # assert record_hit == record_get_data # -- but currently it doesn't because records with no files # do not have a 'files' link assert record_hit['metadata'] == record_get_data['metadata']
def test_file_download_statistics(app, test_community, test_users, test_records, login_user): """Test checking a record's DOI using CLI commands.""" with app.app_context(): def url_for(*args, **kwargs): """Generate url using flask.url_for and the current app ctx.""" with app.app_context(): return flask_url_for(*args, **kwargs) # create user that will create the record and the files scopes = current_oauth2server.scope_choices() allowed_user = create_user('allowed') scopes = current_oauth2server.scope_choices() allowed_token = Token.create_personal('allowed_token', allowed_user.id, scopes=[s[0] for s in scopes]) # application authentication token header allowed_headers = [('Authorization', 'Bearer {}'.format(allowed_token.access_token))] community_name = 'MyTestCommunity1' community = Community.get(name=community_name) com_admin = create_user('com_admin2', roles=[community.admin_role]) com_admin_token = Token.create_personal('com_admin_token', com_admin.id, scopes=[s[0] for s in scopes]) # application authentication token header com_admin_headers = [ ('Authorization', 'Bearer {}'.format(com_admin_token.access_token)), ('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) ' 'AppleWebKit/537.36 (KHTML, like Gecko)' 'Chrome/45.0.2454.101 Safari/537.36') ] publish_headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] + com_admin_headers submit_headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] + allowed_headers stats_headers = [('Content-Type', 'application/json')] test_records_data = [ generate_record_data(community=test_community.name) for idx in range(1, 3) ] for record_data in test_records_data: with app.test_client() as client: login_user(allowed_user, client) record_list_url = (lambda **kwargs: url_for( 'b2share_records_rest.b2rec_list', **kwargs)) headers = [('Content-Type', 'application/json'), ('Accept', 'application/json')] + allowed_headers draft_create_res = client.post(record_list_url(), data=json.dumps(record_data), headers=headers) assert draft_create_res.status_code == 201 draft_create_data = json.loads( draft_create_res.get_data(as_text=True)) uploaded_files = { 'myfile1.html': b'contents1', 'myfile2.html': b'contents2' } for file_key, file_content in uploaded_files.items(): # Test file upload headers = [('Accept', '*/*'), ('Content-Type', 'text/html; charset=utf-8') ] + allowed_headers object_url = '{0}/{1}'.format( draft_create_data['links']['files'], file_key) file_put_res = client.put( object_url, input_stream=BytesIO(file_content), headers=headers) assert file_put_res.status_code == 200 file_put_data = json.loads( file_put_res.get_data(as_text=True)) assert 'created' in file_put_data bucket_id = draft_create_data['links']['files'].split( '/')[-1] # make sure that downloads from deposits are skipped client.get( url_for('invenio_files_rest.object_api', bucket_id=bucket_id, key=file_key)) assert process_events(['file-download']) == \ [('file-download', (0, 0))] # test draft submit draft_submit_res = client.patch( url_for('b2share_deposit_rest.b2dep_item', pid_value=draft_create_data['id']), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.submitted.name }]), headers=submit_headers) assert draft_submit_res.status_code == 200 with app.test_client() as client: login_user(com_admin, client) # test draft publish draft_publish_res = client.patch( url_for('b2share_deposit_rest.b2dep_item', pid_value=draft_create_data['id']), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.published.name }]), headers=publish_headers) assert draft_publish_res.status_code == 200 draft_publish_data = json.loads( draft_publish_res.get_data(as_text=True)) # Test record GET record_get_res = client.get(url_for( 'b2share_records_rest.b2rec_item', pid_value=draft_publish_data['id']), headers=headers) assert record_get_res.status_code == 200 record_get_data = json.loads( record_get_res.get_data(as_text=True)) # make sure that templates are in the ES list(current_search.put_templates()) # test that a record is accessible through the rest api file1 = record_get_data['files'][0] # download once client.get(url_for('invenio_files_rest.object_api', bucket_id=file1['bucket'], key=file1['key']), headers=com_admin_headers) # make sure that the queue contains the event assert list( current_queues.queues['stats-file-download'].consume()) # download again client.get(url_for('invenio_files_rest.object_api', bucket_id=file1['bucket'], key=file1['key']), headers=com_admin_headers) process_events(['file-download']) current_search_client.indices.refresh('*') # make sure that new index for events is created in ES current_search_client.indices.exists( index='events-stats-file-download') aggregate_events(['file-download-agg']) current_search_client.indices.refresh('*') # make sure that new aggregation index is created in ES current_search_client.indices.exists( index='stats-file-download') stats_ret = client.post(url_for('invenio_stats.stat_query'), data=json.dumps({ 'mystat': { 'stat': 'bucket-file-download-total', 'params': { 'start_date': '2017-01-01', 'bucket_id': file1['bucket'], } } }), headers=stats_headers) stats_ret_data = json.loads(stats_ret.get_data(as_text=True)) assert stats_ret_data['mystat']['buckets'][0]['value'] == 1.0
def test_make_record_with_no_file_and_search(app, test_communities, login_user): '''Test for issue https://github.com/EUDAT-B2SHARE/b2share/issues/1073''' def url_for(*args, **kwargs): with app.app_context(): return flask_url_for(*args, **kwargs) with app.app_context(): community_name = 'MyTestCommunity1' record_data = generate_record_data(community=community_name) allowed_user = create_user('allowed') community = Community.get(name=community_name) com_admin = create_user('com_admin', roles=[community.admin_role]) db.session.commit() with app.test_client() as client: login_user(allowed_user, client) headers = [('Content-Type', 'application/json'), ('Accept', 'application/json')] patch_headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] # create record without files draft_create_res = client.post( url_for('b2share_records_rest.b2rec_list'), data=json.dumps(record_data), headers=headers) assert draft_create_res.status_code == 201 draft_create_data = json.loads( draft_create_res.get_data(as_text=True)) # submit the record draft_submit_res = client.patch( url_for('b2share_deposit_rest.b2dep_item', pid_value=draft_create_data['id']), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.submitted.name }]), headers=patch_headers) assert draft_submit_res.status_code == 200 with app.test_client() as client: login_user(com_admin, client) # publish record draft_publish_res = client.patch( url_for('b2share_deposit_rest.b2dep_item', pid_value=draft_create_data['id']), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.published.name }]), headers=patch_headers) assert draft_publish_res.status_code == 200 draft_publish_data = json.loads( draft_publish_res.get_data(as_text=True)) # get record record_get_res = client.get( url_for('b2share_records_rest.b2rec_item', pid_value=draft_publish_data['id']), headers=headers) assert record_get_res.status_code == 200 record_get_data = json.loads( record_get_res.get_data(as_text=True)) with app.test_client() as client: # refresh index to make records searchable with app.app_context(): current_search._client.indices.refresh() with app.test_client() as client: # test search, for crashes record_search_res = client.get( url_for('b2share_records_rest.b2rec_list'), data='', headers=headers) assert record_search_res.status_code == 200 record_search_data = json.loads( record_search_res.get_data(as_text=True)) assert len(record_search_data['hits']['hits']) == 1 record_hit = record_search_data['hits']['hits'][0] # TODO: the following assert should work: # assert record_hit == record_get_data # -- but currently it doesn't because records with no files # do not have a 'files' link assert record_hit['metadata'] == record_get_data['metadata']
def test_deposit_publish(app, test_users, test_communities, login_user): """Test record draft publication with HTTP PATCH.""" with app.app_context(): community_name = 'MyTestCommunity1' creator = test_users['deposits_creator'] record_data = generate_record_data(community=community_name) community = Community.get(name=community_name) com_admin = create_user('com_admin', roles=[community.admin_role]) deposit = create_deposit(record_data, creator) deposit_id = deposit.id deposit.submit() db.session.commit() with app.test_client() as client: login_user(com_admin, client) headers = [('Content-Type', 'application/json-patch+json'), ('Accept', 'application/json')] draft_patch_res = client.patch(url_for( 'b2share_deposit_rest.b2dep_item', pid_value=deposit.pid.pid_value), data=json.dumps([{ "op": "replace", "path": "/publication_state", "value": PublicationStates.published.name }]), headers=headers) assert draft_patch_res.status_code == 200 draft_patch_data = json.loads( draft_patch_res.get_data(as_text=True)) expected_metadata = build_expected_metadata( record_data, PublicationStates.published.name, owners=[creator.id], draft=True, PID=draft_patch_data['metadata'].get('ePIC_PID'), DOI=draft_patch_data['metadata'].get('DOI'), ) with app.app_context(): deposit = Deposit.get_record(deposit_id) with app.test_client() as client: login_user(creator, client) assert expected_metadata == draft_patch_data['metadata'] assert (deposit['publication_state'] == PublicationStates.published.name) subtest_self_link(draft_patch_data, draft_patch_res.headers, client) pid, published = deposit.fetch_published() # check that the published record and the deposit are equal except # for the schema cleaned_deposit = { f: v for f, v in deposit.items() if f != '$schema' } cleaned_published = { f: v for f, v in deposit.items() if f != '$schema' } assert cleaned_published == cleaned_deposit # check "published" link assert draft_patch_data['links']['publication'] == \ url_for('b2share_records_rest.{0}_item'.format( RecordUUIDProvider.pid_type ), pid_value=pid.pid_value, _external=True) # check that the published record content match the deposit headers = [('Accept', 'application/json')] self_response = client.get( draft_patch_data['links']['publication'], headers=headers) assert self_response.status_code == 200 published_data = json.loads(self_response.get_data(as_text=True)) # we don't want to compare the links and dates cleaned_published_data = deepcopy(published_data) # the published record has an extra empty 'files' array assert cleaned_published_data['files'] == [] del cleaned_published_data['files'] cleaned_draft_data = deepcopy(draft_patch_data) for item in [cleaned_published_data, cleaned_draft_data]: del item['links'] del item['created'] del item['updated'] del item['metadata']['$schema'] assert cleaned_draft_data == cleaned_published_data
def test_deposit_files_permissions(app, test_communities, login_user, test_users): """Test deposit read with HTTP GET.""" with app.app_context(): community_name = 'MyTestCommunity1' admin = test_users['admin'] creator = create_user('creator') non_creator = create_user('non-creator') community = Community.get(name=community_name) com_member = create_user('com_member', roles=[community.member_role]) com_admin = create_user('com_admin', roles=[community.admin_role]) uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2' } test_record_data = generate_record_data(community=community_name) def test_files_access(draft_access, submitted_access, published_access, user=None): def get_file(deposit, file_access): with app.test_client() as client: if user is not None: login_user(user, client) subtest_file_bucket_permissions( client, deposit.files.bucket, access_level=file_access, is_authenticated=user is not None ) deposit = create_deposit(test_record_data, creator, uploaded_files) get_file(deposit, file_access=draft_access) deposit = create_deposit(test_record_data, creator, uploaded_files) deposit.submit() get_file(deposit, file_access=submitted_access) deposit = create_deposit(test_record_data, creator, uploaded_files) deposit.submit() deposit.publish() get_file(deposit, file_access=published_access) # Anonymous user test_files_access(draft_access=None, submitted_access=None, published_access=None) # Non creator user test_files_access(user=non_creator, draft_access=None, submitted_access=None, published_access=None) # Creator test_files_access(user=creator, draft_access='write', submitted_access='write', published_access=None) # Admin test_files_access(user=admin, draft_access='write', submitted_access='write', published_access=None) # Community member test_files_access(user=com_member, draft_access=None, submitted_access=None, published_access=None) # Community admin test_files_access(user=com_admin, draft_access=None, submitted_access='write', published_access=None)
def test_verify_checksum_in_deposit(app, test_communities, login_user, test_users): """Test checksum for files uploaded in a draft.""" with app.app_context(): creator = create_user('creator') uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2', 'replaced.dat': b'old_content', } test_record_data = generate_record_data() deposit = create_deposit(test_record_data, creator, uploaded_files) uploaded_file_name = 'additional.dat' uploaded_file_content = b'additional content' headers = [('Accept', '*/*')] with app.test_client() as client: login_user(creator, client) # try uploading a new file file_url = url_for_file(deposit.files.bucket.id, uploaded_file_name) client.put(file_url, input_stream=BytesIO(uploaded_file_content), headers=headers) uploaded_files[uploaded_file_name] = uploaded_file_content # get file content by its uri file_instance = deposit.files['replaced.dat'].obj.file file_reader = urlopen('file://' + file_instance.uri) content = file_reader.read() assert content == b'old_content' # first make it writeable file_instance.writable = True file_instance.set_contents(BytesIO(b'test')) db.session.add(file_instance) db.session.commit() # changing the contents this way should be okay # as the checksum is updated after writing verify_checksum.apply([str(file_instance.id)]) assert file_instance.last_check # directly changing the contents at the uri with open(file_instance.uri, 'w') as file_writer: file_writer.write('modified content') with app.extensions['mail'].record_messages() as outbox: verify_checksum.apply([str(file_instance.id)]) # last_check=False as the checksum will be different now assert not file_instance.last_check schedule_failed_checksum_files(max_count=0, max_size=0, batch_interval={'seconds': 1}, frequency={'seconds': 1}) assert len(outbox) == 1 # assert that an email is sent afterwards to the support email # mentioning the uri of the file with the different checksum email = outbox[0] assert file_instance.uri in email.body assert current_app.config['SUPPORT_EMAIL'] in email.recipients
def test_update_expired_embargo(app, test_communities, login_user, cli_cmd): """Test record embargo update.""" uploaded_files = {'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2'} with app.app_context(): creator = create_user('creator') non_creator = create_user('non-creator') # create a record with a finishing embargo released_record_data = generate_record_data( open_access=False, embargo_date=datetime.utcnow().isoformat(), ) _, _, released_record = create_record(released_record_data, creator, files=uploaded_files) released_record_id = released_record.id # create a record with anot finished embargo closed_record_data = generate_record_data( open_access=False, # embargo finishes tomorrow embargo_date=(datetime.utcnow() + timedelta(days=1)).isoformat(), ) _, _, closed_record = create_record(closed_record_data, creator, files=uploaded_files) closed_record_id = closed_record.id db.session.commit() # refresh index to make records searchable current_search._client.indices.refresh() def check_embargo(record_id, is_embargoed): with app.app_context(): with app.test_client() as client: login_user(non_creator, client) # test open_access field in record's metadata record = Record.get_record(record_id) assert record['open_access'] != is_embargoed # test record's file access subtest_file_bucket_permissions( client, record.files.bucket, access_level=None if is_embargoed else 'read', is_authenticated=True) # check that both records are under embargo check_embargo(released_record_id, is_embargoed=True) check_embargo(closed_record_id, is_embargoed=True) with app.app_context(): if not cli_cmd: update_expired_embargoes.delay() else: script_info = ScriptInfo(create_app=lambda info: app) runner = CliRunner() result = runner.invoke(b2records, ['update_expired_embargoes'], obj=script_info) assert result.exit_code == 0 # refresh index to make records searchable current_search._client.indices.refresh() # check that only the released record is not under embargo check_embargo(released_record_id, is_embargoed=False) check_embargo(closed_record_id, is_embargoed=True)
def test_delete_record(app, test_users, test_communities, login_user, script_info): """Test record deletion through the REST API.""" from click.testing import CliRunner from invenio_search import current_search_client from invenio_indexer import cli from invenio_indexer.tasks import process_bulk_queue uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2' } admin = test_users['admin'] headers = [('Accept', 'application/json')] with app.app_context(): creator = create_user('creator') non_creator = create_user('non_creator') record_data = generate_record_data() with app.test_client() as client: deposit, record_pid, record = create_record( record_data, creator, files=uploaded_files ) pid_value = record_pid.pid_value record_id = record.id bucket_id = record.files.bucket.id object_version = record.files.bucket.objects[0] deposit_bucket_id = deposit.files.bucket.id deposit_object_version = deposit.files.bucket.objects[0] record_url = url_for('b2share_records_rest.b2rec_item', pid_value=pid_value) deposit_url = url_for('b2share_deposit_rest.b2dep_item', pid_value=pid_value) bucket_url = url_for('invenio_files_rest.bucket_api', bucket_id=bucket_id) deposit_bucket_url = url_for('invenio_files_rest.bucket_api', bucket_id=deposit_bucket_id) object_version_url = url_for( 'invenio_files_rest.object_api', bucket_id=bucket_id, version=object_version.version_id, key=object_version.key ) deposit_object_version_url = url_for( 'invenio_files_rest.object_api', bucket_id=deposit_bucket_id, version=deposit_object_version.version_id, key=deposit_object_version.key ) # check that the record and deposit are searchable current_search_client.indices.flush('*') res = current_search_client.search(index='records') assert res['hits']['total'] == 1 res = current_search_client.search(index='deposits') assert res['hits']['total'] == 1 def test_delete(status, user=None): with app.test_client() as client: if user is not None: login_user(user, client) # delete the record request_res = client.delete(record_url, headers=headers) assert request_res.status_code == status def test_access(user=None, deleted=True): with app.test_client() as client: if user is not None: login_user(user, client) # try accessing the record request_res = client.get(record_url, headers=headers) assert request_res.status_code == 410 if deleted else 200 # try accessing the file bucket request_res = client.get(bucket_url, headers=headers) assert request_res.status_code == 404 if deleted else 200 # try accessing the file request_res = client.get(object_version_url, headers=headers) assert request_res.status_code == 404 if deleted else 200 # try accessing the deposit request_res = client.get(deposit_url, headers=headers) assert request_res.status_code == 410 if deleted else 200 # try accessing the deposit file bucket request_res = client.get(deposit_bucket_url, headers=headers) assert request_res.status_code == 404 if deleted else 200 # try accessing the deposit file request_res = client.get(deposit_object_version_url, headers=headers) assert request_res.status_code == 404 if deleted else 200 # Check that everything is accessible test_access(creator, deleted=False) test_delete(401) # anonymous user test_delete(403, creator) test_delete(403, non_creator) test_delete(204, admin) test_access() # anonymous user test_access(creator) test_access(non_creator) test_access(admin) # Check that reindexing records does not index deleted records and deposits with app.app_context(): runner = CliRunner() # Initialize queue res = runner.invoke(cli.queue, ['init', 'purge'], obj=script_info) assert 0 == res.exit_code # schedule a reindex task res = runner.invoke(cli.reindex, ['--yes-i-know'], obj=script_info) assert 0 == res.exit_code res = runner.invoke(cli.run, [], obj=script_info) assert 0 == res.exit_code # execute scheduled tasks synchronously process_bulk_queue.delay() # flush the indices so that indexed records are searchable current_search_client.indices.flush('*') # check that the record and deposit are not indexed res = current_search_client.search(index='records') assert res['hits']['total'] == 0 res = current_search_client.search(index='deposits') assert res['hits']['total'] == 0
def test_deposit_read_permissions(app, login_user, test_users, test_communities): """Test deposit read with HTTP GET.""" with app.app_context(): community_name = 'MyTestCommunity1' record_data = generate_record_data(community=community_name) community = Community.get(name=community_name) admin = test_users['admin'] creator = create_user('creator') non_creator = create_user('non-creator') com_member = create_user('com_member', roles=[community.member_role]) com_admin = create_user('com_admin', roles=[community.admin_role]) def test_get(deposit, status, user=None): with app.test_client() as client: if user is not None: login_user(user, client) headers = [('Accept', 'application/json')] request_res = client.get(url_for( 'b2share_deposit_rest.b2dep_item', pid_value=deposit.pid.pid_value), headers=headers) assert request_res.status_code == status # test with anonymous user deposit = create_deposit(record_data, creator) test_get(deposit, 401) deposit.submit() test_get(deposit, 401) deposit.publish() test_get(deposit, 401) deposit = create_deposit(record_data, creator) test_get(deposit, 403, non_creator) deposit.submit() test_get(deposit, 403, non_creator) deposit.publish() test_get(deposit, 403, non_creator) deposit = create_deposit(record_data, creator) test_get(deposit, 200, creator) deposit.submit() test_get(deposit, 200, creator) deposit.publish() test_get(deposit, 200, creator) deposit = create_deposit(record_data, creator) test_get(deposit, 200, admin) deposit.submit() test_get(deposit, 200, admin) deposit.publish() test_get(deposit, 200, admin) deposit = create_deposit(record_data, creator) test_get(deposit, 403, com_member) deposit.submit() test_get(deposit, 403, com_member) deposit.publish() test_get(deposit, 403, com_member) deposit = create_deposit(record_data, creator) test_get(deposit, 403, com_admin) deposit.submit() test_get(deposit, 200, com_admin) deposit.publish() test_get(deposit, 200, com_admin)
def test_deposit_files_permissions(app, test_communities, login_user, test_users): """Test deposit read with HTTP GET.""" with app.app_context(): community_name = 'MyTestCommunity1' admin = test_users['admin'] creator = create_user('creator') non_creator = create_user('non-creator') community = Community.get(name=community_name) com_member = create_user('com_member', roles=[community.member_role]) com_admin = create_user('com_admin', roles=[community.admin_role]) uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2' } test_record_data = generate_record_data(community=community_name) def test_files_access(draft_access, submitted_access, published_access, user=None): def get_file(deposit, file_access): with app.test_client() as client: if user is not None: login_user(user, client) subtest_file_bucket_permissions(client, deposit.files.bucket, access_level=file_access, is_authenticated=user is not None) deposit = create_deposit(test_record_data, creator, uploaded_files) get_file(deposit, file_access=draft_access) deposit = create_deposit(test_record_data, creator, uploaded_files) deposit.submit() get_file(deposit, file_access=submitted_access) deposit = create_deposit(test_record_data, creator, uploaded_files) deposit.submit() deposit.publish() get_file(deposit, file_access=published_access) # Anonymous user test_files_access(draft_access=None, submitted_access=None, published_access=None) # Non creator user test_files_access(user=non_creator, draft_access=None, submitted_access=None, published_access=None) # Creator test_files_access(user=creator, draft_access='write', submitted_access='write', published_access=None) # Admin test_files_access(user=admin, draft_access='write', submitted_access='write', published_access=None) # Community member test_files_access(user=com_member, draft_access=None, submitted_access=None, published_access=None) # Community admin test_files_access(user=com_admin, draft_access=None, submitted_access='write', published_access=None)
def test_delete_record(app, test_users, test_communities, login_user, script_info): """Test record deletion through the REST API.""" from click.testing import CliRunner from invenio_search import current_search_client from invenio_indexer import cli from invenio_indexer.tasks import process_bulk_queue uploaded_files = { 'myfile1.dat': b'contents1', 'myfile2.dat': b'contents2' } admin = test_users['admin'] headers = [('Accept', 'application/json')] with app.app_context(): creator = create_user('creator') non_creator = create_user('non_creator') record_data = generate_record_data() with app.test_client() as client: deposit, record_pid, record = create_record( record_data, creator, files=uploaded_files ) pid_value = record_pid.pid_value record_id = record.id bucket_id = record.files.bucket.id object_version = record.files.bucket.objects[0] deposit_bucket_id = deposit.files.bucket.id deposit_object_version = deposit.files.bucket.objects[0] record_url = url_for('b2share_records_rest.b2rec_item', pid_value=pid_value) deposit_url = url_for('b2share_deposit_rest.b2dep_item', pid_value=pid_value) bucket_url = url_for('invenio_files_rest.bucket_api', bucket_id=bucket_id) deposit_bucket_url = url_for('invenio_files_rest.bucket_api', bucket_id=deposit_bucket_id) object_version_url = url_for( 'invenio_files_rest.object_api', bucket_id=bucket_id, version=object_version.version_id, key=object_version.key ) deposit_object_version_url = url_for( 'invenio_files_rest.object_api', bucket_id=deposit_bucket_id, version=deposit_object_version.version_id, key=deposit_object_version.key ) # check that the record and deposit are searchable current_search_client.indices.flush('*') res = current_search_client.search(index='records') assert res['hits']['total'] == 1 res = current_search_client.search(index='deposits') assert res['hits']['total'] == 1 def test_delete(status, user=None): with app.test_client() as client: if user is not None: login_user(user, client) # delete the record request_res = client.delete(record_url, headers=headers) assert request_res.status_code == status def test_access(user=None, deleted=True): with app.test_client() as client: if user is not None: login_user(user, client) # try accessing the record request_res = client.get(record_url, headers=headers) assert request_res.status_code == 410 if deleted else 200 # try accessing the file bucket request_res = client.get(bucket_url, headers=headers) assert request_res.status_code == 404 if deleted else 200 # try accessing the file request_res = client.get(object_version_url, headers=headers) assert request_res.status_code == 404 if deleted else 200 # try accessing the deposit request_res = client.get(deposit_url, headers=headers) assert request_res.status_code == 410 if deleted else 200 # try accessing the deposit file bucket request_res = client.get(deposit_bucket_url, headers=headers) assert request_res.status_code == 404 if deleted else 200 # try accessing the deposit file request_res = client.get(deposit_object_version_url, headers=headers) assert request_res.status_code == 404 if deleted else 200 # Check that everything is accessible test_access(creator, deleted=False) test_delete(401) # anonymous user test_delete(403, creator) test_delete(403, non_creator) test_delete(200, admin) test_access() # anonymous user test_access(creator) test_access(non_creator) test_access(admin) # Check that reindexing records does not index deleted records and deposits with app.app_context(): runner = CliRunner() # Initialize queue res = runner.invoke(cli.queue, ['init', 'purge'], obj=script_info) assert 0 == res.exit_code # schedule a reindex task res = runner.invoke(cli.reindex, ['--yes-i-know'], obj=script_info) assert 0 == res.exit_code res = runner.invoke(cli.run, [], obj=script_info) assert 0 == res.exit_code # execute scheduled tasks synchronously process_bulk_queue.delay() # flush the indices so that indexed records are searchable current_search_client.indices.flush('*') # check that the record and deposit are not indexed res = current_search_client.search(index='records') assert res['hits']['total'] == 0 res = current_search_client.search(index='deposits') assert res['hits']['total'] == 0