def test_generation_of_external_pids(app, records_data_with_external_pids,
                                     deposit_with_external_pids, test_users):
    """Test the generate_external_pids function."""
    expected_output = records_data_with_external_pids[
        'external_pids'][:]
    with app.app_context():
        deposit = Deposit.get_record(deposit_with_external_pids.deposit_id)
        output = generate_external_pids(deposit)
        assert output == expected_output

        all_files = list(deposit.files)
        for f in all_files:
            if f.obj.key == \
                    records_data_with_external_pids['external_pids'][0]['key']:
                f.delete(f.obj.bucket, f.obj.key)
        output = generate_external_pids(deposit)
        expected_output_sorted = \
            records_data_with_external_pids['external_pids'][1:]
        expected_output_sorted.sort(key=lambda f: f['key'])
        assert output == expected_output_sorted

        records_data_with_external_pids['external_pids'].reverse()
        deposit2 = create_deposit(records_data_with_external_pids,
                                  test_users['deposits_creator'])
        output = generate_external_pids(deposit2)
        assert output == expected_output
def test_generation_of_external_pids(app, records_data_with_external_pids,
                                     deposit_with_external_pids, test_users):
    """Test the generate_external_pids function."""
    expected_output = records_data_with_external_pids['external_pids'][:]
    with app.app_context():
        deposit = Deposit.get_record(deposit_with_external_pids.deposit_id)
        output = generate_external_pids(deposit)
        assert output == expected_output

        all_files = list(deposit.files)
        for f in all_files:
            if f.obj.key == \
                    records_data_with_external_pids['external_pids'][0]['key']:
                f.delete(f.obj.bucket, f.obj.key)
        output = generate_external_pids(deposit)
        expected_output_sorted = \
            records_data_with_external_pids['external_pids'][1:]
        expected_output_sorted.sort(key=lambda f: f['key'])
        assert output == expected_output_sorted

        records_data_with_external_pids['external_pids'].reverse()
        deposit2 = create_deposit(records_data_with_external_pids,
                                  test_users['deposits_creator'])
        output = generate_external_pids(deposit2)
        assert output == expected_output
Exemple #3
0
    def _load_additional_permissions(self):
        permissions = []
        new_deposit = None
        # Check submit/publish actions
        if (request.method == 'PATCH' and
            request.content_type == 'application/json-patch+json'):
            # FIXME: need some optimization on Invenio side. We are applying
            # the patch twice
            patch = deposit_patch_input_loader(self.deposit)
            new_deposit = deepcopy(self.deposit)
            # Generate 'external_pids' field in order to give
            # the illusion that this field actually exist.
            external_pids = generate_external_pids(self.deposit)
            if external_pids:
                new_deposit['external_pids'] = deepcopy(external_pids)
            apply_patch(new_deposit, patch, in_place=True)
            external_pids_changed = False
            if external_pids:
                external_pids_changed = (
                    external_pids != new_deposit['external_pids']
                )
                del new_deposit['external_pids']
        else:
            abort(400)

        # Create permission for updating the state_field
        if (new_deposit is not None and new_deposit['publication_state']
                != self.deposit['publication_state']):
            state_permission = StrictDynamicPermission()
            state_permission.explicit_needs.add(
                update_deposit_publication_state_need_factory(
                    community=self.deposit['community'],
                    old_state=self.deposit['publication_state'],
                    new_state=new_deposit['publication_state']
                )
            )
            # Owners of a record can always "submit" it.
            if (self.deposit['publication_state'] == PublicationStates.draft.name and
                new_deposit['publication_state'] == PublicationStates.submitted.name or
                # Owners have also the right to move the record from submitted
                # to draft again.
                self.deposit['publication_state'] == PublicationStates.submitted.name and
                new_deposit['publication_state'] == PublicationStates.draft.name):
                # Owners are allowed to update
                for owner_id in self.deposit['_deposit']['owners']:
                    state_permission.explicit_needs.add(UserNeed(owner_id))
            permissions.append(state_permission)

        # Create permission for updating generic metadata fields.
        # Only superadmin can modify published draft.
        if self.deposit['publication_state'] != 'published':
            new_state = new_deposit['publication_state']
            # Check if any metadata has been changed
            del new_deposit['publication_state']
            original_metadata = deepcopy(self.deposit)
            del original_metadata['publication_state']
            if original_metadata != new_deposit:
                permissions.append(
                    UpdateDepositMetadataPermission(self.deposit, new_state)
                )

            if external_pids_changed:
                permissions.append(
                    DepositFilesPermission(self.deposit, 'bucket-update')
                )

        if len(permissions) > 1:
            self.permissions.add(AndPermissions(*permissions))
        elif len(permissions) == 1:
            self.permissions.add(permissions[0])
        elif len(permissions) == 0:
            # Avoid forbidding requests doing nothing. This can be useful if
            # a script replays an action.
            self.permissions.add(
                UpdateDepositMetadataPermission(
                    self.deposit, new_deposit['publication_state']
                )
            )
Exemple #4
0
    def filter_internal(self, data):
        """Remove internal fields from the record metadata."""
        external_pids = []
        bucket = None
        record = None
        # differentiating between search results and
        # single record requests
        if hasattr(g, 'record'):
            record = g.record
            if record.files:
                bucket = record.files.bucket
            if is_deposit(record.model):
                external_pids = generate_external_pids(record)
            # if it is a published record don't generate external pids
            # as they are immutable and stored in _deposit
            else:
                external_pids = record.model.json[
                    '_deposit'].get('external_pids')
            user_has_permission = \
                allow_public_file_metadata(data['metadata']) if bucket \
                is None else files_permission_factory(
                    bucket, 'bucket-read').can()
        elif hasattr(g, 'record_hit'):
            user_has_permission = allow_public_file_metadata(
                g.record_hit['_source'])

        if '_deposit' in data['metadata']:
            data['metadata']['owners'] = data['metadata']['_deposit']['owners']

            # Add the external_pids only if the
            # user is allowed to read the bucket
            if external_pids and bucket and user_has_permission:
                data['metadata']['external_pids'] = external_pids
            del data['metadata']['_deposit']
        if '_files' in data['metadata']:
            # Also add the files field only if the user is allowed
            if user_has_permission:
                data['files'] = data['metadata']['_files']
                if external_pids and bucket:
                    external_dict = {x['key']: x['ePIC_PID']
                                     for x in external_pids}
                    for _file in data['files']:
                        if _file['key'] in external_dict:
                            _file['b2safe'] = True
                            _file['ePIC_PID'] = external_dict[_file['key']]
            del data['metadata']['_files']
        if '_pid' in data['metadata']:
            # move PIDs to metadata top level
            epic_pids = [p for p in data['metadata']['_pid']
                         if p.get('type') == 'ePIC_PID']
            dois = [p for p in data['metadata']['_pid']
                    if p.get('type') == 'DOI']
            if len(epic_pids) > 0:
                data['metadata']['ePIC_PID'] = epic_pids[0].get('value')
            if len(dois) > 0:
                data['metadata']['DOI'] = DOI_URL_PREFIX + dois[0].get('value')

            # add parent version pid
            # data['metadata']['parent_id'] = next(
            #     pid['value'] for pid in data['metadata']['_pid']
            #     if pid['type'] == RecordUUIDProvider.parent_pid_type
            # )
            del data['metadata']['_pid']
        if '_oai' in data['metadata']:
            del data['metadata']['_oai']
        if '_internal' in data['metadata']:
            del data['metadata']['_internal']
        return data
Exemple #5
0
    def filter_internal(self, data):
        """Remove internal fields from the record metadata."""
        external_pids = []
        bucket = None
        record = None
        # differentiating between search results and
        # single record requests
        if hasattr(g, 'record'):
            record = g.record
            if record.files:
                bucket = record.files.bucket
            if is_deposit(record.model):
                external_pids = generate_external_pids(record)
            # if it is a published record don't generate external pids
            # as they are immutable and stored in _deposit
            else:
                external_pids = record.model.json[
                    '_deposit'].get('external_pids')
            user_has_permission = \
                allow_public_file_metadata(data['metadata']) if bucket \
                is None else files_permission_factory(
                    bucket, 'bucket-read').can()
        elif hasattr(g, 'record_hit'):
            user_has_permission = allow_public_file_metadata(
                g.record_hit['_source'])

        if '_deposit' in data['metadata']:
            if hasattr(g, 'record') and is_deposit(record.model) and current_app.config.get('AUTOMATICALLY_ASSIGN_DOI', False):
                # add future DOI string
                data['metadata'].update({'$future_doi': generate_doi(data['metadata']['_deposit']['id']) })

            data['metadata']['owners'] = data['metadata']['_deposit']['owners']

            # Add the external_pids only if the
            # user is allowed to read the bucket
            if external_pids and bucket and user_has_permission:
                data['metadata']['external_pids'] = external_pids
            del data['metadata']['_deposit']
        if '_files' in data['metadata']:
            # Also add the files field only if the user is allowed
            if user_has_permission:
                data['files'] = data['metadata']['_files']
                if external_pids and bucket:
                    external_dict = {x['key']: x['ePIC_PID']
                                     for x in external_pids}
                    for _file in data['files']:
                        if _file['key'] in external_dict:
                            _file['b2safe'] = True
                            _file['ePIC_PID'] = external_dict[_file['key']]
            del data['metadata']['_files']
        if '_pid' in data['metadata']:
            # move PIDs to metadata top level
            epic_pids = [p for p in data['metadata']['_pid']
                         if p.get('type') == 'ePIC_PID']
            dois = [p for p in data['metadata']['_pid']
                    if p.get('type') == 'DOI']
            if len(epic_pids) > 0:
                data['metadata']['ePIC_PID'] = epic_pids[0].get('value')
            if len(dois) > 0:
                data['metadata']['DOI'] = DOI_URL_PREFIX + dois[0].get('value')

            # add parent version pid
            # data['metadata']['parent_id'] = next(
            #     pid['value'] for pid in data['metadata']['_pid']
            #     if pid['type'] == RecordUUIDProvider.parent_pid_type
            # )
            del data['metadata']['_pid']
        if '_oai' in data['metadata']:
            del data['metadata']['_oai']
        if '_internal' in data['metadata']:
            del data['metadata']['_internal']
        return data
Exemple #6
0
    def _load_additional_permissions(self):
        permissions = []
        new_deposit = None
        # Check submit/publish actions
        if (request.method == 'PATCH' and
            request.content_type == 'application/json-patch+json'):
            # FIXME: need some optimization on Invenio side. We are applying
            # the patch twice
            patch = deposit_patch_input_loader(self.deposit)
            new_deposit = deepcopy(self.deposit)
            # Generate 'external_pids' field in order to give
            # the illusion that this field actually exist.
            external_pids = generate_external_pids(self.deposit)
            if external_pids:
                new_deposit['external_pids'] = deepcopy(external_pids)
            apply_patch(new_deposit, patch, in_place=True)
            external_pids_changed = False
            if external_pids:
                external_pids_changed = (
                    external_pids != new_deposit['external_pids']
                )
                del new_deposit['external_pids']
        else:
            abort(400)

        # Create permission for updating the state_field
        if (new_deposit is not None and new_deposit['publication_state']
                != self.deposit['publication_state']):
            state_permission = StrictDynamicPermission()
            state_permission.explicit_needs.add(
                update_deposit_publication_state_need_factory(
                    community=self.deposit['community'],
                    old_state=self.deposit['publication_state'],
                    new_state=new_deposit['publication_state']
                )
            )
            # Owners of a record can always "submit" it.
            if (self.deposit['publication_state'] == PublicationStates.draft.name and
                new_deposit['publication_state'] == PublicationStates.submitted.name or
                # Owners have also the right to move the record from submitted
                # to draft again.
                self.deposit['publication_state'] == PublicationStates.submitted.name and
                new_deposit['publication_state'] == PublicationStates.draft.name):
                # Owners are allowed to update
                for owner_id in self.deposit['_deposit']['owners']:
                    state_permission.explicit_needs.add(UserNeed(owner_id))
            permissions.append(state_permission)

        # Create permission for updating generic metadata fields.
        # Only superadmin can modify published draft.
        if self.deposit['publication_state'] != 'published':
            new_state = new_deposit['publication_state']
            # Check if any metadata has been changed
            del new_deposit['publication_state']
            original_metadata = deepcopy(self.deposit)
            del original_metadata['publication_state']
            if original_metadata != new_deposit:
                permissions.append(
                    UpdateDepositMetadataPermission(self.deposit, new_state)
                )

            if external_pids_changed:
                permissions.append(
                    DepositFilesPermission(self.deposit, 'bucket-update')
                )

        if len(permissions) > 1:
            self.permissions.add(AndPermissions(*permissions))
        elif len(permissions) == 1:
            self.permissions.add(permissions[0])
        elif len(permissions) == 0:
            # Avoid forbidding requests doing nothing. This can be useful if
            # a script replays an action.
            self.permissions.add(
                UpdateDepositMetadataPermission(
                    self.deposit, new_deposit['publication_state']
                )
            )