Skip to content

Commit

Permalink
Merge bad8667 into 98e48a4
Browse files Browse the repository at this point in the history
  • Loading branch information
lnielsen committed Jun 1, 2017
2 parents 98e48a4 + bad8667 commit 3a36f4a
Show file tree
Hide file tree
Showing 11 changed files with 419 additions and 34 deletions.
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
'zenodo_communities = zenodo.modules.communities.views:blueprint',
'zenodo_deposit = zenodo.modules.deposit.views:blueprint',
'zenodo_frontpage = zenodo.modules.frontpage.views:blueprint',
'zenodo_openaire = zenodo.modules.openaire.views:blueprint',
'zenodo_redirector = zenodo.modules.redirector.views:blueprint',
'zenodo_search_ui = zenodo.modules.search_ui.views:blueprint',
'zenodo_theme = zenodo.modules.theme.views:blueprint',
Expand Down
99 changes: 99 additions & 0 deletions tests/unit/openaire/test_openaire_helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
#
# This file is part of Zenodo.
# Copyright (C) 2017 CERN.
#
# Zenodo 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.
#
# Zenodo 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 Zenodo; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307, USA.
#
# In applying this license, CERN does not
# waive the privileges and immunities granted to it by virtue of its status
# as an Intergovernmental Organization or submit itself to any jurisdiction.

"""Test for OpenAIRE helpers."""

from __future__ import absolute_import, print_function

from zenodo.modules.openaire.helpers import openaire_id, openaire_link, \
openaire_type


def test_openire_type(app, minimal_record):
"""Test OpenAIRE type."""
r = minimal_record
# Default zenodo type is software which has no OpenAIRE type.
assert openaire_type(r) is None

# Datasets just map to datasets.
r['resource_type']['type'] = 'dataset'
assert openaire_type(r) == 'dataset'

# Open publications
r['resource_type']['type'] = 'publication'
assert openaire_type(r) == 'publication'

# Non-open publications
r['access_right'] = 'embargoed'
assert openaire_type(r) is None
# with grants
r['grants'] = [{'id': 'someid'}]
assert openaire_type(r) == 'publication'

# in ecfunded community
del r['grants']
r['communities'] = ['ecfunded']
assert openaire_type(r) == 'publication'
r['communities'] = ['zenodo']
assert openaire_type(r) is None


def test_openire_id(app, minimal_record):
"""Test OpenAIRE ID."""
r = minimal_record
r['doi'] = u'10.5281/zenodo.123'
r['_oai'] = {'id': u'oai:zenodo.org:123'}

# Default zenodo type is software which has no OpenAIRE type.
assert openaire_id(r) is None

# Dataset ID
r['resource_type']['type'] = 'dataset'
assert openaire_id(r) == 'r37b0ad08687::204007f516ddcf0a452c2f22d48695ca'

# Publication ID
r['resource_type']['type'] = 'publication'
assert openaire_id(r) == 'od______2659::47287d1800c112499a117ca17aa1909d'


def test_openire_link(app, minimal_record):
"""Test OpenAIRE ID."""
r = minimal_record
r['doi'] = u'10.5281/zenodo.123'
r['_oai'] = {'id': u'oai:zenodo.org:123'}

# Default zenodo type is software which has no OpenAIRE type.
assert openaire_link(r) is None

# Dataset ID
r['resource_type']['type'] = 'dataset'
assert openaire_link(r) == \
'https://beta.openaire.eu/search/dataset' \
'?datasetId=r37b0ad08687::204007f516ddcf0a452c2f22d48695ca'

# Publication ID
r['resource_type']['type'] = 'publication'
assert openaire_link(r) == \
'https://beta.openaire.eu/search/publication' \
'?articleId=od______2659::47287d1800c112499a117ca17aa1909d'
2 changes: 1 addition & 1 deletion tests/unit/records/test_schemas_openaire_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def test_resource_types(app, db, minimal_oai_record, recid_pid):
assert obj['originalId'] == 'oai:zenodo.org:123'
assert obj['collectedFromId'] == 'opendoar____::2659'
assert obj['hostedById'] == 'opendoar____::2659'
assert obj['resourceType'] == '0001'
assert obj['resourceType'] == '0004'
assert obj['type'] == 'publication'


Expand Down
10 changes: 5 additions & 5 deletions zenodo/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,20 +275,20 @@ def _(x):
OPENAIRE_SCHEMAS_HOST = 'zenodo.org'
#: Hostname for OpenAIRE's grant resolver.
OPENAIRE_JSONRESOLVER_GRANTS_HOST = 'dx.zenodo.org'
#: OpenAIRE Zenodo IDs
#: OpenAIRE data source IDs for Zenodo.
OPENAIRE_ZENODO_IDS = {
'publication': 'opendoar____::2659',
'dataset': 're3data_____::r3d100010468',
}
#: OpenAIRE Zenodo namespace prefixes
#: OpenAIRE ID namespace prefixes for Zenodo.
OPENAIRE_NAMESPACE_PREFIXES = {
'publication': 'od______2659',
'dataset': 'r37b0ad08687',
}
#: OpenAIRE API endpoint.
OPENAIRE_API_URL = 'https://beta.services.openaire.eu/is/mvc'
# TODO: Check if we are to use Dev or Beta endpoint...
# OPENAIRE_API_URL = 'http://dev.openaire.research-infrastructures.eu/is/mvc'
OPENAIRE_API_URL = 'http://dev.openaire.research-infrastructures.eu/is/mvc'
#: URL to OpenAIRE portal.
OPENAIRE_PORTAL_URL = 'https://beta.openaire.eu'

# OpenDefinition
# ==============
Expand Down
118 changes: 118 additions & 0 deletions zenodo/modules/openaire/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
#
# This file is part of Zenodo.
# Copyright (C) 2017 CERN.
#
# Zenodo 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.
#
# Zenodo 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 Zenodo; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307, USA.
#
# In applying this license, CERN does not
# waive the privileges and immunities granted to it by virtue of its status
# as an Intergovernmental Organization or submit itself to any jurisdiction.

"""OpenAIRE related helpers."""

from __future__ import absolute_import, print_function

import hashlib

from flask import current_app

from zenodo.modules.records.models import ObjectType


class _OAType(object):
"""OpenAIRE types."""

publication = 'publication'
dataset = 'dataset'


def is_openaire_publication(record):
"""Determine if record is a publication for OpenAIRE."""
oatype = ObjectType.get_by_dict(record.get('resource_type')).get(
'openaire', {})
if not oatype or oatype['type'] != _OAType.publication:
return False

# Has grants, is part of ecfunded community or is open access.
if record.get('grants') or 'ecfunded' in record.get('communities', []) or \
'open' == record.get('access_right'):
return True
return False


def is_openaire_dataset(record):
"""Determine if record is a dataset for OpenAIRE."""
oatype = ObjectType.get_by_dict(record.get('resource_type')).get(
'openaire', {})
return oatype and oatype['type'] == _OAType.dataset


def openaire_type(record):
"""Get the OpenAIRE type of a record."""
if is_openaire_publication(record):
return _OAType.publication
elif is_openaire_dataset(record):
return _OAType.dataset
return None


def openaire_id(record):
"""Compute the OpenAIRE identifier."""
return _openaire_id(record, openaire_type(record))


def _openaire_id(record, oatype):
"""Compute the OpenAIRE identifier."""
prefix, identifier = openaire_original_id(record, oatype)

if not identifier or not prefix:
return None

m = hashlib.md5()
m.update(identifier.encode('utf8'))

return '{}::{}'.format(prefix, m.hexdigest())


def openaire_original_id(record, oatype):
"""Original original identifier."""
prefix = current_app.config['OPENAIRE_NAMESPACE_PREFIXES'].get(oatype)

value = None
if oatype == _OAType.publication:
value = record.get('_oai', {}).get('id')
elif oatype == _OAType.dataset:
value = record.get('doi')

return prefix, value

def openaire_link(record):
"""Compute an OpenAIRE link."""
oatype = openaire_type(record)
oaid = _openaire_id(record, oatype)

if oatype == _OAType.publication:
return '{}/search/publication?articleId={}'.format(
current_app.config['OPENAIRE_PORTAL_URL'],
oaid,
)
elif oatype == _OAType.dataset:
return '{}/search/dataset?datasetId={}'.format(
current_app.config['OPENAIRE_PORTAL_URL'],
oaid,
)
return None
51 changes: 29 additions & 22 deletions zenodo/modules/openaire/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
from zenodo.modules.records.models import ObjectType
from zenodo.modules.records.serializers.fields import DateString

from .helpers import openaire_original_id, openaire_type

OpenAIREType = namedtuple('OpenAIREType', ('type', 'resource_type'))


Expand All @@ -60,42 +62,48 @@ class RecordSchemaOpenAIREJSON(Schema):
embargoEndDate = DateString(attribute='metadata.embargo_date')

publisher = fields.Method('get_publisher')
collectedFromId = fields.Method('get_openaire_id', required=True)
hostedById = fields.Method('get_openaire_id')
collectedFromId = fields.Method('get_datasource_id', required=True)
hostedById = fields.Method('get_datasource_id')

linksToProjects = fields.Method('get_links_to_projects')
pids = fields.Method('get_pids')

def _resolve_openaire_type(self, obj):
# TODO: Move to utils.py?
metadata = obj.get('metadata')
obj_type = ObjectType.get_by_dict(metadata.get('resource_type'))
if obj_type['internal_id'] == 'dataset':
return OpenAIREType('dataset', '0021')
else:
return OpenAIREType('publication', '0001')
def _openaire_type(self, obj):
return ObjectType.get_by_dict(
obj.get('metadata', {}).get('resource_type')
).get('openaire')

def get_original_id(self, obj):
"""Get Original Id."""
openaire_type = self._resolve_openaire_type(obj)
if openaire_type.type == 'publication':
return obj.get('metadata', {}).get('_oai', {}).get('id')
if openaire_type.type == 'dataset':
return obj.get('metadata', {}).get('doi')
oatype = self._openaire_type(obj)
if oatype:
return openaire_original_id(
obj.get('metadata', {}),
oatype['type']
)[1]
return missing

def get_type(self, obj):
"""Get record type."""
return self._resolve_openaire_type(obj).type
oatype = self._openaire_type(obj)
if oatype:
return oatype['type']
return missing

def get_resource_type(self, obj):
"""Get resource type."""
return self._resolve_openaire_type(obj).resource_type
oatype = self._openaire_type(obj)
if oatype:
return oatype['resourceType']
return missing

def get_openaire_id(self, obj):
def get_datasource_id(self, obj):
"""Get OpenAIRE Zenodo ID."""
# TODO: Move to utils.py?
openaire_type = self._resolve_openaire_type(obj).type
return current_app.config['OPENAIRE_ZENODO_IDS'].get(openaire_type)
oatype = self._openaire_type(obj)
if oatype:
return current_app.config['OPENAIRE_ZENODO_IDS'].get(
oatype['type'])
return missing

# Mapped from: http://api.openaire.eu/vocabularies/dnet:access_modes
LICENSE_MAPPING = {
Expand Down Expand Up @@ -134,7 +142,6 @@ def get_pids(self, obj):

def get_url(self, obj):
"""Get record URL."""
# TODO: Zenodo or DOI URL? ("zenodo.org/..." or "doi.org/...")
return current_app.config['ZENODO_RECORDS_UI_LINKS_FORMAT'].format(
recid=obj['metadata']['recid'])

Expand Down

0 comments on commit 3a36f4a

Please sign in to comment.