コード例 #1
0
def test_valid_get_community_schema(app, test_communities):
    """Test VALID community get request (GET .../communities/<id>)."""
    with app.app_context():
        community_id = str(test_communities['MyTestCommunity1'])
        with app.test_client() as client:
            for version in [0, 1, 'last']:
                headers = [('Content-Type', 'application/json'),
                           ('Accept', 'application/json')]
                res = client.get(
                    url_for('b2share_schemas.community_schema_item',
                            community_id=community_id,
                            schema_version_nb=version),
                    headers=headers)
                assert res.status_code == 200
                # check that the returned community matches the given data
                response_data = json.loads(res.get_data(as_text=True))
                if isinstance(version, int):
                    expected = CommunitySchema.get_community_schema(
                        community_id, version)
                elif version == 'last':
                    expected = CommunitySchema.get_community_schema(
                        community_id)
                else:
                    raise NotImplementedError('Test not implemented')
                assert (expected.build_json_schema() ==
                        response_data['json_schema'])
                assert response_data['community'] == community_id
                assert response_data['version'] == expected.version

    with app.app_context():
        with app.test_client() as client:
            # check that the returned self link returns the same data
            subtest_self_link(response_data, res.headers, client)
コード例 #2
0
def test_valid_get_community_schema(app, test_communities):
    """Test VALID community get request (GET .../communities/<id>)."""
    with app.app_context():
        community_id = str(test_communities['MyTestCommunity1'])
        with app.test_client() as client:
            for version in [0, 1, 'last']:
                headers = [('Content-Type', 'application/json'),
                           ('Accept', 'application/json')]
                res = client.get(url_for(
                    'b2share_schemas.community_schema_item',
                    community_id=community_id,
                    schema_version_nb=version),
                                 headers=headers)
                assert res.status_code == 200
                # check that the returned community matches the given data
                response_data = json.loads(res.get_data(as_text=True))
                if isinstance(version, int):
                    expected = CommunitySchema.get_community_schema(
                        community_id, version)
                elif version == 'last':
                    expected = CommunitySchema.get_community_schema(
                        community_id)
                else:
                    raise NotImplementedError('Test not implemented')
                assert (expected.build_json_schema() ==
                        response_data['json_schema'])
                assert response_data['community'] == community_id
                assert response_data['version'] == expected.version

    with app.app_context():
        with app.test_client() as client:
            # check that the returned self link returns the same data
            subtest_self_link(response_data, res.headers, client)
コード例 #3
0
 def validate(self, **kwargs):
     if ('publication_state' in self
             and self['publication_state'] == PublicationStates.draft.name):
         if 'community' not in self:
             raise ValidationError('Missing required field "community"')
         try:
             community_id = uuid.UUID(self['community'])
         except (ValueError, KeyError) as e:
             raise InvalidDepositError('Community ID is not a valid UUID.') \
                 from e
         default_validator = validator_for(
             CommunitySchema.get_community_schema(
                 community_id).build_json_schema())
         if 'required' not in default_validator.VALIDATORS:
             raise NotImplementedError('B2Share does not support schemas '
                                       'which have no "required" keyword.')
         DraftDepositValidator = type(
             'DraftDepositValidator', (default_validator, ),
             dict(VALIDATORS=copy.deepcopy(default_validator.VALIDATORS)))
         # function ignoring the validation of the given keyword
         ignore = lambda *args, **kwargs: None
         DraftDepositValidator.VALIDATORS['required'] = ignore
         DraftDepositValidator.VALIDATORS['minItems'] = ignore
         kwargs['validator'] = DraftDepositValidator
     return super(Deposit, self).validate(**kwargs)
コード例 #4
0
def community_to_dict(community):
    ret = dict(id=community.id,
               name=community.name,
               description=community.description,
               logo=community.logo,
               created=community.created,
               updated=community.updated,
               publication_workflow=community.publication_workflow,
               restricted_submission=community.restricted_submission,
               links=dict(self=community_self_link(community,
                                                   _external=True), ),
               roles=dict(
                   admin=dict(id=community.admin_role.id,
                              name=community.admin_role.name,
                              description=community.admin_role.description),
                   member=dict(id=community.member_role.id,
                               name=community.member_role.name,
                               description=community.member_role.description),
               ))
    try:
        community_schema = CommunitySchema.get_community_schema(community.id)
        community_schema_dict = json.loads(community_schema.community_schema)
        ret['links']['schema'] = community_schema_json_schema_link(
            community_schema, _external=True)
        ret['links']['schemas'] = community_schema_json_schemas_link(
            community_schema, _external=True)
        ret['schema'] = dict(version=community_schema.version,
                             root_schema=community_schema.root_schema)
        props = community_schema_dict.get('properties', {})
        if props:
            ret['links']['block_schema'] = next(iter(props.values()))['$ref']
            ret['schema']['block_schema_id'] = next(iter(props))
    finally:
        return ret
コード例 #5
0
ファイル: api.py プロジェクト: EUDAT-B2SHARE/b2share
 def validate(self, **kwargs):
     if ('publication_state' in self and
             self['publication_state'] == PublicationStates.draft.name):
         if 'community' not in self:
             raise ValidationError('Missing required field "community"')
         try:
             community_id = uuid.UUID(self['community'])
         except (ValueError, KeyError) as e:
             raise InvalidDepositError('Community ID is not a valid UUID.') \
                 from e
         default_validator = validator_for(
             CommunitySchema.get_community_schema(community_id).build_json_schema())
         if 'required' not in default_validator.VALIDATORS:
             raise NotImplementedError('B2Share does not support schemas '
                                       'which have no "required" keyword.')
         DraftDepositValidator = type(
             'DraftDepositValidator',
             (default_validator,),
             dict(VALIDATORS=copy.deepcopy(default_validator.VALIDATORS))
         )
         # function ignoring the validation of the given keyword
         ignore = lambda *args, **kwargs: None
         DraftDepositValidator.VALIDATORS['required'] = ignore
         DraftDepositValidator.VALIDATORS['minItems'] = ignore
         kwargs['validator'] = DraftDepositValidator
     return super(Deposit, self).validate(**kwargs)
コード例 #6
0
def test_new_deposit_versions_preserve_schema(app, test_records, test_users):
    """Creating new versions of existing records."""
    with app.app_context():
        # Retrieve a record which will be the first version, and its deposit
        v1_rec = B2ShareRecord.get_record(test_records[0].record_id)
        _, v1_id = pid_of(test_records[0].data)

        # update the community's schema
        community_id = v1_rec.model.json['community']
        old_schema = CommunitySchema.get_community_schema(community_id)
        json_schema = json.loads(old_schema.model.community_schema)
        new_schema = CommunitySchema.create_version(community_id, json_schema)
        assert new_schema.version > old_schema.version

        # create new, unversioned, draft and records
        data = copy_data_from_previous(v1_rec.model.json)
        unver_dep = create_deposit(data, test_users['deposits_creator'])
        unver_dep.submit()
        unver_dep.publish()
        _, unver_rec = unver_dep.fetch_published()

        # the unversioned draft or record in a version chain have the updated schema
        assert unver_dep['$schema'] != Deposit._build_deposit_schema(
            v1_rec.model.json)
        assert unver_rec.model.json['$schema'] != v1_rec.model.json['$schema']

        # create new draft and record in the version chain of v1
        data = copy_data_from_previous(v1_rec.model.json)
        v2_dep = create_deposit(data,
                                test_users['deposits_creator'],
                                version_of=v1_id)
        v2_dep.submit()
        v2_dep.publish()
        _, v2_rec = v2_dep.fetch_published()

        # the new draft and record in a version chain preserve the version of the schema
        assert v2_dep['$schema'] == Deposit._build_deposit_schema(
            v1_rec.model.json)
        assert v2_rec.model.json['$schema'] == v1_rec.model.json['$schema']
コード例 #7
0
ファイル: api.py プロジェクト: llehtine/b2share
    def create(cls, data, id_=None):
        """Create a deposit."""
        # check that the status field is not set
        if 'publication_state' in data:
            raise InvalidDepositError(
                'Field "publication_state" cannot be set.')
        data['publication_state'] = PublicationStates.draft.name
        # Set record's schema
        if '$schema' in data:
            raise InvalidDepositError('"$schema" field should not be set.')
        if 'community' not in data or not data['community']:
            raise ValidationError(
                'Record\s metadata has no community field.')
        try:
            community_id = uuid.UUID(data['community'])
        except ValueError as e:
            raise InvalidDepositError(
                'Community ID is not a valid UUID.') from e
        try:
            schema = CommunitySchema.get_community_schema(community_id)
        except CommunitySchemaDoesNotExistError as e:
            raise InvalidDepositError(
                'No schema for community {}.'.format(community_id)) from e

        from b2share.modules.schemas.serializers import \
            community_schema_draft_json_schema_link
        data['$schema'] = community_schema_draft_json_schema_link(
            schema,
            _external=True
        )
        deposit = super(Deposit, cls).create(data, id_=id_)

        # create file bucket
        bucket = deposit._create_bucket()
        db.session.add(bucket)
        db.session.add(RecordsBuckets(
            record_id=deposit.id, bucket_id=bucket.id
        ))

        return deposit
コード例 #8
0
    def create(cls, data, id_=None, version_of=None):
        """Create a deposit with the optional id.

        :params version_of: PID of an existing record. If set, the new record
        will be marked as a new version of this referenced record. If no data
        is provided the new record will be a copy of this record. Note: this
        PID must reference the current last version of a record.
        """

        # check that the status field is not set
        if 'publication_state' in data:
            raise InvalidDepositError(
                'Field "publication_state" cannot be set.')
        data['publication_state'] = PublicationStates.draft.name
        # Set record's schema
        if '$schema' in data:
            raise InvalidDepositError('"$schema" field should not be set.')

        # Retrieve reserved record PID which should have already been created
        # by the deposit minter (The record PID value is the same
        # as the one of the deposit)
        rec_pid = RecordUUIDProvider.get(data['_deposit']['id']).pid
        version_master, prev_version = None, None
        # if this is a new version of an existing record, add the future
        # record pid in the chain of versions.
        if version_of:
            version_master, prev_version = \
                find_version_master_and_previous_record(version_of)
            # The new version must be in the same community
            if data['community'] != prev_version['community']:
                raise ValidationError(
                    'The community field cannot change between versions.')
            try:
                version_master.insert_draft_child(rec_pid)
            except Exception as exc:
                # Only one draft is allowed per version chain.
                if 'Draft child already exists for this relation' in \
                        exc.args[0]:
                    raise DraftExistsVersioningError(
                        version_master.draft_child
                    )
                raise exc
        else:
            # create parent PID
            parent_pid = RecordUUIDProvider.create().pid
            version_master = PIDNodeVersioning(parent=parent_pid)
            version_master.insert_draft_child(child=rec_pid)

        # Mint the deposit with the parent PID
        data['_pid'] = [{
            'value': version_master.parent.pid_value,
            'type': RecordUUIDProvider.parent_pid_type,
        }]
        if 'community' not in data or not data['community']:
            raise ValidationError(
                'Record\s metadata has no community field.')
        try:
            community_id = uuid.UUID(data['community'])
        except ValueError as e:
            raise InvalidDepositError(
                'Community ID is not a valid UUID.') from e
        try:
            schema = CommunitySchema.get_community_schema(community_id)
        except CommunitySchemaDoesNotExistError as e:
            raise InvalidDepositError(
                'No schema for community {}.'.format(community_id)) from e

        if version_of:
            data['$schema'] = Deposit._build_deposit_schema(prev_version)
        else:
            from b2share.modules.schemas.serializers import \
                community_schema_draft_json_schema_link
            data['$schema'] = community_schema_draft_json_schema_link(
                schema,
                _external=True
            )

        # create file bucket
        if prev_version and prev_version.files:
            # Clone the bucket from the previous version. This doesn't
            # duplicate files.
            bucket = prev_version.files.bucket.snapshot(lock=False)
            bucket.locked = False
        else:
            bucket = Bucket.create(storage_class=current_app.config[
                'DEPOSIT_DEFAULT_STORAGE_CLASS'
            ])

        if 'external_pids' in data:
            create_b2safe_file(data['external_pids'], bucket)
            del data['external_pids']

        deposit = super(Deposit, cls).create(data, id_=id_)
        db.session.add(bucket)
        db.session.add(RecordsBuckets(
            record_id=deposit.id, bucket_id=bucket.id
        ))

        return deposit
コード例 #9
0
def test_new_community_set_schema_cmd(app, login_user, tmp_location):
    """Test adding a community and setting its schema using CLI commands."""
    with app.app_context():
        tmp_location.default = True
        db.session.merge(tmp_location)
        db.session.commit()

        runner = CliRunner()
        script_info = ScriptInfo(create_app=lambda info: app)
        comm_name = 'MyCom'

        # Create a new community on the command line
        args = ['create', comm_name, 'MyCom description', 'eudat.png']
        result = runner.invoke(communities_cmd, args, obj=script_info)
        assert result.exit_code == 0
        community = Community.get(name=comm_name)
        assert community
        assert community.name == comm_name

        # Create a schema for this new community
        with runner.isolated_filesystem():
            with open("schema.json", "w") as f:
                f.write(json.dumps(test_schema))

            # check RootSchemaDoesNotExistError
            with pytest.raises(RootSchemaDoesNotExistError):
                update_or_set_community_schema(comm_name, 'schema.json')

            # check RootSchemaDoesNotExistError via cli
            args = ['set_schema', comm_name, 'schema.json']
            result = runner.invoke(communities_cmd, args, obj=script_info)
            assert result.exit_code != 0

            # initialize the root schema in the test environment
            result = runner.invoke(schemas_cmd,
                                   ['init', '--ignore-mismatches'],
                                   obj=script_info)
            assert result.exit_code == 0

            # Make custom schema via cli
            args = ['set_schema', comm_name, 'schema.json']
            result = runner.invoke(communities_cmd, args, obj=script_info)
            assert result.exit_code == 0

        community_name = 'MyCom'
        community = Community.get(name=community_name)

        # Get the block schema id
        community_schema = CommunitySchema.get_community_schema(
            community.id).community_schema
        props = json.loads(community_schema).get('properties')
        assert len(props) == 1
        block_schema_id = props.popitem()[0]

        # Test the community schema by publishing a record
        with app.test_client() as client:
            user = create_user('allowed')
            login_user(user, client)

            record_data = {
                'titles': [{
                    'title': 'My Test Record'
                }],
                'community': str(community.id),
                'open_access': True,
                'community_specific': {
                    block_schema_id: {
                        'test_field1': "string value",
                        'test_field2': 10,
                    }
                },
            }

            headers = [('Content-Type', 'application/json'),
                       ('Accept', 'application/json')]
            draft_res = client.post(url_for('b2share_records_rest.b2rec_list'),
                                    data=json.dumps(record_data),
                                    headers=headers)
            draft_data = json.loads(draft_res.get_data(as_text=True))
            assert draft_res.status_code == 201

            headers = [('Content-Type', 'application/json-patch+json'),
                       ('Accept', 'application/json')]
            draft_submit_res = client.patch(url_for(
                'b2share_deposit_rest.b2dep_item', pid_value=draft_data['id']),
                                            data=json.dumps([{
                                                "op":
                                                "replace",
                                                "path":
                                                "/publication_state",
                                                "value":
                                                "submitted",
                                            }]),
                                            headers=headers)
            assert draft_submit_res.status_code == 200
コード例 #10
0
def test_new_community_set_schema_cmd(app, login_user, tmp_location):
    """Test adding a community and setting its schema using CLI commands."""
    with app.app_context():
        tmp_location.default = True
        db.session.merge(tmp_location)
        db.session.commit()

        runner = CliRunner()
        script_info = ScriptInfo(create_app=lambda info: app)
        comm_name = 'MyCom'

        # Create a new community on the command line
        args = ['create', comm_name, 'MyCom description', 'eudat.png']
        result = runner.invoke(communities_cmd, args, obj=script_info)
        assert result.exit_code == 0
        community = Community.get(name=comm_name)
        assert community
        assert community.name == comm_name

        # Create a schema for this new community
        with runner.isolated_filesystem():
            with open("schema.json", "w") as f:
                f.write(json.dumps(test_schema))

            # check RootSchemaDoesNotExistError
            with pytest.raises(RootSchemaDoesNotExistError):
                update_or_set_community_schema(comm_name, 'schema.json')

            # check RootSchemaDoesNotExistError via cli
            args = ['set_schema', comm_name, 'schema.json']
            result = runner.invoke(communities_cmd, args, obj=script_info)
            assert result.exit_code != 0

            # initialize the root schema in the test environment
            result = runner.invoke(schemas_cmd, ['init'], obj=script_info)
            assert result.exit_code == 0

            # Make custom schema via cli
            args = ['set_schema', comm_name, 'schema.json']
            result = runner.invoke(communities_cmd, args, obj=script_info)
            assert result.exit_code == 0

        community_name = 'MyCom'
        community = Community.get(name=community_name)

        # Get the block schema id
        community_schema = CommunitySchema.get_community_schema(
            community.id).community_schema
        props = json.loads(community_schema).get('properties')
        assert len(props) == 1
        block_schema_id = props.popitem()[0]

        # Test the community schema by publishing a record
        with app.test_client() as client:
            user = create_user('allowed')
            login_user(user, client)

            record_data = {
                'titles': [{'title':'My Test Record'}],
                'community': str(community.id),
                'open_access': True,
                'community_specific': {
                    block_schema_id: {
                        'test_field1': "string value",
                        'test_field2': 10,
                    }
                },
            }

            headers = [('Content-Type', 'application/json'),
                       ('Accept', 'application/json')]
            draft_res = client.post(url_for('b2share_records_rest.b2rec_list'),
                                    data=json.dumps(record_data),
                                    headers=headers)
            draft_data = json.loads(draft_res.get_data(as_text=True))
            assert draft_res.status_code == 201

            headers = [('Content-Type', 'application/json-patch+json'),
                       ('Accept', 'application/json')]
            draft_submit_res = client.patch(
                url_for('b2share_deposit_rest.b2dep_item',
                        pid_value=draft_data['id']),
                data=json.dumps([{
                    "op": "replace",
                    "path": "/publication_state",
                    "value": "submitted",
                }]),
                headers=headers)
            assert draft_submit_res.status_code == 200
コード例 #11
0
ファイル: api.py プロジェクト: EUDAT-B2SHARE/b2share
    def create(cls, data, id_=None, version_of=None):
        """Create a deposit with the optional id.

        :params version_of: PID of an existing record. If set, the new record
        will be marked as a new version of this referenced record. If no data
        is provided the new record will be a copy of this record. Note: this
        PID must reference the current last version of a record.
        """

        # check that the status field is not set
        if 'publication_state' in data:
            raise InvalidDepositError(
                'Field "publication_state" cannot be set.')
        data['publication_state'] = PublicationStates.draft.name
        # Set record's schema
        if '$schema' in data:
            raise InvalidDepositError('"$schema" field should not be set.')

        # Retrieve reserved record PID which should have already been created
        # by the deposit minter (The record PID value is the same
        # as the one of the deposit)
        rec_pid = RecordUUIDProvider.get(data['_deposit']['id']).pid
        version_master, prev_version = None, None
        # if this is a new version of an existing record, add the future
        # record pid in the chain of versions.
        if version_of:
            version_master, prev_version = \
                find_version_master_and_previous_record(version_of)
            # The new version must be in the same community
            if data['community'] != prev_version['community']:
                raise ValidationError(
                    'The community field cannot change between versions.')
            try:
                version_master.insert_draft_child(rec_pid)
            except Exception as exc:
                # Only one draft is allowed per version chain.
                if 'Draft child already exists for this relation' in \
                        exc.args[0]:
                    raise DraftExistsVersioningError(
                        version_master.draft_child
                    )
                raise exc
        else:
            # create parent PID
            parent_pid = RecordUUIDProvider.create().pid
            version_master = PIDVersioning(parent=parent_pid)
            version_master.insert_draft_child(child=rec_pid)

        # Mint the deposit with the parent PID
        data['_pid'] = [{
            'value': version_master.parent.pid_value,
            'type': RecordUUIDProvider.parent_pid_type,
        }]
        if 'community' not in data or not data['community']:
            raise ValidationError(
                'Record\s metadata has no community field.')
        try:
            community_id = uuid.UUID(data['community'])
        except ValueError as e:
            raise InvalidDepositError(
                'Community ID is not a valid UUID.') from e
        try:
            schema = CommunitySchema.get_community_schema(community_id)
        except CommunitySchemaDoesNotExistError as e:
            raise InvalidDepositError(
                'No schema for community {}.'.format(community_id)) from e

        if version_of:
            data['$schema'] = Deposit._build_deposit_schema(prev_version)
        else:
            from b2share.modules.schemas.serializers import \
                community_schema_draft_json_schema_link
            data['$schema'] = community_schema_draft_json_schema_link(
                schema,
                _external=True
            )

        # create file bucket
        if prev_version and prev_version.files:
            # Clone the bucket from the previous version. This doesn't
            # duplicate files.
            bucket = prev_version.files.bucket.snapshot(lock=False)
            bucket.locked = False
        else:
            bucket = Bucket.create(storage_class=current_app.config[
                'DEPOSIT_DEFAULT_STORAGE_CLASS'
            ])

        if 'external_pids' in data:
            create_b2safe_file(data['external_pids'], bucket)
            del data['external_pids']

        deposit = super(Deposit, cls).create(data, id_=id_)
        db.session.add(bucket)
        db.session.add(RecordsBuckets(
            record_id=deposit.id, bucket_id=bucket.id
        ))

        return deposit