From 895f263e4d988140d4e2135d9ef34eafb2f4f359 Mon Sep 17 00:00:00 2001 From: Brian Kelly Date: Tue, 17 Dec 2024 15:20:42 -0600 Subject: [PATCH 1/2] Allow UISerializer to serialize Polygon locations in addition to Points. --- .../resources/serializers/ui/schema.py | 14 +- .../serializers/test_ui_serializer.py | 253 +++++++++++++++++- 2 files changed, 262 insertions(+), 5 deletions(-) diff --git a/invenio_rdm_records/resources/serializers/ui/schema.py b/invenio_rdm_records/resources/serializers/ui/schema.py index 05395550a..b536db105 100644 --- a/invenio_rdm_records/resources/serializers/ui/schema.py +++ b/invenio_rdm_records/resources/serializers/ui/schema.py @@ -115,6 +115,18 @@ def mask_removed_by(obj): return return_value +def get_coordinates(obj): + """Coordinates determined by geometry type.""" + geometry_type = obj.get("type", None) + + if geometry_type == "Point": + return obj.get("coordinates", []) + elif geometry_type == "Polygon": + return obj.get("coordinates", [[[]]]) + else: + return None + + class RelatedIdentifiersSchema(Schema): """Localization of language titles.""" @@ -168,7 +180,7 @@ class GeometrySchema(Schema): """Schema for geometry in the UI.""" type = fields.Str() - coordinates = fields.List(fields.Float()) + coordinates = fields.Function(get_coordinates) class IdentifierSchema(Schema): diff --git a/tests/resources/serializers/test_ui_serializer.py b/tests/resources/serializers/test_ui_serializer.py index 89bf2d091..ec279e87d 100644 --- a/tests/resources/serializers/test_ui_serializer.py +++ b/tests/resources/serializers/test_ui_serializer.py @@ -31,7 +31,7 @@ def _add_affiliation_name(creatibutors): @pytest.fixture(scope="function") -def full_to_dict_record(full_record_to_dict): +def full_to_dict_record_point(full_record_to_dict): """Full record dereferenced data, as is expected by the UI serializer.""" # TODO: Converge this and full record over time to_dict_record = deepcopy(full_record_to_dict) @@ -109,7 +109,89 @@ def full_to_dict_record(full_record_to_dict): return to_dict_record -def test_ui_serializer(app, full_to_dict_record): +@pytest.fixture(scope="function") +def full_to_dict_record_polygon(full_record_to_dict): + """Full record dereferenced data, as is expected by the UI serializer.""" + # TODO: Converge this and full record over time + to_dict_record = deepcopy(full_record_to_dict) + + to_dict_record["metadata"]["languages"] = [ + {"id": "dan", "title": {"en": "Danish"}}, + {"id": "eng", "title": {"en": "English"}}, + ] + + to_dict_record["metadata"]["resource_type"] = { + "id": "publication-article", + "title": {"en": "Journal article"}, + } + + to_dict_record["metadata"]["subjects"] = [ + {"id": "A-D000007", "title": {"en": "Abdominal Injuries"}}, + {"id": "A-D000008", "title": {"en": "Abdominal Neoplasms"}}, + ] + + to_dict_record["metadata"]["related_identifiers"] = [ + { + "identifier": "10.1234/foo.bar", + "resource_type": {"id": "dataset", "title": {"en": "Dataset"}}, + "relation_type": {"id": "iscitedby", "title": {"en": "Is cited by"}}, + "scheme": "doi", + } + ] + + to_dict_record["metadata"]["funding"] = [ + { + "funder": { + "id": "00k4n6c32", + "name": "EC", + "title": {"en": "European Commission", "fr": "Commission Européenne"}, + "country": "BE", + }, + "award": { + "id": "00k4n6c32", + "identifiers": [ + { + "identifier": "000000012156142X", + "scheme": "isni", + }, + { + "identifier": "00k4n6c32", + "scheme": "ror", + }, + ], + "name": "European Commission", + "title": { + "en": "European Commission", + "fr": "Commission européenne", + }, + "country": "BE", + }, + } + ] + + to_dict_record["metadata"]["locations"] = { + "features": [ + { + "geometry": { + "type": "Polygon", + "coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]], + }, + "identifiers": [{"scheme": "geonames", "identifier": "2661235"}], + "place": "CERN", + "description": "Invenio birth place.", + }, + ] + } + + _add_affiliation_name(to_dict_record["metadata"]["creators"]) + _add_affiliation_name(to_dict_record["metadata"]["contributors"]) + + to_dict_record["access"]["status"] = "embargoed" + + return to_dict_record + + +def test_ui_serializer_point(app, full_to_dict_record_point): expected_data = { "access_status": { "description_l10n": "The files will be made publicly available on " @@ -260,10 +342,173 @@ def test_ui_serializer(app, full_to_dict_record): }, } - serialized_record = UIJSONSerializer().dump_obj(full_to_dict_record) + serialized_record = UIJSONSerializer().dump_obj(full_to_dict_record_point) + assert serialized_record["ui"] == expected_data + + serialized_records = UIJSONSerializer().serialize_object_list( + {"hits": {"hits": [full_to_dict_record_point]}} + ) + assert json.loads(serialized_records)["hits"]["hits"][0]["ui"] == expected_data + + +def test_ui_serializer_polygon(app, full_to_dict_record_polygon): + expected_data = { + "access_status": { + "description_l10n": "The files will be made publicly available on " + "January 1, 2131.", + "icon": "outline clock", + "id": "embargoed", + "title_l10n": "Embargoed", + "embargo_date_l10n": "January 1, 2131", + "message_class": "warning", + }, + "contributors": { + "affiliations": [[1, "CERN", "cern"], [2, "TU Wien", None]], + "contributors": [ + { + "affiliations": [[1, "CERN"], [2, "TU Wien"]], + "person_or_org": { + "family_name": "Nielsen", + "given_name": "Lars Holm", + "identifiers": [ + {"identifier": "0000-0001-8135-3489", "scheme": "orcid"} + ], + "name": "Nielsen, Lars Holm", + "type": "personal", + }, + "role": {"id": "other", "title": "other"}, + }, + { + "person_or_org": { + "family_name": "Dirk", + "given_name": "Dirkin", + "name": "Dirk, Dirkin", + "type": "personal", + }, + "role": {"id": "other", "title": "Other"}, + }, + ], + }, + "creators": { + "affiliations": [[1, "CERN", "cern"], [2, "free-text", None]], + "creators": [ + { + "affiliations": [[1, "CERN"], [2, "free-text"]], + "person_or_org": { + "family_name": "Nielsen", + "given_name": "Lars Holm", + "identifiers": [ + {"identifier": "0000-0001-8135-3489", "scheme": "orcid"} + ], + "name": "Nielsen, Lars Holm", + "type": "personal", + }, + }, + { + "person_or_org": { + "family_name": "Tom", + "given_name": "Blabin", + "name": "Tom, Blabin", + "type": "personal", + } + }, + ], + }, + "publication_date_l10n_long": "January 2018\u2009–\u2009September 2020", + "publication_date_l10n_medium": "Jan 2018\u2009–\u2009Sep 2020", + "resource_type": {"id": "publication-article", "title_l10n": "Journal article"}, + "additional_titles": [ + { + "lang": {"id": "eng", "title_l10n": "English"}, + "title": "a research data management platform", + "type": {"id": "subtitle", "title_l10n": "Subtitle"}, + } + ], + "additional_descriptions": [ + { + "description": "Bla bla bla", + "lang": {"id": "eng", "title_l10n": "English"}, + "type": {"id": "methods", "title_l10n": "Methods"}, + } + ], + "is_draft": False, + "languages": [ + {"id": "dan", "title_l10n": "Danish"}, + {"id": "eng", "title_l10n": "English"}, + ], + "dates": [ + { + "date": "1939/1945", + "description": "A date", + "type": {"id": "other", "title_l10n": "Other"}, + } + ], + "rights": [ + { + "description_l10n": "A description", + "link": "https://customlicense.org/licenses/by/4.0/", + "title_l10n": "A custom license", + }, + { + "description_l10n": "The Creative Commons Attribution license allows re-distribution and re-use of a licensed work on the condition that the creator is appropriately credited.", + "id": "cc-by-4.0", + "props": { + "scheme": "spdx", + "url": "https://creativecommons.org/licenses/by/4.0/legalcode", + }, + "title_l10n": "Creative Commons Attribution 4.0 International", + }, + ], + "related_identifiers": [ + { + "identifier": "10.1234/foo.bar", + "relation_type": {"id": "iscitedby", "title_l10n": "Is cited by"}, + "resource_type": {"id": "dataset", "title_l10n": "Dataset"}, + "scheme": "doi", + } + ], + "custom_fields": {}, + "description_stripped": "A description \nwith HTML tags", + "version": "v1.0", + "created_date_l10n_long": "November 14, 2023", + "updated_date_l10n_long": "November 14, 2023", + "funding": [ + { + "award": { + "id": "00k4n6c32", + "identifiers": [ + {"identifier": "000000012156142X", "scheme": "isni"}, + {"identifier": "00k4n6c32", "scheme": "ror"}, + ], + "title_l10n": "European Commission", + }, + "funder": { + "country": "BE", + "id": "00k4n6c32", + "name": "EC", + "title_l10n": "European Commission", + }, + } + ], + "locations": { + "features": [ + { + "geometry": { + "type": "Polygon", + "coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]], + }, + "identifiers": [{"scheme": "geonames", "identifier": "2661235"}], + "place": "CERN", + "description": "Invenio birth place.", + }, + ] + }, + } + + serialized_record = UIJSONSerializer().dump_obj(full_to_dict_record_polygon) assert serialized_record["ui"] == expected_data serialized_records = UIJSONSerializer().serialize_object_list( - {"hits": {"hits": [full_to_dict_record]}} + {"hits": {"hits": [full_to_dict_record_polygon]}} ) assert json.loads(serialized_records)["hits"]["hits"][0]["ui"] == expected_data From c83c51ce16f0b6ffe67b1c126182846e85154e82 Mon Sep 17 00:00:00 2001 From: Brian Kelly Date: Wed, 8 Jan 2025 08:38:20 -0600 Subject: [PATCH 2/2] Consolidate test cases and fixtures --- .../serializers/test_ui_serializer.py | 247 +----------------- 1 file changed, 10 insertions(+), 237 deletions(-) diff --git a/tests/resources/serializers/test_ui_serializer.py b/tests/resources/serializers/test_ui_serializer.py index ec279e87d..a9ff80d3e 100644 --- a/tests/resources/serializers/test_ui_serializer.py +++ b/tests/resources/serializers/test_ui_serializer.py @@ -31,7 +31,7 @@ def _add_affiliation_name(creatibutors): @pytest.fixture(scope="function") -def full_to_dict_record_point(full_record_to_dict): +def full_to_dict_record(full_record_to_dict): """Full record dereferenced data, as is expected by the UI serializer.""" # TODO: Converge this and full record over time to_dict_record = deepcopy(full_record_to_dict) @@ -98,87 +98,14 @@ def full_to_dict_record_point(full_record_to_dict): "place": "CERN", "description": "Invenio birth place.", }, - ] - } - - _add_affiliation_name(to_dict_record["metadata"]["creators"]) - _add_affiliation_name(to_dict_record["metadata"]["contributors"]) - - to_dict_record["access"]["status"] = "embargoed" - - return to_dict_record - - -@pytest.fixture(scope="function") -def full_to_dict_record_polygon(full_record_to_dict): - """Full record dereferenced data, as is expected by the UI serializer.""" - # TODO: Converge this and full record over time - to_dict_record = deepcopy(full_record_to_dict) - - to_dict_record["metadata"]["languages"] = [ - {"id": "dan", "title": {"en": "Danish"}}, - {"id": "eng", "title": {"en": "English"}}, - ] - - to_dict_record["metadata"]["resource_type"] = { - "id": "publication-article", - "title": {"en": "Journal article"}, - } - - to_dict_record["metadata"]["subjects"] = [ - {"id": "A-D000007", "title": {"en": "Abdominal Injuries"}}, - {"id": "A-D000008", "title": {"en": "Abdominal Neoplasms"}}, - ] - - to_dict_record["metadata"]["related_identifiers"] = [ - { - "identifier": "10.1234/foo.bar", - "resource_type": {"id": "dataset", "title": {"en": "Dataset"}}, - "relation_type": {"id": "iscitedby", "title": {"en": "Is cited by"}}, - "scheme": "doi", - } - ] - - to_dict_record["metadata"]["funding"] = [ - { - "funder": { - "id": "00k4n6c32", - "name": "EC", - "title": {"en": "European Commission", "fr": "Commission Européenne"}, - "country": "BE", - }, - "award": { - "id": "00k4n6c32", - "identifiers": [ - { - "identifier": "000000012156142X", - "scheme": "isni", - }, - { - "identifier": "00k4n6c32", - "scheme": "ror", - }, - ], - "name": "European Commission", - "title": { - "en": "European Commission", - "fr": "Commission européenne", - }, - "country": "BE", - }, - } - ] - - to_dict_record["metadata"]["locations"] = { - "features": [ { "geometry": { "type": "Polygon", "coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]], }, - "identifiers": [{"scheme": "geonames", "identifier": "2661235"}], - "place": "CERN", - "description": "Invenio birth place.", + "identifiers": [{"scheme": "geonames", "identifier": "123456"}], + "place": "Rectangle", + "description": "Example Polygon", }, ] } @@ -191,7 +118,7 @@ def full_to_dict_record_polygon(full_record_to_dict): return to_dict_record -def test_ui_serializer_point(app, full_to_dict_record_point): +def test_ui_serializer(app, full_to_dict_record): expected_data = { "access_status": { "description_l10n": "The files will be made publicly available on " @@ -338,177 +265,23 @@ def test_ui_serializer_point(app, full_to_dict_record_point): "place": "CERN", "description": "Invenio birth place.", }, - ] - }, - } - - serialized_record = UIJSONSerializer().dump_obj(full_to_dict_record_point) - assert serialized_record["ui"] == expected_data - - serialized_records = UIJSONSerializer().serialize_object_list( - {"hits": {"hits": [full_to_dict_record_point]}} - ) - assert json.loads(serialized_records)["hits"]["hits"][0]["ui"] == expected_data - - -def test_ui_serializer_polygon(app, full_to_dict_record_polygon): - expected_data = { - "access_status": { - "description_l10n": "The files will be made publicly available on " - "January 1, 2131.", - "icon": "outline clock", - "id": "embargoed", - "title_l10n": "Embargoed", - "embargo_date_l10n": "January 1, 2131", - "message_class": "warning", - }, - "contributors": { - "affiliations": [[1, "CERN", "cern"], [2, "TU Wien", None]], - "contributors": [ - { - "affiliations": [[1, "CERN"], [2, "TU Wien"]], - "person_or_org": { - "family_name": "Nielsen", - "given_name": "Lars Holm", - "identifiers": [ - {"identifier": "0000-0001-8135-3489", "scheme": "orcid"} - ], - "name": "Nielsen, Lars Holm", - "type": "personal", - }, - "role": {"id": "other", "title": "other"}, - }, - { - "person_or_org": { - "family_name": "Dirk", - "given_name": "Dirkin", - "name": "Dirk, Dirkin", - "type": "personal", - }, - "role": {"id": "other", "title": "Other"}, - }, - ], - }, - "creators": { - "affiliations": [[1, "CERN", "cern"], [2, "free-text", None]], - "creators": [ - { - "affiliations": [[1, "CERN"], [2, "free-text"]], - "person_or_org": { - "family_name": "Nielsen", - "given_name": "Lars Holm", - "identifiers": [ - {"identifier": "0000-0001-8135-3489", "scheme": "orcid"} - ], - "name": "Nielsen, Lars Holm", - "type": "personal", - }, - }, - { - "person_or_org": { - "family_name": "Tom", - "given_name": "Blabin", - "name": "Tom, Blabin", - "type": "personal", - } - }, - ], - }, - "publication_date_l10n_long": "January 2018\u2009–\u2009September 2020", - "publication_date_l10n_medium": "Jan 2018\u2009–\u2009Sep 2020", - "resource_type": {"id": "publication-article", "title_l10n": "Journal article"}, - "additional_titles": [ - { - "lang": {"id": "eng", "title_l10n": "English"}, - "title": "a research data management platform", - "type": {"id": "subtitle", "title_l10n": "Subtitle"}, - } - ], - "additional_descriptions": [ - { - "description": "Bla bla bla", - "lang": {"id": "eng", "title_l10n": "English"}, - "type": {"id": "methods", "title_l10n": "Methods"}, - } - ], - "is_draft": False, - "languages": [ - {"id": "dan", "title_l10n": "Danish"}, - {"id": "eng", "title_l10n": "English"}, - ], - "dates": [ - { - "date": "1939/1945", - "description": "A date", - "type": {"id": "other", "title_l10n": "Other"}, - } - ], - "rights": [ - { - "description_l10n": "A description", - "link": "https://customlicense.org/licenses/by/4.0/", - "title_l10n": "A custom license", - }, - { - "description_l10n": "The Creative Commons Attribution license allows re-distribution and re-use of a licensed work on the condition that the creator is appropriately credited.", - "id": "cc-by-4.0", - "props": { - "scheme": "spdx", - "url": "https://creativecommons.org/licenses/by/4.0/legalcode", - }, - "title_l10n": "Creative Commons Attribution 4.0 International", - }, - ], - "related_identifiers": [ - { - "identifier": "10.1234/foo.bar", - "relation_type": {"id": "iscitedby", "title_l10n": "Is cited by"}, - "resource_type": {"id": "dataset", "title_l10n": "Dataset"}, - "scheme": "doi", - } - ], - "custom_fields": {}, - "description_stripped": "A description \nwith HTML tags", - "version": "v1.0", - "created_date_l10n_long": "November 14, 2023", - "updated_date_l10n_long": "November 14, 2023", - "funding": [ - { - "award": { - "id": "00k4n6c32", - "identifiers": [ - {"identifier": "000000012156142X", "scheme": "isni"}, - {"identifier": "00k4n6c32", "scheme": "ror"}, - ], - "title_l10n": "European Commission", - }, - "funder": { - "country": "BE", - "id": "00k4n6c32", - "name": "EC", - "title_l10n": "European Commission", - }, - } - ], - "locations": { - "features": [ { "geometry": { "type": "Polygon", "coordinates": [[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]], }, - "identifiers": [{"scheme": "geonames", "identifier": "2661235"}], - "place": "CERN", - "description": "Invenio birth place.", + "identifiers": [{"scheme": "geonames", "identifier": "123456"}], + "place": "Rectangle", + "description": "Example Polygon", }, ] }, } - serialized_record = UIJSONSerializer().dump_obj(full_to_dict_record_polygon) + serialized_record = UIJSONSerializer().dump_obj(full_to_dict_record) assert serialized_record["ui"] == expected_data serialized_records = UIJSONSerializer().serialize_object_list( - {"hits": {"hits": [full_to_dict_record_polygon]}} + {"hits": {"hits": [full_to_dict_record]}} ) assert json.loads(serialized_records)["hits"]["hits"][0]["ui"] == expected_data