Example #1
0
    def _create_record(data={}, published=True):
        data['$schema'] = (current_app.extensions['invenio-jsonschemas'].
                           path_to_url('records/record-v0.1.0.json'))
        _deposit = data.pop('_deposit', {})

        data_to_use = create_loaded_record(data)

        record = Deposit.create(data_to_use)

        # Have to modify `_deposit` content after the record is initially
        # created because `_deposit` is used to choose to mint or not
        if _deposit:
            for key, value in _deposit.items():
                record.model.json['_deposit'][key] = value
            db.session.add(record.model)

        if published:
            record.publish()
            pid, record = record.fetch_published()

        # Flush to index and database
        current_search.flush_and_refresh(index='*')
        db.session.commit()

        return record
Example #2
0
def test_fetch_deposit(create_record):
    unpublished_record = create_record(published=False)
    unpublished_record.publish()
    _, published_record = unpublished_record.fetch_published()

    _, deposit = Deposit.fetch_deposit(published_record)

    assert unpublished_record == deposit
Example #3
0
def test_deposit_publish_sets_appropriate_types(locations):
    deposit = Deposit.create({})

    deposit_record = deposit.publish()
    pid, published_record = deposit_record.fetch_published()

    assert deposit_record['type'] == RecordType.draft.value
    assert published_record['type'] == RecordType.published.value
Example #4
0
def test_deposit_create_creates_recordsbuckets(locations):
    assert RecordsBuckets.query.first() is None
    assert RecordMetadata.query.first() is None
    assert Bucket.query.first() is None

    deposit = Deposit.create({})

    record_bucket = RecordsBuckets.query.first()
    record = RecordMetadata.query.first()
    buckets = Bucket.query.all()
    assert record_bucket
    assert record_bucket.record == record
    assert record_bucket.bucket in buckets
Example #5
0
def test_register_doi_task_succeeds(
        config, create_record, patched_externalities):
    """Test successful doi task."""
    original_datacite_doi_prefix = config['PIDSTORE_DATACITE_DOI_PREFIX']
    config['PIDSTORE_DATACITE_DOI_PREFIX'] = '10.5072'
    original_doi_register_signals = config['DOI_REGISTER_SIGNALS']
    config['DOI_REGISTER_SIGNALS'] = False  # To be sure
    returned_doi = '10.5072/qwer-tyui'
    patched_client, patched_indexer = patched_externalities
    # NOTE: `create_record` does NOT trigger register_doi bc
    #       DOI_REGISTER_SIGNALS set to False
    record = create_record()
    doi_pid = PersistentIdentifier.get(pid_type='doi', pid_value=record['id'])

    register_doi(record['id'])

    # Validate proper usage of DataCite API
    assert patched_client.metadata_post.called_with(
        datacite_v41.serialize(doi_pid, record)
    )
    assert patched_client.doi_post.called_with(
        returned_doi,
        'https://localhost:5000/records/{}'.format(record['id'])
    )
    # Validate DOI update
    doi_pid = PersistentIdentifier.get(pid_type='doi', pid_value=returned_doi)
    assert doi_pid
    recid_pid, record = record_resolver.resolve(str(record['id']))
    depid_pid, deposit = Deposit.fetch_deposit(record)
    assert deposit['doi'] == returned_doi
    assert record['doi'] == returned_doi
    assert doi_pid.is_registered() and not doi_pid.is_new()
    # Validate indexing
    assert patched_indexer.index.called

    config['PIDSTORE_DATACITE_DOI_PREFIX'] = original_datacite_doi_prefix
    config['DOI_REGISTER_SIGNALS'] = original_doi_register_signals
Example #6
0
def test_deposit_create_fills_data(locations):
    data = {}

    deposit = Deposit.create(data)

    assert data['_buckets']['deposit']
Example #7
0
def register_doi(recid_pid_value):
    """External DOI registration task.

    This asynchronous task mints a DOI with the external service and
    stores it in the local doi PID. It will retry a `max_retries` number of
    times.

    If a new record is private, then the landing URL is not provided, so that
    the DOI is in 'draft' mode on DataCite.
    TODO: If an old public record is made private, remove its DOI from DataCite
          search. This is not a big need though since the DOI link will still
          resolve.

    Summary of states:

    'draft':
        * has a non-resolvable (no landing page) DOI
        * is not indexed in DataCite search
        * may not even have metadata
        * via MDS API: obtained by not assigning a landing page to a record

    'registered':
        * has a resolvable (landing page) DOI
        * has metadata
        * is indexed in DataCite search
        * via MDS API: obtained by API call on 'findable' record

    'findable':
        * has a resolvable (landing page) DOI
        * has metadata
        * is indexed in DataCite search
        * via MDS API: obtained by assigning a landing page to a record

    Refer to [DataCite states](https://support.datacite.org/docs/doi-states).

    `default_retry_delay` is in seconds.

    :param recid_pid_value: pid_value of recid-PID for the target record.
                            Note that this pid_value is also the pid_value of
                            the doi-PID associated with the target record if
                            it has not been DOI-minted yet.
    """
    try:
        recid_pid, record = record_resolver.resolve(str(recid_pid_value))
        depid_pid, deposit = Deposit.fetch_deposit(record)

        doi_pid_value = record.get('doi') or recid_pid_value
        doi_pid = PersistentIdentifier.get(pid_type='doi',
                                           pid_value=doi_pid_value)

        client = DataCiteMDSClient(
            username=current_app.config['PIDSTORE_DATACITE_USERNAME'],
            password=current_app.config['PIDSTORE_DATACITE_PASSWORD'],
            prefix=current_app.config['PIDSTORE_DATACITE_DOI_PREFIX'],
            test_mode=current_app.config['PIDSTORE_DATACITE_TESTMODE'],
            url=current_app.config['PIDSTORE_DATACITE_URL'])

        # Update DataCite metadata and let DataCite mint new DOI if unknown DOI
        serialized_record = datacite_v41.serialize(doi_pid, record)
        result = client.metadata_post(serialized_record)
        minted_doi = extract_doi(result)

        if not RecordPermissions.is_private(record):
            landing_url = url_for_record_ui_recid_external(recid_pid_value)
            client.doi_post(minted_doi, landing_url)

        # TODO: elif is private now, but previous version was not,
        #       make record 'registered' on DataCite.
        #       Dependent on versioning and PID status logic.

        if doi_pid.is_new():
            # Update doi_pid
            doi_pid.pid_value = minted_doi
            doi_pid.register()

            # Update deposit/record
            deposit['doi'] = minted_doi
            record['doi'] = minted_doi
            deposit.commit()
            record.commit()
            # The above only flushes (no db commit). The below is needed to
            # persist the changes to the db.
            db.session.commit()

            # Re-index deposit/record
            RecordIndexer().index(deposit)
            RecordIndexer().index(record)

    except (HttpError, DataCiteError) as e:
        register_doi.retry(exc=e)
    except RequestError:
        current_app.logger.exception('Could not index {}.'.format(record))
    except Exception as e:
        current_app.logger.exception(
            'Exception in register_doi for recid_pid_value: {}. Retrying...'.
            format(recid_pid_value))
        register_doi.retry(exc=e)