diff --git a/data-computer/swagger.json b/data-computer/swagger.json index 4e4f56c..45c5cc3 100644 --- a/data-computer/swagger.json +++ b/data-computer/swagger.json @@ -3,7 +3,7 @@ "info": { "title": "data-computer - Calculs sur fichier corpus compressé", "summary": "Algorithmes de calculs sur un corpus compressé", - "version": "2.1.0", + "version": "2.2.2", "termsOfService": "https://services.istex.fr/", "contact": { "name": "Inist-CNRS", diff --git a/data-computer/v1/base-line.ini b/data-computer/v1/base-line.ini index 4fd1056..ecdf3db 100644 --- a/data-computer/v1/base-line.ini +++ b/data-computer/v1/base-line.ini @@ -27,6 +27,10 @@ post.parameters.2.schema.format = uri post.parameters.2.required = false +[env] +path = generator +value = base-line + [use] plugin = basics plugin = analytics @@ -49,12 +53,6 @@ file = recorder.cfg # Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt -[shift] -[replace] -path = id -value = base-line -path = value -value = env('identifier') +[delegate] +file = recipient.cfg -[JSONString] -indent = env('indent') diff --git a/data-computer/v1/graph-segment.ini b/data-computer/v1/graph-segment.ini index aa36416..d847ff5 100644 --- a/data-computer/v1/graph-segment.ini +++ b/data-computer/v1/graph-segment.ini @@ -27,6 +27,10 @@ post.parameters.2.schema.format = uri post.parameters.2.required = false +[env] +path = generator +value = graph-segment + [use] plugin = basics plugin = analytics @@ -89,12 +93,6 @@ file = recorder.cfg # Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt -[shift] -[replace] -path = id -value = graph-segment -path = value -value = env('identifier') +[delegate] +file = recipient.cfg -[JSONString] -indent = env('indent') diff --git a/data-computer/v1/lda.ini b/data-computer/v1/lda.ini index 3a8db9b..29d2284 100644 --- a/data-computer/v1/lda.ini +++ b/data-computer/v1/lda.ini @@ -27,6 +27,10 @@ post.parameters.2.schema.format = uri post.parameters.2.required = false +[env] +path = generator +value = lda + [use] plugin = basics plugin = analytics @@ -51,12 +55,6 @@ file = recorder.cfg # Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt -[shift] -[replace] -path = id -value = lda -path = value -value = env('identifier') +[delegate] +file = recipient.cfg -[JSONString] -indent = env('indent') diff --git a/data-computer/v1/logger.cfg b/data-computer/v1/logger.cfg index 49db973..b46e88a 100644 --- a/data-computer/v1/logger.cfg +++ b/data-computer/v1/logger.cfg @@ -9,6 +9,12 @@ text = Error trapped [assign] +path = body.identifier +value = env('identifier') + +path = body.generator +value = env('generator') + path = body.error.type value = get('type') diff --git a/data-computer/v1/mock-error-async.ini b/data-computer/v1/mock-error-async.ini index d2872fb..4b4ad9e 100644 --- a/data-computer/v1/mock-error-async.ini +++ b/data-computer/v1/mock-error-async.ini @@ -27,6 +27,10 @@ post.parameters.2.schema.format = uri post.parameters.2.required = false +[env] +path = generator +value = mock-error-async + [use] plugin = basics plugin = analytics @@ -50,12 +54,5 @@ file = recorder.cfg # Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt -[shift] -[replace] -path = id -value = mock-error-async -path = value -value = env('identifier') - -[JSONString] -indent = env('indent') +[delegate] +file = recipient.cfg diff --git a/data-computer/v1/mock-error-sync.ini b/data-computer/v1/mock-error-sync.ini index 03239a3..11b1bdc 100644 --- a/data-computer/v1/mock-error-sync.ini +++ b/data-computer/v1/mock-error-sync.ini @@ -27,6 +27,10 @@ post.parameters.2.schema.format = uri post.parameters.2.required = false +[env] +path = generator +value = mock-error-sync + [use] plugin = basics plugin = analytics @@ -36,18 +40,11 @@ file = charger.cfg # Step 2 (générique): Traiter de manière asynchnore les items reçus - [validate] - path = fake path - rule = required - +[validate] +path = fake path +rule = required # Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt -[shift] -[replace] -path = id -value = mock-erreur-sync -path = value -value = env('identifier') +[delegate] +file = recipient.cfg -[JSONString] -indent = env('indent') diff --git a/data-computer/v1/recipient.cfg b/data-computer/v1/recipient.cfg new file mode 100644 index 0000000..f723830 --- /dev/null +++ b/data-computer/v1/recipient.cfg @@ -0,0 +1,12 @@ +[use] +plugin = basics + +[shift] +[replace] +path = id +value = env('generator') +path = value +value = env('identifier') + +[JSONString] +indent = env('indent') diff --git a/data-computer/v1/tree-segment.ini b/data-computer/v1/tree-segment.ini index 82c10c8..798f690 100644 --- a/data-computer/v1/tree-segment.ini +++ b/data-computer/v1/tree-segment.ini @@ -27,6 +27,10 @@ post.parameters.2.schema.format = uri post.parameters.2.required = false +[env] +path = generator +value = tree-segment + [use] plugin = basics plugin = analytics @@ -86,12 +90,6 @@ file = recorder.cfg # Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt -[shift] -[replace] -path = id -value = tree-segment -path = value -value = env('identifier') +[delegate] +file = recipient.cfg -[JSONString] -indent = env('indent') diff --git a/data-workflow/swagger.json b/data-workflow/swagger.json index 727d19a..6653a59 100644 --- a/data-workflow/swagger.json +++ b/data-workflow/swagger.json @@ -3,7 +3,7 @@ "info": { "title": "data-workflow - Enchainement de traitements asynchrones", "summary": "Les worflows permettent de traiter des fichiers corpus compressés en appelant des webservices d'enrichissement par documents (webservices synchrones)", - "version": "1.0.1", + "version": "1.1.3", "termsOfService": "https://services.istex.fr/", "contact": { "name": "Inist-CNRS", diff --git a/data-workflow/v1/base-line.ini b/data-workflow/v1/base-line.ini index 1998896..e3bb2ff 100644 --- a/data-workflow/v1/base-line.ini +++ b/data-workflow/v1/base-line.ini @@ -27,6 +27,10 @@ post.parameters.2.schema.format = uri post.parameters.2.required = false +[env] +path = generator +value = base-line + [use] plugin = basics plugin = analytics @@ -49,12 +53,6 @@ file = recorder.cfg # Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt -[shift] -[replace] -path = id -value = base-line -path = value -value = env('identifier') +[delegate] +file = recipient.cfg -[JSONString] -indent = env('indent') diff --git a/data-workflow/v1/buffer.cfg b/data-workflow/v1/buffer.cfg new file mode 100644 index 0000000..a56c958 --- /dev/null +++ b/data-workflow/v1/buffer.cfg @@ -0,0 +1,24 @@ +[use] +plugin = basics + +# On sauvegarde sur disque pour accepter rapidement tous les objets en entrée +# et répondre rapidement au client que le traitmenent asynchnrone est lancé. +# +# Le "fork" se détache uniquement quand tous les objets sont "rentrés" dans le fork +# Si le traitement est plus lent que la sauvegarde sur disque +# il est nécessaire de créer un fichier temporaire +[pack] +[FILESave] +identifier = env('identifier') +location = /tmp/upload +compress = true + +[exchange] +value = get('filename') + +[FILELoad] +compress = true +location = /tmp/upload +[unpack] + + diff --git a/data-workflow/v1/conditormetrie.cfg b/data-workflow/v1/conditormetrie.cfg new file mode 100644 index 0000000..1a0d9ac --- /dev/null +++ b/data-workflow/v1/conditormetrie.cfg @@ -0,0 +1,395 @@ +[use] +plugin = basics +plugin = analytics + +[env] +path = number2labelDR +value = fix({"01": "DR01 Ile-de-France Villejuif","02": "DR02 Paris-Centre","04": "DR04 Ile-de-France Gif-sur-Yvette","05": "DR05 Ile-de-France Meudon","16": "DR16 Paris-Normandie","06": "DR06 Centre Est","10": "DR10 Alsace","08": "DR08 Centre Limousin Poitou Charente","17": "DR17 Bretagne et Pays de la Loire","18": "DR18 Hauts-de-France","07": "DR07 Rhône Auvergne","11": "DR11 Alpes","12": "DR12 Provence et Corse","20": "DR20 Côte d'Azur","13": "DR13 Occitanie Est","14": "DR14 Occitanie Ouest","15": "DR15 Aquitaine"}) + + +[assign] +# Récupère electronicPublicationDate et publicationDate +# Prend la plus ancienne (= la plus petite) +# Ne garde que l'année +path = ApilPublicationDate +value = get("host.electronicPublicationDate", "9999") \ + .castArray() \ + .concat(_.get(self, "host.publicationDate", "9999")) \ + .min().toString() \ + .thru(str => str.substring(0,4)) + +[assign] +path = ApilFinancement +value = get('funders').castArray().filter(Boolean).thru(arr => Boolean(arr.length)) + +# Quand les RNSR ne sont pas fournis dans authors.*.affiliations.*.rnsr +# on utilise les enrichissements et on les met au même niveau dans ApilRnsr +[map] +path = authors + +[map/map] +path = affiliations + +[map/map/assign] +path = ApilRnsr1 +value = get("rnsr") + +[map/map/swing] +test = get("ApilRnsr1").isEmpty() +[map/map/swing/assign] +path = ApilRnsr +value = get("enrichments.rnsr", []) \ + .filter(rnsr => !["200612821P", "200018571R", "199812965F", "201523784S"].includes(rnsr)) + +# On rassemble tous les RNSR au niveau de la notice (ceux en provenance de +# authors.*.rnsr et ceux en provenance de authors.*.affiliations.*) +# dans allAuthorsRnsr +[assign] +path=ApilRnsr2 +value= get("authors").map("rnsr").flatten() + +[assign] +path = allApilRnsr1 +; value= get("authors").map("affiliations").map("ApilRnsr1") +value= get("authors").flatMap("affiliations").flatMap("ApilRnsr1") + +[assign] +path= ApilRnsr +value= get("allApilRnsr1").concat(self.ApilRnsr2).compact().uniq() + +# Garde un identifiant +[assign] +path = sourceUidChain +value = get("business.sourceUidChain") + +#On ajoute un objet pour attribuer 'OA - Inconnu' aux null ou undefined +path = enrichments.openAccess.unpaywall.oaLocations +value = get("enrichments.openAccess.unpaywall.oaLocations",[{"hostType":"OA - Inconnu"}]) + +# Supprime les champs inutiles pour les études bibliométriques +[exchange] +value = omit(['business','origins','technical','allApilRnsr1','ApilRnsr2']) +append = pack + + +# Quand les RNSR ne sont pas fournis dans authors.*.affiliations.*.rnsr +# on utilise le Web Service qui les met au même niveau dans wsRnsr + +# Récupère les infos Loterre 2XK +[assign] +path = ws.loterre2xk +value = get("ApilRnsr").castArray().map((itemApilRnsr, indice) => ({indice, itemApilRnsr, codeRNSR: itemApilRnsr, institut: itemApilRnsr, publicationDate: self.ApilPublicationDate })) + +[expand] +path = ws.loterre2xk + +[expand/exploding] + +[expand/expand] +path = value.itemApilRnsr +size = 100 +cacheName = 04-2xk-identify + +[expand/expand/URLConnect] +url = https://loterre-resolvers.services.istex.fr/v1/2XK/identify +timeout = 120000 +noerror = true + +[expand/assign] +path = value.institut +value = get('value.institut').append(`|${self.value.publicationDate}`) + +[expand/expand] +path = value.institut +size = 100 +cacheName = 04-rnsr-year-instituts-cnrs + +[expand/expand/URLConnect] +url = https://mapping-tools.services.istex.fr/v1/rnsr-year/instituts-cnrs +timeout = 90002 +noerror = true + +[expand/assign] +path = value.label +value = get('value.itemApilRnsr.prefLabel@fr', 'n/a') + +path = value.labelNormalized +value = get('value.itemApilRnsr.prefLabel@fr', 'n/a').thru(item => String(item).normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toUpperCase()) + +path = value.dr +value = get("value.itemApilRnsr.delegationRegionale_dep").castArray().compact().map(n => _.get(env("number2labelDR"), n, `unknow ${n}` )) + +[expand/aggregate] + +[assign] +path = ApilRnsr +value = get("ws.loterre2xk").castArray().map('codeRNSR') + +path = ApilWsLaboIntitule +value = get("ws.loterre2xk").castArray().map('label') + +path = ApilWsDr +value = get("ws.loterre2xk").castArray().map('dr') + +path = ApilWsInstitutCnrs +value = get("ws.loterre2xk").castArray().map('institut') + +# S'il y a au moins un institut, il y a au moins une affiliation CNRS +path = ApilWsIsCnrs +value = get("ws.loterre2xk").castArray().map('institut').thru(array => Boolean(array.length)) + +; [debug] +; path = ApilRnsr +; path = ApilWsLaboIntitule +; path = ApilWsDr +; path = ApilWsInstitutCnrs +; path = ApilWsIsCnrs + +############################################################### + +#interrogation d'Openalex depuis le champs doi https://biblio-tools.services.istex.fr/v1/openalex/works/expand +#Pas d'omit sur ce champs, les valeurs apc peuvent eventuellement servir pour d'autres cas +[assign] +path=ApilWsOpenalex +value = get("doi") + +[expand] +path = ApilWsOpenalex +size = 100 + +[expand/URLConnect] +url = https://biblio-tools.services.istex.fr/v1/openalex/works/expand +timeout = 90007 +noerror = true + +# Données Open Access host type modifiées à partir d'un champ fulltext, si hal est présent +#Transformer des données inconnues de 'HostType' en repository si absence d'un DOI mais présence de Hal dans 'fulltext' +[assign] +path=ApilOaLocationsHal +value=get("enrichments.openAccess.unpaywall.oaLocations").map("hostType").concat([self.fulltextUrl].map((value)=>value && value.replace(/^((?!hal).)*$/,"@@@@").replace(/.*hal.*/,"repository"))).uniq().filter((value, index, collection)=>{if(!(value === "OA - Inconnu" && collection[index+1] === "repository" )){return true}}).filter(value=>value!=="@@@@").compact() + +#Transformer des données inconnues en "green" si absence d'un DOI mais présence de "repository" dans 'ApilOaLocationsHal' +[assign] +path=ApilOaStatusHal +value=get("enrichments.openAccess.unpaywall.oaStatus").replace(/^$/,"OA - Inconnu").castArray().concat(self.ApilOaLocationsHal).compact().join(",").replace(/OA - Inconnu,repository|OA - Non,repository|closed,repository/g,"green").split(",").head().capitalize().replace("Oa - inconnu","OA - Inconnu") + +##Transformer des données inconnues en OA-Oui si absence d'un DOI mais présence de "green" dans 'ApiloaStatusHal' +[assign] +path=ApilIsOaHal +value=get("ApilOaStatusHal","OA - Inconnu").replace("closed","OA - Non").replace(/^((?!OA).)*$/,"OA - Oui") + +#On traduit les voies d'acces. Sort pour placer "publisher" avant "repository", replace puis si les 2 valeurs sont présentes, on remplace par "commun" +[assign] +path=ApilTypeDaccesHal +value=get("ApilOaLocationsHal").sort().replace("repository","Archive seule").replace("publisher","Editeur seul").replace("Editeur seul,Archive seule","Commun") + +#on crée un nouveau champ où l'on récupère les valeurs de "apc_list/value". Si value = 0 alors la publi est diamant. On remplace donc "0" par "diamond" et efface tout le reste. On concatène ensuite avec enrichments/openAccess/unpaywall/oaStatus qui donne les couleurs de l'OA. Puis on retire "gold" lorsqu'il est associé à "diamond" +[assign] +path=ApilOaStatusDiamond +value=get("ApilWsOpenalex").castArray().map("apc_list/value").replace(/^(?!0$).*$/,"").replace(/^0$/,"diamond").concat(_.get(self,"enrichments.openAccess.unpaywall.oaStatus")).filter((value, index, collection)=>{if(!(value === "gold" && collection[index-1] === "diamond" )){return true}}).last().capitalize().replace(/^$/,"OA - Inconnu") + + +#on crée un nouveau champ où l'on cumule les nouvelles données de 'ApilOaStatusDiamond' et 'ApilOaStatusHal' +[assign] +path=ApilOaStatusDiamondHal +value=get("ApilOaStatusDiamond").concat(self.ApilOaStatusHal).uniq().filter((value, index, collection)=>{if(!(value === "OA - Inconnu" && collection[index+1] === "Green" )){return true}}).filter((value, index, collection)=>{if(!(value === "Gold" && collection[index-1] === "Diamond" )){return true}}).toString() + +#Transformations spécifiques pour créer des valuers compatibles avec VEga-lite pour la création de graphiques +[assign] +path=ApilGraphSourceEditeurIsOa +value=get("enrichments.openAccess.unpaywall.isOa").replace(/^((?!Oui).)*$/,"null").prepend("OA=").append((";TypeAcces="+self.ApilTypeDaccesHal).replace(/Commun|Editeur seul/g,"Editeur").replace(/OA - Non|Archive seule|OA - Inconnu/g,"null")) + +[assign] +path=ApilGraphSourceEditeurIsOaHal +value=get("ApilIsOaHal").replace(/^((?!Oui).)*$/,"null").prepend("OA=").append((";TypeAcces="+self.ApilTypeDaccesHal).replace(/Commun|Editeur seul/g,"Editeur").replace(/OA - Non|Archive seule|OA - Inconnu/g,"null")) + +#On détermine l'ordre de provenance des notices composants la notice Conditor +[assign] +path = ApilProvenance +value = get("sourceUidChain").replace(/\$.*?!/g,"!").split("!").compact() + +#On concatène 'volume', 'issue' et 'pages.range' dans un seul champ +[assign] +path = ApilCollation +value = get("host.volume").concat(_.get(self,"host.issue")).concat(_.get(self,"host.pages.range")).join(" / ") + +#Récupère les fulltext d'unpaywall si le champs 'fulltexturl' (qui vient de conditor) est nul dans une colonne nommée ApilFullText (je ne sais pas comment on déclare le nom de la colonne dans ce cas précis) + +[assign] +path = fulltextUrl +value = get("fulltextUrl").castArray().compact() + +[swing] +test = get("fulltextUrl").isEmpty() + +[swing/assign] +path = fulltextUrl +value=get("enrichments.openAccess.unpaywall.oaLocations").filter(item=>item.hostType==="repository").map(item=>item.url) + +; [assign] +; path = value +; value = get('fulltextUrl').castArray().uniq() + +#Homogénéise les types de document +[assign] +path = ApilWsTypeDoc +value = get("originalGenre").trim() + +[expand] +path = ApilWsTypeDoc +size = 100 +cacheName = 04-homogenize-document-type-json + +[expand/URLConnect] +url = https://mapping-tools.services.istex.fr/v1/homogenize/documentType/json +timeout = 90003 +noerror = true + +# Si le WS renvoie un "n/a" +[swing] +test = get("ApilWsTypeDoc").isEqual("n/a") + +# On l'écrase avec la valeur de "originalGenre" +[swing/assign] +path = ApilWsTypeDoc +value = get("originalGenre").trim() + +# Homogénéise les sources +[assign] +path = ApilWsSource +value = get("host.title",_.get(self,"host.conference.name")).trim() + +# si les champs 'host.title' et 'host.conference.name' ne sont pas vides +[expand] +path = ApilWsSource +size = 100 +cacheName = 04-homogenize-source-json + +[expand/URLConnect] +url = https://mapping-tools.services.istex.fr/v1/homogenize/source/json +timeout = 90004 +noerror = true + +# si le champ "ApilWsSource" issu du WS est "n/a" +[swing] +test = get("ApilWsSource").isEqual("n/a") + +[swing/assign] +path = ApilWsSource +value = get("host.title",_.get(self,"host.conference.name")).trim() + +# Traitement des éditeurs +[assign] +path = ws.ApilRacineDoiPublisher +value = get("doi").split('/').filter(i => i.match(/^10./)).pop() + +[expand] +path = ws.ApilRacineDoiPublisher +size = 1 +cacheName = 04-api-crossref-prefixes-expand + +[expand/URLFetch] +target = value +url = fix('https://api.crossref.org/prefixes/').append(self.value) +json = true +timeout = 60000 +noerror = true +retries = 2 + +[expand/assign] +path = value +value = get('value.message.name', 'n/a') + +# Dans un champ temporaire, récupérer la valeur host.publisher si elle est présente, sinon récupérer celle du WS DOI. +[assign] +path = tmp.ApilWsPublisher +value = get("host.publisher",_.get(self,"ws.ApilRacineDoiPublisher")) + +# Homogénéise l'éditeur +[assign] +path = ApilWsPublisher +value = get("tmp.ApilWsPublisher").trim() + +[expand] +path = ApilWsPublisher +size = 100 +cacheName = 04-homogenize-publisher-json + +[expand/URLConnect] +url = https://mapping-tools.services.istex.fr/v1/homogenize/publisher/json +timeout = 90006 +noerror = true + +# Si host.publisher existe et que le ApilWsPublisher vaut n/a, +[swing] +test = has("host.publisher") +test = get("ApilWsPublisher").isEqual("n/a") + +# On l'écrase avec la valeur de host.publisher +[swing/assign] +path = ApilWsPublisher +value = get("host.publisher") + +# Enrichissements pays +[assign] +path = ws.libpostal +value = get("authors") \ + .flatMap("affiliations") \ + .map("address").uniq() \ + .map((address, id) => ({ \ + id, \ + value: address \ + })) + +[map] +path = ws.libpostal + +[map/expand] +path = value +size = 100 +cacheName = 04-address-expand + +[map/expand/URLConnect] +url = https://affiliations-tools.services.istex.fr/v1/addresses/parse +timeout = 90007 +noerror = true + +[map/expand/assign] +path = value.value.address +value = get('value.id') + +path = value.value.country +value = get('value.value.country').replace(/\W/g, ' ').trim() + +[map/expand/assign] +path = value +value = get('value.value') + +[map/expand/expand] +path = value.country +size = 10 +cacheName = 04-country-expand + +[map/expand/expand/URLConnect] +url = https://loterre-resolvers.services.istex.fr/v1/9SD/identify +timeout = 90008 + +[map/exchange] +value = get('value') + +# TODO: si champ state, on est aux États-Unis (United States of America) + +[assign] +path = ApilWsCodeISO +value = get("ws.libpostal").castArray().filter(Boolean) \ + .map(n => n.country?.cartographyCode) \ + .uniq().filter(Boolean) + +path = ApilWsCountry +value = get("ws.libpostal").castArray().filter(Boolean) \ + .map(n => n.country?.["prefLabel@en"]) \ + .uniq().filter(Boolean) + +# Suppression des champs non voulus +[exchange] +value = omit(['tmp']) diff --git a/data-workflow/v1/conditormetrie.ini b/data-workflow/v1/conditormetrie.ini new file mode 100644 index 0000000..65fc99c --- /dev/null +++ b/data-workflow/v1/conditormetrie.ini @@ -0,0 +1,65 @@ +# Entrypoint output format +mimeType = application/json + +# OpenAPI Documentation - JSON format (dot notation) +post.operationId = post-v1-conditormetrie +post.description = Enrichissements biliométriques sur un corpus Conditor +post.summary = Le résulat produit une liste de notices enrichies +post.tags.0 = data-workflow +post.requestBody.content.application/x-tar.schema.type = string +post.requestBody.content.application/x-tar.schema.format = binary +post.requestBody.required = true +post.responses.default.description = Informations permettant de récupérer les données le moment venu +post.parameters.0.description = Indenter le JSON résultant +post.parameters.0.in = query +post.parameters.0.name = indent +post.parameters.0.schema.type = boolean +post.parameters.1.description = URL pour signaler que le traitement est terminé +post.parameters.1.in = header +post.parameters.1.name = X-Webhook-Success +post.parameters.1.schema.type = string +post.parameters.1.schema.format = uri +post.parameters.1.required = false +post.parameters.2.description = URL pour signaler que le traitement a échoué +post.parameters.2.in = header +post.parameters.2.name = X-Webhook-Failure +post.parameters.2.schema.type = string +post.parameters.2.schema.format = uri +post.parameters.2.required = false + +[env] +path = generator +value = conditormetrie + +path = language +value = en + +[use] +plugin = basics +plugin = analytics + +# Step 1 (générique): Charger le fichier corpus +[delegate] +file = charger.cfg + +# Step 2 (générique): Traiter de manière asynchnore les items reçus +[fork] +standalone = true +logger = logger.cfg + +# Step 2.0 (optionnel): Accélére le détachement du fork si l'enrichissement est lent +[fork/delegate] +file = buffer.cfg + +# Step 2.1 (spécifique): Lancer un calcul sur tous les items reçus +[fork/delegate] +file = conditormetrie.cfg + +# Step 2.2 (générique): Enregister le résulat et signaler que le traitment est fini +[fork/delegate] +file = recorder.cfg + +# Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt +[delegate] +file = recipient.cfg + diff --git a/data-workflow/v1/logger.cfg b/data-workflow/v1/logger.cfg index 49db973..b46e88a 100644 --- a/data-workflow/v1/logger.cfg +++ b/data-workflow/v1/logger.cfg @@ -9,6 +9,12 @@ text = Error trapped [assign] +path = body.identifier +value = env('identifier') + +path = body.generator +value = env('generator') + path = body.error.type value = get('type') diff --git a/data-workflow/v1/recipient.cfg b/data-workflow/v1/recipient.cfg new file mode 100644 index 0000000..f723830 --- /dev/null +++ b/data-workflow/v1/recipient.cfg @@ -0,0 +1,12 @@ +[use] +plugin = basics + +[shift] +[replace] +path = id +value = env('generator') +path = value +value = env('identifier') + +[JSONString] +indent = env('indent') diff --git a/data-workflow/v1/recorder.cfg b/data-workflow/v1/recorder.cfg index f768491..66e4702 100644 --- a/data-workflow/v1/recorder.cfg +++ b/data-workflow/v1/recorder.cfg @@ -34,10 +34,10 @@ # Step 2.4.3 (faculatif) : Ajouter une trace dans log [swing/debug] -text = webhook triggered +text = WebHook triggered # Step 2.5 (faculatif) : Ajouter une trace dans log [debug] -text = process completed +text = Process completed diff --git a/data-workflow/v1/tag-cloud-en.ini b/data-workflow/v1/tag-cloud-en.ini index 462f6a3..d9ae3bb 100644 --- a/data-workflow/v1/tag-cloud-en.ini +++ b/data-workflow/v1/tag-cloud-en.ini @@ -28,6 +28,9 @@ post.parameters.2.required = false [env] +path = generator +value = tag-cloud-en + path = language value = en @@ -53,12 +56,6 @@ file = recorder.cfg # Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt -[shift] -[replace] -path = id -value = tag-cloud-en -path = value -value = env('identifier') +[delegate] +file = recipient.cfg -[JSONString] -indent = env('indent') diff --git a/data-workflow/v1/tag-cloud-fr.ini b/data-workflow/v1/tag-cloud-fr.ini index 0d77643..715014b 100644 --- a/data-workflow/v1/tag-cloud-fr.ini +++ b/data-workflow/v1/tag-cloud-fr.ini @@ -28,6 +28,9 @@ post.parameters.2.required = false [env] +path = generator +value = tag-cloud-fr + path = language value = fr @@ -53,12 +56,6 @@ file = recorder.cfg # Step 3 : Renvoyer immédiatement un seul élément indiquant comment récupérer le résulat quand il sera prêt -[shift] -[replace] -path = id -value = tag-cloud-fr -path = value -value = env('identifier') +[delegate] +file = recipient.cfg -[JSONString] -indent = env('indent') diff --git a/data-wrapper/v1/istex-tar-gz.ini b/data-wrapper/v1/istex-tar-gz.ini index d72d223..06dd43f 100644 --- a/data-wrapper/v1/istex-tar-gz.ini +++ b/data-wrapper/v1/istex-tar-gz.ini @@ -7,8 +7,8 @@ post.description = Transformation d'un fichier ISTEX (format tar.gz) en fichier corpus post.summary = Le fichier est transformé en fichier coprus exploitable par un web service asynchrone post.tags.0 = data-wrapper -post.requestBody.content.text/csv.schema.type = string -post.requestBody.content.text/csv.schema.format = binary +post.requestBody.content.application/x-tar.schema.type = string +post.requestBody.content.application/x-tar.schema.format = binary post.requestBody.required = true post.responses.default.description = Fichier corpus au format tar.gz post.responses.default.content.application/x-tar.schema.type = string diff --git a/data-wrapper/v1/query-conditor.ini b/data-wrapper/v1/query-conditor.ini new file mode 100644 index 0000000..fba7b82 --- /dev/null +++ b/data-wrapper/v1/query-conditor.ini @@ -0,0 +1,73 @@ +# Entrypoint output format +mimeType = application/x-tar +extension = tar.gz + +# OpenAPI Documentation - JSON format (dot notation) +post.operationId = post-v1-query-conditor +post.description = Téléchargement des documents Conditor répondant à un requete +post.summary = Le fichier en entrée contient une requete dont le résulat produira un fichier coprus exploitable par un web service asynchrone +post.tags.0 = data-wrapper +post.requestBody.content.text/plain.schema.type = string +post.requestBody.content.text/plain.schema.format = binary +post.requestBody.required = true +post.responses.default.description = Fichier corpus au format tar.gz +post.responses.default.content.application/x-tar.schema.type = string +post.responses.default.content.application/x-tar.schema.format = binary +post.parameters.0.description = Nom du champ à exploiter comme identifiant de colonne +post.parameters.0.in = query +post.parameters.0.name = id +post.parameters.0.schema.type = string +post.parameters.0.schema.default = business.sourceUidChain +post.parameters.0.required = false +post.parameters.1.description = Nom du champ à exploiter comme identifiant de ligne +post.parameters.1.in = query +post.parameters.1.name = value +post.parameters.1.schema.type = string +post.parameters.1.schema.default = title.en +post.parameters.1.required = false +post.parameters.2.description = chaque ligne est réduite à un object contenant 2 champs (id, value) +post.parameters.2.in = query +post.parameters.2.name = slim +post.parameters.2.schema.type = boolean +post.parameters.2.schema.default = true +post.parameters.2.required = false + +[env] +path = slim +value = env('slim').thru(x => (x === 'false' ? false : true)) + +[use] +plugin = basics +plugin = conditor + +[TXTConcat] + +[replace] +path = q +value = self().trim() + +[CORHALFetch] +url = https://corhal-api.inist.fr +retries = 3 +timeout = 60000 + +[assign] +path = id +value = get(env('id', 'business.sourceUidChain')) +path = value +value = get(env('value', 'title.en')) +value = self() + +[exchange] +value = self().thru(x => _.env(null, 'slim') ? _.pick(x, ['id', 'value']) : x) + +[TARDump] +compress = true +manifest = fix({version: '1'}) +manifest = fix({generator: 'v1/query-conditor'}) +manifest = fix({parameters: _.omit(_.env(), 'headers')}) +manifest = fix({hostAgent: _.get(_.env(), 'headers.host')}) +manifest = fix({userAgent: _.get(_.env(), 'headers.user-agent')}) + + + diff --git a/data-wrapper/v1/query-istex.ini b/data-wrapper/v1/query-istex.ini new file mode 100644 index 0000000..d5acc90 --- /dev/null +++ b/data-wrapper/v1/query-istex.ini @@ -0,0 +1,74 @@ +# Entrypoint output format +mimeType = application/x-tar +extension = tar.gz + +# OpenAPI Documentation - JSON format (dot notation) +post.operationId = post-v1-query-istex +post.description = Téléchargement des documents ISTEX répondant à une requete +post.summary = Le fichier en entrée contient une requete dont le résulat produira un fichier coprus exploitable par un web service asynchrone +post.tags.0 = data-wrapper +post.requestBody.content.text/plain.schema.type = string +post.requestBody.content.text/plain.schema.format = binary +post.requestBody.required = true +post.responses.default.description = Fichier corpus au format tar.gz +post.responses.default.content.application/x-tar.schema.type = string +post.responses.default.content.application/x-tar.schema.format = binary +post.parameters.0.description = Nom du champ à exploiter comme identifiant de colonne +post.parameters.0.in = query +post.parameters.0.name = id +post.parameters.0.schema.type = string +post.parameters.0.schema.default = arkIstex +post.parameters.0.required = false +post.parameters.1.description = Nom du champ à exploiter comme identifiant de ligne +post.parameters.1.in = query +post.parameters.1.name = value +post.parameters.1.schema.type = string +post.parameters.1.schema.default = title +post.parameters.1.required = false +post.parameters.2.description = chaque ligne est réduite à un object contenant 2 champs (id, value) +post.parameters.2.in = query +post.parameters.2.name = slim +post.parameters.2.schema.type = boolean +post.parameters.2.schema.default = true +post.parameters.2.required = false + +[env] +path = slim +value = env('slim').thru(x => (x === 'false' ? false : true)) + +[use] +plugin = basics +plugin = istex + +[TXTConcat] + +[replace] +path = q +value = self().trim() + +[ISTEXScroll] +query = get('q') +field = * + +[ISTEXResult] + +[assign] +path = id +value = get(env('id', 'arkIstex')) +path = value +value = get(env('value', 'title')) +value = self() + +[exchange] +value = self().thru(x => _.env(null, 'slim') ? _.pick(x, ['id', 'value']) : x) + +[TARDump] +compress = true +manifest = fix({version: '1'}) +manifest = fix({generator: 'v1/query-istex'}) +manifest = fix({parameters: _.omit(_.env(), 'headers')}) +manifest = fix({hostAgent: _.get(_.env(), 'headers.host')}) +manifest = fix({userAgent: _.get(_.env(), 'headers.user-agent')}) + + +