diff --git a/rero_ils/config.py b/rero_ils/config.py index 6fe9bb5053..266b423ec1 100644 --- a/rero_ils/config.py +++ b/rero_ils/config.py @@ -3044,7 +3044,8 @@ def _(x): RERO_ILS_ENTITY_TYPES = { 'bf:Person': 'agents', 'bf:Organisation': 'agents', - 'bf:Topic': 'concepts' + 'bf:Topic': 'concepts', + 'bf:Temporal': 'concepts' } # The absolute path to put the agent synchronization logs, default is the diff --git a/rero_ils/modules/entities/remote_entities/jsonschemas/remote_entities/remote_entity-v0.0.1.json b/rero_ils/modules/entities/remote_entities/jsonschemas/remote_entities/remote_entity-v0.0.1.json index 83d391a0fa..8c04f52dc6 100644 --- a/rero_ils/modules/entities/remote_entities/jsonschemas/remote_entities/remote_entity-v0.0.1.json +++ b/rero_ils/modules/entities/remote_entities/jsonschemas/remote_entities/remote_entity-v0.0.1.json @@ -31,7 +31,8 @@ "enum": [ "bf:Organisation", "bf:Person", - "bf:Topic" + "bf:Topic", + "bf:Temporal" ] }, "viaf_pid": { diff --git a/rero_ils/modules/entities/remote_entities/proxy.py b/rero_ils/modules/entities/remote_entities/proxy.py index fe1327913c..5517157da9 100644 --- a/rero_ils/modules/entities/remote_entities/proxy.py +++ b/rero_ils/modules/entities/remote_entities/proxy.py @@ -69,9 +69,17 @@ def create_proxy(category): 'entities': (EntityType.ORGANISATION,) }, 'concepts': { + 'class': MefConceptsProxy, + 'entities': (EntityType.TOPIC, EntityType.TEMPORAL) + }, + 'topics': { 'class': MefConceptsProxy, 'entities': (EntityType.TOPIC,) }, + 'temporals': { + 'class': MefConceptsProxy, + 'entities': (EntityType.TEMPORAL, ) + }, 'concepts-genreForm': { 'class': MefConceptsGenreFormProxy, 'entities': (EntityType.TOPIC,) @@ -80,7 +88,8 @@ def create_proxy(category): # Create proxy configuration aliases proxy_config[EntityType.PERSON] = proxy_config['person'] proxy_config[EntityType.ORGANISATION] = proxy_config['organisation'] - proxy_config[EntityType.TOPIC] = proxy_config['concepts'] + proxy_config[EntityType.TOPIC] = proxy_config['topics'] + proxy_config[EntityType.TEMPORAL] = proxy_config['temporals'] # Try to create the proxy, otherwise raise a ValueError if data := proxy_config.get(category): @@ -276,6 +285,25 @@ class MefConceptsProxy(MEFProxyMixin): mef_entrypoint = 'concepts' + def _get_query_params(self, term): + """Get all parameters to use to build the MEF query. + + :param term: the searched term + :type term: str + :returns: a list of query parameters to build the `q` parameter to send + to the remote MEF server to filter the response. All these params + will be joined by 'AND' condition. + :rtype: list + """ + params = super()._get_query_params(term) + if self.entity_types: + ent_types = [] + for _type in self.entity_types: + _type = _type.replace(":", "\\:") + ent_types.append(f'type:{_type}') + params += [f'({" OR ".join(ent_types)})'] + return params + def _post_process_result_hit(self, hit): """Modify a MEF hit response to return a standardized hit. @@ -287,7 +315,6 @@ def _post_process_result_hit(self, hit): """ if not (metadata := hit.get('metadata', {})): return - metadata['type'] = EntityType.TOPIC super()._post_process_result_hit(hit) diff --git a/rero_ils/modules/entities/remote_entities/replace.py b/rero_ils/modules/entities/remote_entities/replace.py index 419ad3ad93..aaf603e97b 100644 --- a/rero_ils/modules/entities/remote_entities/replace.py +++ b/rero_ils/modules/entities/remote_entities/replace.py @@ -91,13 +91,7 @@ def _get_latest(self, entity_type, source, pid): url = f'{self._get_base_url(entity_type)}/mef/latest/{source}:{pid}' res = requests_retry_session().get(url) if res.status_code == requests.codes.ok: - # TODO: could be deleted if MEF is updated. - if data := res.json(): - if data_type := data.get('bf:Agent', data.get('type')): - data['type'] = data_type - elif entity_type == 'concepts': - data['type'] = 'bf:Topic' - return data + return res.json() self.logger.warning(f'Problem get {url}: {res.status_code}') return {} @@ -185,7 +179,8 @@ def _do_entity(self, entity, doc_pid): self.logger.info( f'Replace document:{doc_pid} ' f'{self.field} "{authorized_access_point}" - ' - f'({mef_type}) {new_source}:{new_source_pid} ' + f'({mef_type}|{doc_entity_type}) ' + f'{new_source}:{new_source_pid} ' f'"{mef_authorized_access_point}"' ) entity['entity'] = { @@ -203,7 +198,8 @@ def _do_entity(self, entity, doc_pid): self.rero_only[identifier] = info self.logger.warning( f'No other source found for document:{doc_pid} ' - f'{self.field} - ({mef_type}) {identifier} "{info}"' + f'{self.field} - ({mef_type}|{doc_entity_type}) ' + f'{identifier} "{info}"' ) else: authorized_access_point = entity[ @@ -212,7 +208,7 @@ def _do_entity(self, entity, doc_pid): self.not_found[identifier] = info self.logger.warning( f'No MEF found for document:{doc_pid} ' - f'{self.parent} - ({mef_type}) {identifier} "{info}"' + f' - ({mef_type}) {identifier} "{info}"' ) return changed @@ -234,6 +230,8 @@ def _replace_entities_in_document(self, doc_id): self.logger.error( f'Error document:{doc.pid} {entity} {err}"' ) + import traceback + traceback.print_exc() if changed: return doc diff --git a/rero_ils/modules/entities/remote_entities/sync.py b/rero_ils/modules/entities/remote_entities/sync.py index 2be3f64dfa..caf8a9c4dc 100644 --- a/rero_ils/modules/entities/remote_entities/sync.py +++ b/rero_ils/modules/entities/remote_entities/sync.py @@ -119,11 +119,7 @@ def _get_latest(self, entity_type, source, pid): url = f'{base_url}/mef/latest/{source}:{pid}' res = requests_retry_session().get(url) if res.status_code == requests.codes.ok: - data = res.json() - if entity_type == 'concepts' and not data.get('type'): - # TODO: delete for MEF v0.12.0 - data['type'] = 'bf:Topic' - return data + return res.json() self.logger.debug(f'Problem get {url}: {res.status_code}') return {} diff --git a/tests/data/data.json b/tests/data/data.json index 86cb026a36..ce7d2c24bc 100644 --- a/tests/data/data.json +++ b/tests/data/data.json @@ -1765,6 +1765,90 @@ "rero" ] }, + "ent_topic_temporal": { + "$schema": "https://mef.rero.ch/schemas/concepts_mef/mef-concept-v0.0.1.json", + "idref": { + "$schema": "https://mef.rero.ch/schemas/concepts_idref/idref-concept-v0.0.1.json", + "authorized_access_point": "1945-....", + "bnf_type": "sujet Rameau", + "broader": [ + { + "authorized_access_point": "1800-...." + } + ], + "classification": [ + { + "classificationPortion": "900", + "name": "Histoire", + "type": "bf:ClassificationDdc" + } + ], + "identifiedBy": [ + { + "source": "IDREF", + "type": "uri", + "value": "http://www.idref.fr/033472890" + }, + { + "source": "BNF", + "type": "uri", + "value": "http://catalogue.bnf.fr/ark:/12148/cb12433520g" + } + ], + "md5": "834a06398eb0d971e6df7a0095deeaef", + "narrower": [ + { + "authorized_access_point": "1945-1990" + }, + { + "authorized_access_point": "1970-...." + } + ], + "note": [ + { + "label": [ + "Dict. encyclopédique d'histoire / M. Mourre, 1996" + ], + "noteType": "dataSource" + }, + { + "label": [ + "Laval RVM (en ligne), 2012-10-16" + ], + "noteType": "dataNotFound" + }, + { + "label": [ + "2 septembre 1945 : fin de la Seconde guerre mondiale", + "S'emploie uniquement en subdivision chronologique [sans subd. géogr.] à tous sujets noms communs et noms propres, à l'exception des personnes et des sujets pour lesquels il existe un découpage chronologique spécifique, par ex. : Paris (France) -- 1944-" + ], + "noteType": "general" + } + ], + "pid": "033472890", + "related": [ + { + "authorized_access_point": "20e siècle" + }, + { + "authorized_access_point": "Histoire universelle - 1945-...." + } + ], + "relation_pid": { + "type": "redirect_from", + "value": "033467404" + }, + "type": "bf:Temporal", + "variant_access_point": [ + "1945-.... (subdivision)" + ] + }, + "pid": "16705461", + "sources": [ + "idref" + ], + "type": "bf:Temporal" + }, "ent_pers_all": { "$schema": "https://bib.rero.ch/schemas/remote_entities/remote_entity-v0.0.1.json", "type": "bf:Person", @@ -2056,6 +2140,16 @@ "value": "A003633163" } } + }, + { + "entity": { + "authorized_access_point": "1945-....", + "type": "bf:Temporal", + "identifiedBy": { + "type": "IdRef", + "value": "033472890" + } + } } ], "dimensions": [ diff --git a/tests/fixtures/metadata.py b/tests/fixtures/metadata.py index 06f2f60286..64de652d75 100644 --- a/tests/fixtures/metadata.py +++ b/tests/fixtures/metadata.py @@ -275,6 +275,12 @@ def entity_topic_data_2(data): return deepcopy(data.get('ent_topic2')) +@pytest.fixture(scope="module") +def entity_topic_data_temporal(data): + """Load mef concept topic temporal data.""" + return deepcopy(data.get('ent_topic_temporal')) + + @pytest.fixture(scope="module") def entity_person_response_data(entity_topic_data): """Load mef concept topic response data.""" diff --git a/tests/ui/entities/remote_entities/test_remote_entities_api.py b/tests/ui/entities/remote_entities/test_remote_entities_api.py index 311a117a3b..1c22b1cce7 100644 --- a/tests/ui/entities/remote_entities/test_remote_entities_api.py +++ b/tests/ui/entities/remote_entities/test_remote_entities_api.py @@ -354,7 +354,7 @@ def test_remote_entity_properties( def test_replace_identified_by( app, entity_organisation, entity_person_rero, person2_data, - entity_person_all, entity_topic_data_2, + entity_person_all, entity_topic_data_2, entity_topic_data_temporal, document, document_sion_items, export_document ): """Test replace identified by with $ref.""" @@ -418,6 +418,7 @@ def test_replace_identified_by( 'requests.Session.get', side_effect=[ mock_response(json_data=entity_person_all), + mock_response(json_data=entity_topic_data_temporal), mock_response(json_data=person2_data), mock_response(json_data=entity_topic_data_2) ]