Skip to content

Commit

Permalink
views: FAIR signposting level 1 support
Browse files Browse the repository at this point in the history
  • Loading branch information
ptamarit committed Dec 13, 2024
1 parent 34eac5e commit fe891a1
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 9 deletions.
6 changes: 5 additions & 1 deletion invenio_rdm_records/resources/serializers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@
)
from .marcxml import MARCXMLSerializer
from .schemaorg import SchemaorgJSONLDSerializer
from .signposting import FAIRSignpostingProfileLvl2Serializer
from .signposting import (
FAIRSignpostingProfileLvl1Serializer,
FAIRSignpostingProfileLvl2Serializer,
)
from .ui import UIJSONSerializer

__all__ = (
Expand All @@ -47,6 +50,7 @@
"DataPackageSerializer",
"DublinCoreJSONSerializer",
"DublinCoreXMLSerializer",
"FAIRSignpostingProfileLvl1Serializer",
"FAIRSignpostingProfileLvl2Serializer",
"GeoJSONSerializer",
"IIIFCanvasV2JSONSerializer",
Expand Down
30 changes: 28 additions & 2 deletions invenio_rdm_records/resources/serializers/signposting/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,35 @@
"""Signposting serializers."""

from flask_resources import BaseListSchema, MarshmallowSerializer
from flask_resources.serializers import JSONSerializer
from flask_resources.serializers import JSONSerializer, SimpleSerializer

from .schema import FAIRSignpostingProfileLvl2Schema
from .schema import FAIRSignpostingProfileLvl2Schema, LandingPageLvl1Schema


class FAIRSignpostingProfileLvl1Serializer(MarshmallowSerializer):
"""FAIR Signposting Profile level 1 serializer."""

def __init__(self):
"""Initialise Serializer."""
super().__init__(
format_serializer_cls=SimpleSerializer,
object_schema_cls=LandingPageLvl1Schema,
list_schema_cls=BaseListSchema,
encoder=self.fair_signposting_tostring,
)

@classmethod
def fair_signposting_tostring(cls, record):
"""Stringify a FAIR Signposting record."""
links = []
for rel, values in record.items():
# if rel not in excluded_keys:
for value in values:
link = f'<{value["href"]}> ; rel="{rel}"'
if "type" in value:
link += f' ; type="{value["type"]}"'
links.append(link)
return " , ".join(links)


class FAIRSignpostingProfileLvl2Serializer(MarshmallowSerializer):
Expand Down
38 changes: 32 additions & 6 deletions invenio_rdm_records/resources/serializers/signposting/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,13 @@ class LandingPageSchema(Schema):
Serialization input (`obj`) is a whole record dict projection.
"""

anchor = fields.Method(serialize="serialize_anchor")
author = fields.Method(serialize="serialize_author")
cite_as = fields.Method(data_key="cite-as", serialize="serialize_cite_as")
describedby = fields.Method(serialize="serialize_describedby")
item = fields.Method(serialize="serialize_item")
license = fields.Method(serialize="serialize_license")
type = fields.Method(serialize="serialize_type")

def serialize_anchor(self, obj, **kwargs):
"""Seralize to landing page URL."""
return obj["links"]["self_html"]

def serialize_author(self, obj, **kwargs):
"""Serialize author(s).
Expand Down Expand Up @@ -144,6 +139,37 @@ def serialize_type(self, obj, **kwargs):
return result


class LandingPageLvl1Schema(LandingPageSchema):
"""Schema for serialization of link context object for the landing page.
Serialization input (`obj`) is a whole record dict projection.
"""

linkset = fields.Method(serialize="serialize_linkset")

def serialize_linkset(self, obj, **kwargs):
"""Serialize the linkset URL."""
return [
{
"href": obj["links"]["self"],
"type": "application/linkset+json",
}
]


class LandingPageLvl2Schema(LandingPageSchema):
"""Schema for serialization of link context object for the landing page.
Serialization input (`obj`) is a whole record dict projection.
"""

anchor = fields.Method(serialize="serialize_anchor")

def serialize_anchor(self, obj, **kwargs):
"""Serialize to landing page URL."""
return obj["links"]["self_html"]


class ContentResourceSchema(Schema):
"""Schema for serialization of link context object for the content resource.
Expand Down Expand Up @@ -205,7 +231,7 @@ class FAIRSignpostingProfileLvl2Schema(Schema):

def serialize_linkset(self, obj, **kwargs):
"""Serialize linkset."""
result = [LandingPageSchema().dump(obj)]
result = [LandingPageLvl2Schema().dump(obj)]

content_resource_schema = ContentResourceSchema(context={"record_dict": obj})
result += [
Expand Down
72 changes: 72 additions & 0 deletions tests/resources/serializers/test_signposting_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"""Resources serializers tests."""

from invenio_rdm_records.resources.serializers import (
FAIRSignpostingProfileLvl1Serializer,
FAIRSignpostingProfileLvl2Serializer,
)

Expand Down Expand Up @@ -125,6 +126,43 @@ def test_signposting_serializer_full(running_app, full_record_to_dict):
assert expected == serialized


def test_signposting_lvl1_serializer_full(running_app, full_record_to_dict):
ui_url = "https://127.0.0.1:5000/records/12345-abcde"
api_url = "https://127.0.0.1:5000/api/records/12345-abcde"
filename = "test.txt"

expected = [
f'<https://orcid.org/0000-0001-8135-3489> ; rel="author"',
f'<https://doi.org/10.1234/12345-abcde> ; rel="cite-as"',
f'<{api_url}> ; rel="describedby" ; type="application/dcat+xml"',
f'<{api_url}> ; rel="describedby" ; type="application/json"',
f'<{api_url}> ; rel="describedby" ; type="application/ld+json"',
f'<{api_url}> ; rel="describedby" ; type="application/marcxml+xml"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.citationstyles.csl+json"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.datacite.datacite+json"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.datacite.datacite+xml"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.geo+json"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.inveniordm.v1+json"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.inveniordm.v1.full+csv"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.inveniordm.v1.simple+csv"',
f'<{api_url}> ; rel="describedby" ; type="application/x-bibtex"',
f'<{api_url}> ; rel="describedby" ; type="application/x-dc+xml"',
f'<{api_url}> ; rel="describedby" ; type="text/x-bibliography"',
f'<{ui_url}/files/{filename}> ; rel="item" ; type="text/plain"',
'<https://customlicense.org/licenses/by/4.0/> ; rel="license"',
'<https://creativecommons.org/licenses/by/4.0/legalcode> ; rel="license"',
'<https://schema.org/Photograph> ; rel="type"',
'<https://schema.org/AboutPage> ; rel="type"',
f'<{api_url}> ; rel="linkset" ; type="application/linkset+json"',
]

serialized = FAIRSignpostingProfileLvl1Serializer().serialize_object(
full_record_to_dict
)

assert expected == serialized.split(" , ")


def test_signposting_serializer_minimal(running_app, minimal_record_to_dict):
expected = {
"linkset": [
Expand Down Expand Up @@ -218,3 +256,37 @@ def test_signposting_serializer_minimal(running_app, minimal_record_to_dict):
serialized = FAIRSignpostingProfileLvl2Serializer().dump_obj(minimal_record_to_dict)

assert expected == serialized


def test_signposting_lvl1_serializer_minimal(running_app, minimal_record_to_dict):
api_url = "https://127.0.0.1:5000/api/records/67890-fghij"

expected = [
# No author since no associated PID
# No cite-as since no DOI
f'<{api_url}> ; rel="describedby" ; type="application/dcat+xml"',
f'<{api_url}> ; rel="describedby" ; type="application/json"',
f'<{api_url}> ; rel="describedby" ; type="application/ld+json"',
f'<{api_url}> ; rel="describedby" ; type="application/marcxml+xml"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.citationstyles.csl+json"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.datacite.datacite+json"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.datacite.datacite+xml"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.geo+json"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.inveniordm.v1+json"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.inveniordm.v1.full+csv"',
f'<{api_url}> ; rel="describedby" ; type="application/vnd.inveniordm.v1.simple+csv"',
f'<{api_url}> ; rel="describedby" ; type="application/x-bibtex"',
f'<{api_url}> ; rel="describedby" ; type="application/x-dc+xml"',
f'<{api_url}> ; rel="describedby" ; type="text/x-bibliography"',
# No files
# No license
'<https://schema.org/Photograph> ; rel="type"',
'<https://schema.org/AboutPage> ; rel="type"',
f'<{api_url}> ; rel="linkset" ; type="application/linkset+json"',
]

serialized = FAIRSignpostingProfileLvl1Serializer().serialize_object(
minimal_record_to_dict
)

assert expected == serialized.split(" , ")

0 comments on commit fe891a1

Please sign in to comment.