From a1c1e548d9f370b4639c16d1cf41d4e578e6093c Mon Sep 17 00:00:00 2001 From: Emanuel Dima Date: Tue, 28 Mar 2017 12:15:32 +0200 Subject: [PATCH] improve record cli command to handle unregistered dois --- b2share/modules/records/cli.py | 56 ++++++++++--- .../test_record_cli.py | 82 +++++++++++++++++++ 2 files changed, 127 insertions(+), 11 deletions(-) create mode 100644 tests/b2share_functional_tests/test_record_cli.py diff --git a/b2share/modules/records/cli.py b/b2share/modules/records/cli.py index d0113552f3..9001787fce 100644 --- a/b2share/modules/records/cli.py +++ b/b2share/modules/records/cli.py @@ -28,10 +28,12 @@ import click from flask_cli import with_appcontext +import requests from invenio_db import db from invenio_pidstore.models import PIDStatus from invenio_pidstore.providers.datacite import DataCiteProvider +from invenio_records_files.api import Record from b2share.modules.records.serializers import datacite_v31 from b2share.modules.records.minters import make_record_url @@ -46,16 +48,6 @@ def b2records(): """B2SHARE Records commands.""" -@b2records.command() -@with_appcontext -@click.option('-u', '--update', is_flag=True, default=False) -def check_dois(update): - """ Checks that all DOIs of records in the current instance are registered. - """ - for record in list_db_published_records(): - check_record_doi(record, update) - - @b2records.command() @with_appcontext def update_expired_embargoes(): @@ -64,6 +56,25 @@ def update_expired_embargoes(): click.secho('Expiring embargoes...', fg='green') +@b2records.command() +@with_appcontext +@click.option('-r', '--record', default=None) +@click.option('-a', '--allrecords', is_flag=True, default=False) +@click.option('-u', '--update', is_flag=True, default=False) +def check_dois(record, allrecords, update): + """ Checks that DOIs of records in the current instance are registered. + """ + if record: + record = Record.get_record(record) + check_record_doi(record, update) + elif allrecords: + click.secho('checking DOI for all records') + for record in list_db_published_records(): + check_record_doi(record, update) + else: + raise click.ClickException('Either -r or -a option must be selected') + + def check_record_doi(record, update=False): """ Checks that the DOI of a record is registered.""" recid = record.get('_deposit', {}).get('id') @@ -72,16 +83,39 @@ def check_record_doi(record, update=False): for d in record['_pid'] if d.get('type') == 'DOI'] for doi in doi_list: + if _datacite_doi_reference(doi.pid.pid_value) is None: + if doi.pid.status == PIDStatus.REGISTERED: + # the doi is not truly registered with datacite + click.secho(' {}: not registered with datacite'.format( + doi.pid.pid_value)) + doi.pid.status = PIDStatus.RESERVED + click.secho(' {}: {}'.format(doi.pid.pid_value, doi.pid.status)) if doi.pid.status != PIDStatus.RESERVED: continue # RESERVED but not REGISTERED if update: + recid = record.get('_deposit', {}).get('id') url = make_record_url(recid) doc = datacite_v31.serialize(doi.pid, record) - doi.register(url=url, doc=doc) + _datacite_register_doi(doi, url, doc) db.session.commit() click.secho(' registered just now', fg='green', bold=True) else: click.secho(' not registered', fg='red', bold=True) + + +def _datacite_doi_reference(doi_value): + url = "http://doi.org/" + doi_value + res = requests.get(url, allow_redirects=False) + if res.status_code < 200 or res.status_code >= 400: + click.secho(' doi.org returned code {} for {}'.format( + res.status_code, doi_value)) + return None + return res.headers['Location'] + + + +def _datacite_register_doi(doi, url, doc): + doi.register(url=url, doc=doc) diff --git a/tests/b2share_functional_tests/test_record_cli.py b/tests/b2share_functional_tests/test_record_cli.py new file mode 100644 index 0000000000..7e99a5c48d --- /dev/null +++ b/tests/b2share_functional_tests/test_record_cli.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +# +# This file is part of EUDAT B2Share. +# Copyright (C) 2017 SurfSara, University of Tübingen +# +# B2Share is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# B2Share is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with B2Share; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + +"""Test B2Share records cli module.""" +from __future__ import absolute_import, print_function + +from unittest.mock import patch, DEFAULT +from click.testing import CliRunner +from flask_cli import ScriptInfo + +import b2share.modules.records.cli as records_cli + +headers = [('Content-Type', 'application/json'), + ('Accept', 'application/json')] +patch_headers = [('Content-Type', 'application/json-patch+json'), + ('Accept', 'application/json')] + +def test_record_doi_cli(app, test_community, test_records, login_user): + """Test checking a record's DOI using CLI commands.""" + with app.app_context(): + _test_record_doi_cli(app, test_community, test_records) + +@patch.multiple('b2share.modules.records.cli', + _datacite_doi_reference=DEFAULT, + _datacite_register_doi=DEFAULT) +def _test_record_doi_cli(app, test_community, test_records, + _datacite_doi_reference, _datacite_register_doi): + _datacite_doi_reference.return_value = None + + runner = CliRunner() + script_info = ScriptInfo(create_app=lambda info: app) + + doi_prefix = app.config['PIDSTORE_DATACITE_DOI_PREFIX'] + "/b2share." + + def call_doi_cli_command(args): + nonlocal _datacite_doi_reference + nonlocal _datacite_register_doi + _datacite_doi_reference.reset_mock() + _datacite_register_doi.reset_mock() + result = runner.invoke(records_cli.check_dois, args, obj=script_info) + if result.exit_code != 0: + print(result.output) + assert result.exit_code == 0 + + # Run 'check_record_doi' command for all each record in turn + for record in test_records: + doi = doi_prefix + record.pid + call_doi_cli_command(['-r', record.pid]) + _datacite_doi_reference.assert_called_with(doi) + _datacite_register_doi.assert_not_called() + + call_doi_cli_command(['-r', record.pid, '-u']) + _datacite_doi_reference.assert_called_with(doi) + assert _datacite_register_doi.call_args[0][1].endswith(record.pid) + + + # Run 'check_record_doi' command for all records + call_doi_cli_command(['-a']) + for i, record in enumerate(test_records): + assert _datacite_doi_reference.call_args_list[i][0] == (doi_prefix + record.pid,) + _datacite_register_doi.assert_not_called() + + call_doi_cli_command(['-a', '-u']) + for i, record in enumerate(test_records): + assert _datacite_doi_reference.call_args_list[i][0] == (doi_prefix + record.pid,) + assert _datacite_register_doi.call_args_list[i][0][1].endswith(record.pid)