Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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)
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
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)
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
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)
Ejemplo n.º 14
0
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)
Ejemplo n.º 15
0
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']
Ejemplo n.º 16
0
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']
Ejemplo n.º 17
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)
Ejemplo n.º 18
0
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)
Ejemplo n.º 19
0
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
Ejemplo n.º 20
0
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
Ejemplo n.º 21
0
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')
Ejemplo n.º 22
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']
Ejemplo n.º 23
0
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
Ejemplo n.º 24
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']
Ejemplo n.º 25
0
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
Ejemplo n.º 26
0
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)
Ejemplo n.º 27
0
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
Ejemplo n.º 28
0
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)
Ejemplo n.º 29
0
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
Ejemplo n.º 30
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)
Ejemplo n.º 31
0
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')
Ejemplo n.º 32
0
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)
Ejemplo n.º 33
0
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