예제 #1
0
def b2share_deposit_uuid_minter(record_uuid, data):
    """Mint deposit's PID."""
    dep_pid = DepositUUIDProvider.create(
        object_type='rec', object_uuid=record_uuid,
        # we reuse the deposit UUID as PID value. This makes the demo easier.
        pid_value=record_uuid.hex
    )

    # this change is done to keep the external_pids info for the new versions
    if '_deposit' in data and 'external_pids' in data['_deposit']:
        data['_deposit'].update({
            'id': dep_pid.pid.pid_value,
            # FIXME: do not set the status once it is done by invenio-deposit API
            'status': 'draft',
        })
    else:
        data['_deposit'] = {
            'id': dep_pid.pid.pid_value,
            # FIXME: do not set the status once it is done by invenio-deposit API
            'status': 'draft',
        }

    # reserve the record PID
    RecordUUIDProvider.create(
        object_type='rec',
        pid_value=dep_pid.pid.pid_value
    )

    return dep_pid.pid
예제 #2
0
def b2share_deposit_uuid_minter(record_uuid, data):
    """Mint deposit's PID."""
    dep_pid = DepositUUIDProvider.create(
        object_type='rec', object_uuid=record_uuid,
        # we reuse the deposit UUID as PID value. This makes the demo easier.
        pid_value=record_uuid.hex
    )

    # this change is done to keep the external_pids info for the new versions
    if '_deposit' in data and 'external_pids' in data['_deposit']:
        data['_deposit'].update({
            'id': dep_pid.pid.pid_value,
            # FIXME: do not set the status once it is done by invenio-deposit API
            'status': 'draft',
        })
    else:
        data['_deposit'] = {
            'id': dep_pid.pid.pid_value,
            # FIXME: do not set the status once it is done by invenio-deposit API
            'status': 'draft',
        }

    from b2share.modules.records.providers import RecordUUIDProvider

    # reserve the record PID
    RecordUUIDProvider.create(
        object_type='rec',
        pid_value=dep_pid.pid.pid_value
    )

    return dep_pid.pid
예제 #3
0
def b2share_deposit_uuid_minter(record_uuid, data):
    """Mint deposit's PID."""
    dep_pid = DepositUUIDProvider.create(
        object_type='rec', object_uuid=record_uuid,
        # we reuse the deposit UUID as PID value. This makes the demo easier.
        pid_value=record_uuid.hex
    )

    data['_deposit'] = {
        'id': dep_pid.pid.pid_value,
        # FIXME: do not set the status once it is done by invenio-deposit API
        'status': 'draft',
    }

    # reserve the record PID
    RecordUUIDProvider.create(
        object_type='rec',
        pid_value=dep_pid.pid.pid_value
    )

    return dep_pid.pid
def alembic_upgrade_database_data(alembic, verbose):
    """Migrate the database data from v2.0.0 to 2.1.0."""
    ### Add versioning PIDs ###
    # Reserve the record PID and versioning PID for unpublished deposits

    # Hack: disable record indexing during record migration
    from invenio_indexer.api import RecordIndexer
    old_index_fn = RecordIndexer.index
    RecordIndexer.index = lambda s, record: None

    if verbose:
        click.secho('migrating deposits and records...')
    with db.session.begin_nested():
        # Migrate published records
        records_pids = PersistentIdentifier.query.filter(
            PersistentIdentifier.pid_type == RecordUUIDProvider.pid_type,
            PersistentIdentifier.status == PIDStatus.REGISTERED,
        ).all()
        for rec_pid in records_pids:
            if verbose:
                click.secho('    record {}'.format(rec_pid.pid_value))
            try:
                record = Record.get_record(rec_pid.object_uuid)
            except NoResultFound:
                # The record is deleted but not the PID. Fix it.
                rec_pid.status = PIDStatus.DELETED
                continue
            # Create parent version PID
            parent_pid = RecordUUIDProvider.create().pid
            version_master = PIDVersioning(parent=parent_pid)
            version_master.insert_draft_child(child=rec_pid)
            version_master.update_redirect()
            migrate_record_metadata(
                Record.get_record(rec_pid.object_uuid),
                parent_pid
            )

        # Migrate deposits
        deposit_pids = PersistentIdentifier.query.filter(
            PersistentIdentifier.pid_type == DepositUUIDProvider.pid_type,
            PersistentIdentifier.status == PIDStatus.REGISTERED,
        ).all()
        for dep_pid in deposit_pids:
            if verbose:
                click.secho('    deposit {}'.format(dep_pid.pid_value))
            try:
                deposit = Deposit.get_record(dep_pid.object_uuid)

                if deposit['publication_state'] != \
                        PublicationStates.published.name:
                    # The record is not published yet. Reserve the PID.
                    rec_pid = RecordUUIDProvider.create(
                        object_type='rec',
                        pid_value=dep_pid.pid_value,
                    ).pid
                    # Create parent version PID
                    parent_pid = RecordUUIDProvider.create().pid
                    assert parent_pid
                    version_master = PIDVersioning(parent=parent_pid)
                    version_master.insert_draft_child(child=rec_pid)
                else:
                    # Retrieve previously created version PID
                    rec_pid = RecordUUIDProvider.get(dep_pid.pid_value).pid
                    version_master = PIDVersioning(child=rec_pid)
                    parent_pid = version_master.parent
                    if not parent_pid:
                        click.secho('    record {} was deleted, but the deposit has not been removed'.format(rec_pid.pid_value), fg='red')

                if parent_pid:
                    migrate_record_metadata(
                        Deposit.get_record(dep_pid.object_uuid),
                        parent_pid
                    )
            except NoResultFound:
                # The deposit is deleted but not the PID. Fix it.
                dep_pid.status = PIDStatus.DELETED


    if verbose:
        click.secho('done migrating deposits.')
    RecordIndexer.index = old_index_fn
예제 #5
0
def alembic_upgrade_database_data(alembic, verbose):
    """Migrate the database data from v2.0.0 to 2.1.0."""
    ### Add versioning PIDs ###
    # Reserve the record PID and versioning PID for unpublished deposits

    # Hack: disable record indexing during record migration
    from invenio_indexer.api import RecordIndexer
    old_index_fn = RecordIndexer.index
    RecordIndexer.index = lambda s, record: None

    if verbose:
        click.secho('migrating deposits and records...')
    with db.session.begin_nested():
        # Migrate published records
        records_pids = PersistentIdentifier.query.filter(
            PersistentIdentifier.pid_type == RecordUUIDProvider.pid_type,
            PersistentIdentifier.status == PIDStatus.REGISTERED,
        ).all()
        for rec_pid in records_pids:
            if verbose:
                click.secho('    record {}'.format(rec_pid.pid_value))
            try:
                record = Record.get_record(rec_pid.object_uuid)
            except NoResultFound:
                # The record is deleted but not the PID. Fix it.
                rec_pid.status = PIDStatus.DELETED
                continue
            # Create parent version PID
            parent_pid = RecordUUIDProvider.create().pid
            version_master = PIDVersioning(parent=parent_pid)
            version_master.insert_draft_child(child=rec_pid)
            version_master.update_redirect()
            migrate_record_metadata(Record.get_record(rec_pid.object_uuid),
                                    parent_pid)

        # Migrate deposits
        deposit_pids = PersistentIdentifier.query.filter(
            PersistentIdentifier.pid_type == DepositUUIDProvider.pid_type,
            PersistentIdentifier.status == PIDStatus.REGISTERED,
        ).all()
        for dep_pid in deposit_pids:
            if verbose:
                click.secho('    deposit {}'.format(dep_pid.pid_value))
            try:
                deposit = Deposit.get_record(dep_pid.object_uuid)

                if deposit['publication_state'] != \
                        PublicationStates.published.name:
                    # The record is not published yet. Reserve the PID.
                    rec_pid = RecordUUIDProvider.create(
                        object_type='rec',
                        pid_value=dep_pid.pid_value,
                    ).pid
                    # Create parent version PID
                    parent_pid = RecordUUIDProvider.create().pid
                    assert parent_pid
                    version_master = PIDVersioning(parent=parent_pid)
                    version_master.insert_draft_child(child=rec_pid)
                else:
                    # Retrieve previously created version PID
                    rec_pid = RecordUUIDProvider.get(dep_pid.pid_value).pid
                    version_master = PIDVersioning(child=rec_pid)
                    parent_pid = version_master.parent
                    if not parent_pid:
                        click.secho(
                            '    record {} was deleted, but the deposit has not been removed'
                            .format(rec_pid.pid_value),
                            fg='red')

                if parent_pid:
                    migrate_record_metadata(
                        Deposit.get_record(dep_pid.object_uuid), parent_pid)
            except NoResultFound:
                # The deposit is deleted but not the PID. Fix it.
                dep_pid.status = PIDStatus.DELETED

    if verbose:
        click.secho('done migrating deposits.')
    RecordIndexer.index = old_index_fn
예제 #6
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
예제 #7
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 = 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