Newer
Older
web-services / data-workflow / v1 / conditormetrie.cfg
@Nicolas Thouvenin Nicolas Thouvenin on 20 Nov 13 KB fix: accelerates synchronous response
[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'])