invenio-vocabularies 9.1.2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. invenio_vocabularies/__init__.py +16 -0
  2. invenio_vocabularies/administration/__init__.py +10 -0
  3. invenio_vocabularies/administration/views/__init__.py +10 -0
  4. invenio_vocabularies/administration/views/vocabularies.py +43 -0
  5. invenio_vocabularies/alembic/17c703ce1eb7_create_names_table.py +54 -0
  6. invenio_vocabularies/alembic/3ba812d80559_add_internal_name_id.py +36 -0
  7. invenio_vocabularies/alembic/4a9a4fd235f8_create_vocabulary_schemes.py +37 -0
  8. invenio_vocabularies/alembic/4f365fced43f_create_vocabularies_tables.py +92 -0
  9. invenio_vocabularies/alembic/55a700f897b6_add_names_and_afiliations_pid_column.py +96 -0
  10. invenio_vocabularies/alembic/6312f33645c1_create_affiliations_table.py +54 -0
  11. invenio_vocabularies/alembic/676dd587542d_create_funders_vocabulary_table.py +58 -0
  12. invenio_vocabularies/alembic/8ff82dfb0be8_create_vocabularies_branch.py +28 -0
  13. invenio_vocabularies/alembic/__init__.py +9 -0
  14. invenio_vocabularies/alembic/af2457652217_drop_unique_constraint_from_internal_id.py +37 -0
  15. invenio_vocabularies/alembic/e1146238edd3_create_awards_table.py +56 -0
  16. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/.eslintrc.yml +11 -0
  17. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/.prettierrc +1 -0
  18. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/index.js +7 -0
  19. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/package.json +25 -0
  20. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/AwardResults.js +95 -0
  21. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/CustomAwardForm.js +139 -0
  22. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FunderDropdown.js +87 -0
  23. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingField.js +244 -0
  24. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingField.test.js +1 -0
  25. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingFieldItem.js +152 -0
  26. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingModal.js +246 -0
  27. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/NoAwardResults.js +37 -0
  28. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/index.js +8 -0
  29. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/index.js +7 -0
  30. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/index.js +7 -0
  31. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/index.js +7 -0
  32. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/i18next.js +36 -0
  33. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/_generatedTranslations.js +66 -0
  34. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ar/messages.po +96 -0
  35. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ar/translations.json +28 -0
  36. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/bg/messages.po +94 -0
  37. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/bg/translations.json +28 -0
  38. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ca/messages.po +94 -0
  39. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ca/translations.json +28 -0
  40. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/cs/messages.po +97 -0
  41. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/cs/translations.json +28 -0
  42. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/da/messages.po +94 -0
  43. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/da/translations.json +28 -0
  44. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/de/messages.po +98 -0
  45. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/de/translations.json +28 -0
  46. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/el/messages.po +94 -0
  47. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/el/translations.json +28 -0
  48. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/en/messages.po +88 -0
  49. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/en/translations.json +28 -0
  50. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/es/messages.po +96 -0
  51. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/es/translations.json +28 -0
  52. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/et/messages.po +95 -0
  53. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/et/translations.json +28 -0
  54. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/fa/messages.po +94 -0
  55. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/fa/translations.json +28 -0
  56. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/fr/messages.po +96 -0
  57. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/fr/translations.json +28 -0
  58. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/hr/messages.po +94 -0
  59. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/hr/translations.json +28 -0
  60. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/hu/messages.po +96 -0
  61. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/hu/translations.json +28 -0
  62. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/index.js +24 -0
  63. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/it/messages.po +96 -0
  64. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/it/translations.json +28 -0
  65. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ja/messages.po +94 -0
  66. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ja/translations.json +28 -0
  67. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ka/messages.po +94 -0
  68. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ka/translations.json +28 -0
  69. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ko/messages.po +90 -0
  70. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ko/translations.json +28 -0
  71. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/lt/messages.po +94 -0
  72. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/lt/translations.json +28 -0
  73. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/no/messages.po +94 -0
  74. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/no/translations.json +28 -0
  75. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/pl/messages.po +94 -0
  76. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/pl/translations.json +28 -0
  77. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/pt/messages.po +94 -0
  78. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/pt/translations.json +28 -0
  79. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ro/messages.po +95 -0
  80. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ro/translations.json +28 -0
  81. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ru/messages.po +95 -0
  82. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/ru/translations.json +28 -0
  83. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/sk/messages.po +94 -0
  84. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/sk/translations.json +28 -0
  85. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/sv/messages.po +98 -0
  86. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/sv/translations.json +28 -0
  87. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/tr/messages.po +96 -0
  88. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/tr/translations.json +28 -0
  89. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/uk/messages.po +94 -0
  90. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/uk/translations.json +28 -0
  91. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/zh_CN/messages.po +96 -0
  92. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/zh_CN/translations.json +28 -0
  93. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/zh_TW/messages.po +94 -0
  94. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/messages/zh_TW/translations.json +28 -0
  95. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/package.json +19 -0
  96. invenio_vocabularies/assets/semantic-ui/translations/invenio_vocabularies/translations.pot +88 -0
  97. invenio_vocabularies/cli.py +175 -0
  98. invenio_vocabularies/config.py +231 -0
  99. invenio_vocabularies/contrib/__init__.py +9 -0
  100. invenio_vocabularies/contrib/affiliations/__init__.py +20 -0
  101. invenio_vocabularies/contrib/affiliations/affiliations.py +61 -0
  102. invenio_vocabularies/contrib/affiliations/api.py +13 -0
  103. invenio_vocabularies/contrib/affiliations/config.py +79 -0
  104. invenio_vocabularies/contrib/affiliations/datastreams.py +301 -0
  105. invenio_vocabularies/contrib/affiliations/facets.py +36 -0
  106. invenio_vocabularies/contrib/affiliations/jsonschemas/__init__.py +9 -0
  107. invenio_vocabularies/contrib/affiliations/jsonschemas/affiliations/affiliation-v1.0.0.json +63 -0
  108. invenio_vocabularies/contrib/affiliations/mappings/__init__.py +10 -0
  109. invenio_vocabularies/contrib/affiliations/mappings/os-v1/__init__.py +9 -0
  110. invenio_vocabularies/contrib/affiliations/mappings/os-v1/affiliations/affiliation-v1.0.0.json +112 -0
  111. invenio_vocabularies/contrib/affiliations/mappings/os-v1/affiliations/affiliation-v2.0.0.json +171 -0
  112. invenio_vocabularies/contrib/affiliations/mappings/os-v2/__init__.py +9 -0
  113. invenio_vocabularies/contrib/affiliations/mappings/os-v2/affiliations/affiliation-v1.0.0.json +112 -0
  114. invenio_vocabularies/contrib/affiliations/mappings/os-v2/affiliations/affiliation-v2.0.0.json +171 -0
  115. invenio_vocabularies/contrib/affiliations/mappings/v7/__init__.py +9 -0
  116. invenio_vocabularies/contrib/affiliations/mappings/v7/affiliations/affiliation-v1.0.0.json +112 -0
  117. invenio_vocabularies/contrib/affiliations/models.py +13 -0
  118. invenio_vocabularies/contrib/affiliations/resources.py +16 -0
  119. invenio_vocabularies/contrib/affiliations/schema.py +71 -0
  120. invenio_vocabularies/contrib/affiliations/services.py +15 -0
  121. invenio_vocabularies/contrib/awards/__init__.py +19 -0
  122. invenio_vocabularies/contrib/awards/api.py +13 -0
  123. invenio_vocabularies/contrib/awards/awards.py +96 -0
  124. invenio_vocabularies/contrib/awards/config.py +59 -0
  125. invenio_vocabularies/contrib/awards/datastreams.py +372 -0
  126. invenio_vocabularies/contrib/awards/jsonschemas/__init__.py +9 -0
  127. invenio_vocabularies/contrib/awards/jsonschemas/awards/award-v1.0.0.json +91 -0
  128. invenio_vocabularies/contrib/awards/mappings/__init__.py +9 -0
  129. invenio_vocabularies/contrib/awards/mappings/os-v1/__init__.py +9 -0
  130. invenio_vocabularies/contrib/awards/mappings/os-v1/awards/award-v1.0.0.json +147 -0
  131. invenio_vocabularies/contrib/awards/mappings/os-v2/__init__.py +9 -0
  132. invenio_vocabularies/contrib/awards/mappings/os-v2/awards/award-v1.0.0.json +147 -0
  133. invenio_vocabularies/contrib/awards/mappings/v7/__init__.py +9 -0
  134. invenio_vocabularies/contrib/awards/mappings/v7/awards/award-v1.0.0.json +147 -0
  135. invenio_vocabularies/contrib/awards/models.py +13 -0
  136. invenio_vocabularies/contrib/awards/resources.py +16 -0
  137. invenio_vocabularies/contrib/awards/schema.py +119 -0
  138. invenio_vocabularies/contrib/awards/serializer.py +47 -0
  139. invenio_vocabularies/contrib/awards/services.py +15 -0
  140. invenio_vocabularies/contrib/common/__init__.py +9 -0
  141. invenio_vocabularies/contrib/common/openaire/__init__.py +9 -0
  142. invenio_vocabularies/contrib/common/openaire/datastreams.py +84 -0
  143. invenio_vocabularies/contrib/common/ror/__init__.py +9 -0
  144. invenio_vocabularies/contrib/common/ror/datastreams.py +230 -0
  145. invenio_vocabularies/contrib/funders/__init__.py +19 -0
  146. invenio_vocabularies/contrib/funders/api.py +13 -0
  147. invenio_vocabularies/contrib/funders/config.py +78 -0
  148. invenio_vocabularies/contrib/funders/datastreams.py +97 -0
  149. invenio_vocabularies/contrib/funders/facets.py +36 -0
  150. invenio_vocabularies/contrib/funders/funders.py +72 -0
  151. invenio_vocabularies/contrib/funders/jsonschemas/__init__.py +9 -0
  152. invenio_vocabularies/contrib/funders/jsonschemas/funders/funder-v1.0.0.json +65 -0
  153. invenio_vocabularies/contrib/funders/mappings/__init__.py +9 -0
  154. invenio_vocabularies/contrib/funders/mappings/os-v1/__init__.py +9 -0
  155. invenio_vocabularies/contrib/funders/mappings/os-v1/funders/funder-v1.0.0.json +90 -0
  156. invenio_vocabularies/contrib/funders/mappings/os-v1/funders/funder-v2.0.0.json +156 -0
  157. invenio_vocabularies/contrib/funders/mappings/os-v2/__init__.py +9 -0
  158. invenio_vocabularies/contrib/funders/mappings/os-v2/funders/funder-v1.0.0.json +90 -0
  159. invenio_vocabularies/contrib/funders/mappings/os-v2/funders/funder-v2.0.0.json +156 -0
  160. invenio_vocabularies/contrib/funders/mappings/v7/__init__.py +9 -0
  161. invenio_vocabularies/contrib/funders/mappings/v7/funders/funder-v1.0.0.json +90 -0
  162. invenio_vocabularies/contrib/funders/models.py +13 -0
  163. invenio_vocabularies/contrib/funders/resources.py +16 -0
  164. invenio_vocabularies/contrib/funders/schema.py +88 -0
  165. invenio_vocabularies/contrib/funders/serializer.py +33 -0
  166. invenio_vocabularies/contrib/funders/services.py +15 -0
  167. invenio_vocabularies/contrib/names/__init__.py +19 -0
  168. invenio_vocabularies/contrib/names/api.py +13 -0
  169. invenio_vocabularies/contrib/names/components.py +24 -0
  170. invenio_vocabularies/contrib/names/config.py +75 -0
  171. invenio_vocabularies/contrib/names/datastreams.py +483 -0
  172. invenio_vocabularies/contrib/names/jsonschemas/__init__.py +9 -0
  173. invenio_vocabularies/contrib/names/jsonschemas/names/name-v1.0.0.json +68 -0
  174. invenio_vocabularies/contrib/names/mappings/__init__.py +9 -0
  175. invenio_vocabularies/contrib/names/mappings/os-v1/__init__.py +9 -0
  176. invenio_vocabularies/contrib/names/mappings/os-v1/names/name-v1.0.0.json +101 -0
  177. invenio_vocabularies/contrib/names/mappings/os-v1/names/name-v2.0.0.json +165 -0
  178. invenio_vocabularies/contrib/names/mappings/os-v2/__init__.py +9 -0
  179. invenio_vocabularies/contrib/names/mappings/os-v2/names/name-v1.0.0.json +101 -0
  180. invenio_vocabularies/contrib/names/mappings/os-v2/names/name-v2.0.0.json +165 -0
  181. invenio_vocabularies/contrib/names/mappings/v7/__init__.py +9 -0
  182. invenio_vocabularies/contrib/names/mappings/v7/names/name-v1.0.0.json +101 -0
  183. invenio_vocabularies/contrib/names/models.py +13 -0
  184. invenio_vocabularies/contrib/names/names.py +80 -0
  185. invenio_vocabularies/contrib/names/permissions.py +30 -0
  186. invenio_vocabularies/contrib/names/resources.py +54 -0
  187. invenio_vocabularies/contrib/names/s3client.py +50 -0
  188. invenio_vocabularies/contrib/names/schema.py +121 -0
  189. invenio_vocabularies/contrib/names/services.py +64 -0
  190. invenio_vocabularies/contrib/subjects/__init__.py +22 -0
  191. invenio_vocabularies/contrib/subjects/api.py +14 -0
  192. invenio_vocabularies/contrib/subjects/config.py +90 -0
  193. invenio_vocabularies/contrib/subjects/datastreams.py +63 -0
  194. invenio_vocabularies/contrib/subjects/euroscivoc/__init__.py +9 -0
  195. invenio_vocabularies/contrib/subjects/euroscivoc/datastreams.py +101 -0
  196. invenio_vocabularies/contrib/subjects/facets.py +23 -0
  197. invenio_vocabularies/contrib/subjects/gemet/__init__.py +9 -0
  198. invenio_vocabularies/contrib/subjects/gemet/datastreams.py +140 -0
  199. invenio_vocabularies/contrib/subjects/jsonschemas/__init__.py +10 -0
  200. invenio_vocabularies/contrib/subjects/jsonschemas/subjects/subject-v1.0.0.json +69 -0
  201. invenio_vocabularies/contrib/subjects/mappings/__init__.py +9 -0
  202. invenio_vocabularies/contrib/subjects/mappings/os-v1/__init__.py +9 -0
  203. invenio_vocabularies/contrib/subjects/mappings/os-v1/subjects/subject-v1.0.0.json +96 -0
  204. invenio_vocabularies/contrib/subjects/mappings/os-v2/__init__.py +9 -0
  205. invenio_vocabularies/contrib/subjects/mappings/os-v2/subjects/subject-v1.0.0.json +96 -0
  206. invenio_vocabularies/contrib/subjects/mappings/v7/__init__.py +9 -0
  207. invenio_vocabularies/contrib/subjects/mappings/v7/subjects/subject-v1.0.0.json +96 -0
  208. invenio_vocabularies/contrib/subjects/mesh/__init__.py +9 -0
  209. invenio_vocabularies/contrib/subjects/mesh/datastreams.py +48 -0
  210. invenio_vocabularies/contrib/subjects/models.py +14 -0
  211. invenio_vocabularies/contrib/subjects/nvs/__init__.py +9 -0
  212. invenio_vocabularies/contrib/subjects/nvs/datastreams.py +114 -0
  213. invenio_vocabularies/contrib/subjects/resources.py +17 -0
  214. invenio_vocabularies/contrib/subjects/schema.py +101 -0
  215. invenio_vocabularies/contrib/subjects/services.py +30 -0
  216. invenio_vocabularies/contrib/subjects/subjects.py +55 -0
  217. invenio_vocabularies/datastreams/__init__.py +18 -0
  218. invenio_vocabularies/datastreams/datastreams.py +239 -0
  219. invenio_vocabularies/datastreams/errors.py +29 -0
  220. invenio_vocabularies/datastreams/factories.py +86 -0
  221. invenio_vocabularies/datastreams/readers.py +448 -0
  222. invenio_vocabularies/datastreams/tasks.py +115 -0
  223. invenio_vocabularies/datastreams/transformers.py +130 -0
  224. invenio_vocabularies/datastreams/writers.py +222 -0
  225. invenio_vocabularies/datastreams/xml.py +34 -0
  226. invenio_vocabularies/ext.py +179 -0
  227. invenio_vocabularies/factories.py +193 -0
  228. invenio_vocabularies/fixtures.py +52 -0
  229. invenio_vocabularies/jobs.py +207 -0
  230. invenio_vocabularies/proxies.py +27 -0
  231. invenio_vocabularies/records/__init__.py +9 -0
  232. invenio_vocabularies/records/api.py +53 -0
  233. invenio_vocabularies/records/jsonschemas/__init__.py +9 -0
  234. invenio_vocabularies/records/jsonschemas/vocabularies/definitions-v1.0.0.json +30 -0
  235. invenio_vocabularies/records/jsonschemas/vocabularies/vocabulary-v1.0.0.json +55 -0
  236. invenio_vocabularies/records/mappings/__init__.py +9 -0
  237. invenio_vocabularies/records/mappings/os-v1/__init__.py +9 -0
  238. invenio_vocabularies/records/mappings/os-v1/vocabularies/vocabulary-v1.0.0.json +109 -0
  239. invenio_vocabularies/records/mappings/os-v2/__init__.py +9 -0
  240. invenio_vocabularies/records/mappings/os-v2/vocabularies/vocabulary-v1.0.0.json +109 -0
  241. invenio_vocabularies/records/mappings/v7/__init__.py +9 -0
  242. invenio_vocabularies/records/mappings/v7/vocabularies/vocabulary-v1.0.0.json +109 -0
  243. invenio_vocabularies/records/models.py +90 -0
  244. invenio_vocabularies/records/pidprovider.py +118 -0
  245. invenio_vocabularies/records/systemfields/__init__.py +16 -0
  246. invenio_vocabularies/records/systemfields/pid.py +125 -0
  247. invenio_vocabularies/records/systemfields/relations.py +51 -0
  248. invenio_vocabularies/resources/__init__.py +23 -0
  249. invenio_vocabularies/resources/config.py +105 -0
  250. invenio_vocabularies/resources/resource.py +156 -0
  251. invenio_vocabularies/resources/schema.py +21 -0
  252. invenio_vocabularies/resources/serializer.py +39 -0
  253. invenio_vocabularies/services/__init__.py +19 -0
  254. invenio_vocabularies/services/components.py +58 -0
  255. invenio_vocabularies/services/config.py +173 -0
  256. invenio_vocabularies/services/custom_fields/__init__.py +17 -0
  257. invenio_vocabularies/services/custom_fields/subject.py +82 -0
  258. invenio_vocabularies/services/custom_fields/vocabulary.py +96 -0
  259. invenio_vocabularies/services/facets.py +114 -0
  260. invenio_vocabularies/services/generators.py +38 -0
  261. invenio_vocabularies/services/permissions.py +30 -0
  262. invenio_vocabularies/services/querystr.py +57 -0
  263. invenio_vocabularies/services/results.py +110 -0
  264. invenio_vocabularies/services/schema.py +163 -0
  265. invenio_vocabularies/services/service.py +189 -0
  266. invenio_vocabularies/services/tasks.py +38 -0
  267. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/subjects.html +23 -0
  268. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabularies-list.html +12 -0
  269. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabulary-details.html +71 -0
  270. invenio_vocabularies/translations/ar/LC_MESSAGES/messages.mo +0 -0
  271. invenio_vocabularies/translations/ar/LC_MESSAGES/messages.po +277 -0
  272. invenio_vocabularies/translations/bg/LC_MESSAGES/messages.mo +0 -0
  273. invenio_vocabularies/translations/bg/LC_MESSAGES/messages.po +275 -0
  274. invenio_vocabularies/translations/ca/LC_MESSAGES/messages.mo +0 -0
  275. invenio_vocabularies/translations/ca/LC_MESSAGES/messages.po +276 -0
  276. invenio_vocabularies/translations/cs/LC_MESSAGES/messages.mo +0 -0
  277. invenio_vocabularies/translations/cs/LC_MESSAGES/messages.po +281 -0
  278. invenio_vocabularies/translations/da/LC_MESSAGES/messages.mo +0 -0
  279. invenio_vocabularies/translations/da/LC_MESSAGES/messages.po +271 -0
  280. invenio_vocabularies/translations/de/LC_MESSAGES/messages.mo +0 -0
  281. invenio_vocabularies/translations/de/LC_MESSAGES/messages.po +293 -0
  282. invenio_vocabularies/translations/el/LC_MESSAGES/messages.mo +0 -0
  283. invenio_vocabularies/translations/el/LC_MESSAGES/messages.po +275 -0
  284. invenio_vocabularies/translations/es/LC_MESSAGES/messages.mo +0 -0
  285. invenio_vocabularies/translations/es/LC_MESSAGES/messages.po +281 -0
  286. invenio_vocabularies/translations/et/LC_MESSAGES/messages.mo +0 -0
  287. invenio_vocabularies/translations/et/LC_MESSAGES/messages.po +276 -0
  288. invenio_vocabularies/translations/fa/LC_MESSAGES/messages.mo +0 -0
  289. invenio_vocabularies/translations/fa/LC_MESSAGES/messages.po +275 -0
  290. invenio_vocabularies/translations/fr/LC_MESSAGES/messages.mo +0 -0
  291. invenio_vocabularies/translations/fr/LC_MESSAGES/messages.po +279 -0
  292. invenio_vocabularies/translations/hr/LC_MESSAGES/messages.mo +0 -0
  293. invenio_vocabularies/translations/hr/LC_MESSAGES/messages.po +275 -0
  294. invenio_vocabularies/translations/hu/LC_MESSAGES/messages.mo +0 -0
  295. invenio_vocabularies/translations/hu/LC_MESSAGES/messages.po +280 -0
  296. invenio_vocabularies/translations/it/LC_MESSAGES/messages.mo +0 -0
  297. invenio_vocabularies/translations/it/LC_MESSAGES/messages.po +277 -0
  298. invenio_vocabularies/translations/ja/LC_MESSAGES/messages.mo +0 -0
  299. invenio_vocabularies/translations/ja/LC_MESSAGES/messages.po +275 -0
  300. invenio_vocabularies/translations/ka/LC_MESSAGES/messages.mo +0 -0
  301. invenio_vocabularies/translations/ka/LC_MESSAGES/messages.po +275 -0
  302. invenio_vocabularies/translations/ko/LC_MESSAGES/messages.mo +0 -0
  303. invenio_vocabularies/translations/ko/LC_MESSAGES/messages.po +275 -0
  304. invenio_vocabularies/translations/lt/LC_MESSAGES/messages.mo +0 -0
  305. invenio_vocabularies/translations/lt/LC_MESSAGES/messages.po +275 -0
  306. invenio_vocabularies/translations/messages.pot +270 -0
  307. invenio_vocabularies/translations/no/LC_MESSAGES/messages.mo +0 -0
  308. invenio_vocabularies/translations/no/LC_MESSAGES/messages.po +275 -0
  309. invenio_vocabularies/translations/pl/LC_MESSAGES/messages.mo +0 -0
  310. invenio_vocabularies/translations/pl/LC_MESSAGES/messages.po +275 -0
  311. invenio_vocabularies/translations/pt/LC_MESSAGES/messages.mo +0 -0
  312. invenio_vocabularies/translations/pt/LC_MESSAGES/messages.po +275 -0
  313. invenio_vocabularies/translations/ro/LC_MESSAGES/messages.mo +0 -0
  314. invenio_vocabularies/translations/ro/LC_MESSAGES/messages.po +280 -0
  315. invenio_vocabularies/translations/ru/LC_MESSAGES/messages.mo +0 -0
  316. invenio_vocabularies/translations/ru/LC_MESSAGES/messages.po +276 -0
  317. invenio_vocabularies/translations/sk/LC_MESSAGES/messages.mo +0 -0
  318. invenio_vocabularies/translations/sk/LC_MESSAGES/messages.po +276 -0
  319. invenio_vocabularies/translations/sv/LC_MESSAGES/messages.mo +0 -0
  320. invenio_vocabularies/translations/sv/LC_MESSAGES/messages.po +280 -0
  321. invenio_vocabularies/translations/tr/LC_MESSAGES/messages.mo +0 -0
  322. invenio_vocabularies/translations/tr/LC_MESSAGES/messages.po +277 -0
  323. invenio_vocabularies/translations/uk/LC_MESSAGES/messages.mo +0 -0
  324. invenio_vocabularies/translations/uk/LC_MESSAGES/messages.po +275 -0
  325. invenio_vocabularies/translations/zh_CN/LC_MESSAGES/messages.mo +0 -0
  326. invenio_vocabularies/translations/zh_CN/LC_MESSAGES/messages.po +276 -0
  327. invenio_vocabularies/translations/zh_TW/LC_MESSAGES/messages.mo +0 -0
  328. invenio_vocabularies/translations/zh_TW/LC_MESSAGES/messages.po +275 -0
  329. invenio_vocabularies/views.py +53 -0
  330. invenio_vocabularies/webpack.py +51 -0
  331. invenio_vocabularies-9.1.2.dist-info/METADATA +517 -0
  332. invenio_vocabularies-9.1.2.dist-info/RECORD +337 -0
  333. invenio_vocabularies-9.1.2.dist-info/WHEEL +6 -0
  334. invenio_vocabularies-9.1.2.dist-info/entry_points.txt +73 -0
  335. invenio_vocabularies-9.1.2.dist-info/licenses/AUTHORS.rst +13 -0
  336. invenio_vocabularies-9.1.2.dist-info/licenses/LICENSE +21 -0
  337. invenio_vocabularies-9.1.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,19 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2021-2022 CERN.
4
+ #
5
+ # Invenio-Vocabularies is free software; you can redistribute it and/or
6
+ # modify it under the terms of the MIT License; see LICENSE file for more
7
+ # details.
8
+
9
+ """Awards vocabulary."""
10
+
11
+ from .resources import AwardsResource, AwardsResourceConfig
12
+ from .services import AwardsService, AwardsServiceConfig
13
+
14
+ __all__ = [
15
+ "AwardsResource",
16
+ "AwardsResourceConfig",
17
+ "AwardsService",
18
+ "AwardsServiceConfig",
19
+ ]
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2022 CERN.
4
+ #
5
+ # Invenio-Vocabularies is free software; you can redistribute it and/or
6
+ # modify it under the terms of the MIT License; see LICENSE file for more
7
+ # details.
8
+
9
+ """Vocabulary awards."""
10
+
11
+ from .awards import record_type
12
+
13
+ Award = record_type.record_cls
@@ -0,0 +1,96 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2022-2024 CERN.
4
+ #
5
+ # Invenio-Vocabularies is free software; you can redistribute it and/or
6
+ # modify it under the terms of the MIT License; see LICENSE file for more
7
+ # details.
8
+
9
+ """Vocabulary awards."""
10
+
11
+ from flask_resources import (
12
+ BaseListSchema,
13
+ JSONSerializer,
14
+ MarshmallowSerializer,
15
+ ResponseHandler,
16
+ )
17
+ from invenio_db import db
18
+ from invenio_records.dumpers import SearchDumper
19
+ from invenio_records.dumpers.indexedat import IndexedAtDumperExt
20
+ from invenio_records.dumpers.relations import RelationDumperExt
21
+ from invenio_records.systemfields import MultiRelationsField
22
+ from invenio_records_resources.factories.factory import RecordTypeFactory
23
+ from invenio_records_resources.records.systemfields import (
24
+ ModelPIDField,
25
+ PIDListRelation,
26
+ PIDRelation,
27
+ )
28
+ from invenio_records_resources.resources.records.headers import etag_headers
29
+
30
+ from invenio_vocabularies.services.permissions import PermissionPolicy
31
+
32
+ from ..funders.api import Funder
33
+ from ..subjects.api import Subject
34
+ from .config import AwardsSearchOptions, service_components
35
+ from .schema import AwardSchema
36
+ from .serializer import AwardL10NItemSchema
37
+
38
+ award_relations = MultiRelationsField(
39
+ funders=PIDRelation(
40
+ "funder",
41
+ keys=["name"],
42
+ pid_field=Funder.pid,
43
+ cache_key="funder",
44
+ ),
45
+ subjects=PIDListRelation(
46
+ "subjects",
47
+ keys=["subject", "scheme", "identifiers", "props"],
48
+ pid_field=Subject.pid,
49
+ cache_key="subjects",
50
+ ),
51
+ )
52
+
53
+ record_type = RecordTypeFactory(
54
+ "Award",
55
+ # Data layer
56
+ pid_field_cls=ModelPIDField,
57
+ pid_field_kwargs={
58
+ "model_field_name": "pid",
59
+ },
60
+ model_cls_attrs={
61
+ # cannot set to nullable=False because it would fail at
62
+ # service level when create({}), see records-resources.
63
+ "pid": db.Column(db.String(255), unique=True),
64
+ },
65
+ record_dumper=SearchDumper(
66
+ model_fields={"pid": ("id", str)},
67
+ extensions=[
68
+ RelationDumperExt("relations"),
69
+ IndexedAtDumperExt(),
70
+ ],
71
+ ),
72
+ schema_version="1.0.0",
73
+ schema_path="local://awards/award-v1.0.0.json",
74
+ record_relations=award_relations,
75
+ # Service layer
76
+ service_id="awards",
77
+ service_schema=AwardSchema,
78
+ search_options=AwardsSearchOptions,
79
+ service_components=service_components,
80
+ permission_policy_cls=PermissionPolicy,
81
+ # Resource layer
82
+ endpoint_route="/awards",
83
+ resource_cls_attrs={
84
+ "response_handlers": {
85
+ "application/json": ResponseHandler(JSONSerializer(), headers=etag_headers),
86
+ "application/vnd.inveniordm.v1+json": ResponseHandler(
87
+ MarshmallowSerializer(
88
+ format_serializer_cls=JSONSerializer,
89
+ object_schema_cls=AwardL10NItemSchema,
90
+ list_schema_cls=BaseListSchema,
91
+ ),
92
+ headers=etag_headers,
93
+ ),
94
+ }
95
+ },
96
+ )
@@ -0,0 +1,59 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2022 CERN.
4
+ #
5
+ # Invenio-Vocabularies is free software; you can redistribute it and/or
6
+ # modify it under the terms of the MIT License; see LICENSE file for more
7
+ # details.
8
+
9
+ """Vocabulary awards configuration."""
10
+
11
+ from flask import current_app
12
+ from invenio_i18n import lazy_gettext as _
13
+ from invenio_records_resources.services import SearchOptions
14
+ from invenio_records_resources.services.records.components import (
15
+ DataComponent,
16
+ RelationsComponent,
17
+ )
18
+ from invenio_records_resources.services.records.facets import TermsFacet
19
+ from invenio_records_resources.services.records.params import SuggestQueryParser
20
+ from werkzeug.local import LocalProxy
21
+
22
+ from ...services.components import ModelPIDComponent
23
+ from ..funders.facets import FundersLabels
24
+
25
+ award_schemes = LocalProxy(lambda: current_app.config["VOCABULARIES_AWARD_SCHEMES"])
26
+
27
+ awards_openaire_funders_mapping = LocalProxy(
28
+ lambda: current_app.config["VOCABULARIES_AWARDS_OPENAIRE_FUNDERS"]
29
+ )
30
+
31
+ awards_ec_ror_id = LocalProxy(
32
+ lambda: current_app.config["VOCABULARIES_AWARDS_EC_ROR_ID"]
33
+ )
34
+
35
+
36
+ class AwardsSearchOptions(SearchOptions):
37
+ """Search options."""
38
+
39
+ suggest_parser_cls = SuggestQueryParser.factory(
40
+ fields=[
41
+ "acronym^100",
42
+ "number^10",
43
+ "identifiers.identifier^10",
44
+ ],
45
+ )
46
+
47
+ facets = {
48
+ "funders": TermsFacet(
49
+ field="funder.id", label=_("Funders"), value_labels=FundersLabels("funders")
50
+ )
51
+ }
52
+
53
+
54
+ service_components = [
55
+ # Order of components are important!
56
+ DataComponent,
57
+ ModelPIDComponent,
58
+ RelationsComponent,
59
+ ]
@@ -0,0 +1,372 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2022-2024 CERN.
4
+ #
5
+ # Invenio-Vocabularies is free software; you can redistribute it and/or
6
+ # modify it under the terms of the MIT License; see LICENSE file for more
7
+ # details.
8
+
9
+ """Awards datastreams, transformers, writers and readers."""
10
+
11
+ import io
12
+
13
+ import requests
14
+ from flask import current_app
15
+ from invenio_access.permissions import system_identity
16
+ from invenio_i18n import lazy_gettext as _
17
+
18
+ from invenio_vocabularies.datastreams.errors import ReaderError
19
+
20
+ from ...datastreams.errors import TransformerError
21
+ from ...datastreams.readers import BaseReader
22
+ from ...datastreams.transformers import BaseTransformer
23
+ from ...datastreams.writers import ServiceWriter
24
+ from .config import awards_ec_ror_id, awards_openaire_funders_mapping
25
+
26
+
27
+ class AwardsServiceWriter(ServiceWriter):
28
+ """Funders service writer."""
29
+
30
+ def __init__(self, *args, **kwargs):
31
+ """Constructor."""
32
+ service_or_name = kwargs.pop("service_or_name", "awards")
33
+ super().__init__(service_or_name=service_or_name, *args, **kwargs)
34
+
35
+ def _entry_id(self, entry):
36
+ """Get the id from an entry."""
37
+ return entry["id"]
38
+
39
+
40
+ class OpenAIREProjectTransformer(BaseTransformer):
41
+ """Transforms an OpenAIRE project record into an award record."""
42
+
43
+ def apply(self, stream_entry, **kwargs):
44
+ """Applies the transformation to the stream entry."""
45
+ record = stream_entry.entry
46
+ award = {}
47
+
48
+ code = record["code"]
49
+
50
+ # The `id` should follow the format `sourcePrefix::md5(localId)` where `sourcePrefix` is 12 characters long.
51
+ # See: https://graph.openaire.eu/docs/data-model/pids-and-identifiers#identifiers-in-the-graph
52
+ #
53
+ # The format of `id` in the full OpenAIRE Graph Dataset (https://doi.org/10.5281/zenodo.3516917)
54
+ # follows this format (e.g. 'abc_________::0123456789abcdef0123456789abcdef').
55
+ # However, the format of `id` in the new collected projects dataset (https://doi.org/10.5281/zenodo.6419021)
56
+ # does not follow this format, and has a `40|` prefix (e.g. '40|abc_________::0123456789abcdef0123456789abcdef').
57
+ #
58
+ # The number '40' corresponds to the entity types 'Project'.
59
+ # See: https://ec.europa.eu/research/participants/documents/downloadPublic?documentIds=080166e5a3a1a213&appId=PPGMS
60
+ # See: https://graph.openaire.eu/docs/5.0.0/data-model/entities/project#id
61
+ openaire_funder_prefix = record["id"].split("::", 1)[0].split("|", 1)[-1]
62
+
63
+ funder_id = awards_openaire_funders_mapping.get(openaire_funder_prefix)
64
+ if funder_id is None:
65
+ raise TransformerError(
66
+ _(
67
+ "Unknown OpenAIRE funder prefix {openaire_funder_prefix}".format(
68
+ openaire_funder_prefix=openaire_funder_prefix
69
+ )
70
+ )
71
+ )
72
+
73
+ award["id"] = f"{funder_id}::{code}"
74
+
75
+ funding = next(iter(record.get("funding", [])), None)
76
+ if funding:
77
+ funding_stream_id = funding.get("fundingStream", {}).get("id", "")
78
+ # Example funding stream ID: `EC::HE::HORIZON-AG-UN`. We need the `HE`
79
+ # string, i.e. the second "part" of the identifier.
80
+ program = next(iter(funding_stream_id.split("::")[1:2]), "")
81
+ if program:
82
+ award["program"] = program
83
+
84
+ identifiers = []
85
+ if funder_id == awards_ec_ror_id:
86
+ identifiers.append(
87
+ {
88
+ "identifier": f"https://cordis.europa.eu/projects/{code}",
89
+ "scheme": "url",
90
+ }
91
+ )
92
+ elif record.get("websiteurl"):
93
+ identifiers.append(
94
+ {"identifier": record.get("websiteurl"), "scheme": "url"}
95
+ )
96
+
97
+ if identifiers:
98
+ award["identifiers"] = identifiers
99
+
100
+ award["number"] = code
101
+
102
+ # `title` is a mandatory attribute of the `Project` object in the OpenAIRE Graph Data Model.
103
+ # See: https://graph.openaire.eu/docs/data-model/entities/project#title
104
+ # However, 15'000+ awards for the FCT funder (and 1 record the NIH funder) are missing a title attribute.
105
+ if "title" not in record:
106
+ raise TransformerError(
107
+ _(
108
+ "Missing title attribute for award {award_id}".format(
109
+ award_id=award["id"]
110
+ )
111
+ )
112
+ )
113
+ award["title"] = {"en": record["title"]}
114
+
115
+ award["funder"] = {"id": funder_id}
116
+ acronym = record.get("acronym")
117
+ if acronym:
118
+ award["acronym"] = acronym
119
+
120
+ if "startDate" in record:
121
+ award["start_date"] = record["startDate"]
122
+ if "endDate" in record:
123
+ award["end_date"] = record["endDate"]
124
+ if "summary" in record:
125
+ award["description"] = {"en": record["summary"]}
126
+
127
+ stream_entry.entry = award
128
+ return stream_entry
129
+
130
+
131
+ class CORDISProjectHTTPReader(BaseReader):
132
+ """CORDIS Project HTTP Reader returning an in-memory binary stream of the latest CORDIS Horizon Europe project zip file."""
133
+
134
+ def _iter(self, fp, *args, **kwargs):
135
+ raise NotImplementedError(
136
+ "CORDISProjectHTTPReader downloads one file and therefore does not iterate through items"
137
+ )
138
+
139
+ def read(self, item=None, *args, **kwargs):
140
+ """Reads the latest CORDIS Horizon Europe project zip file and yields an in-memory binary stream of it."""
141
+ if item:
142
+ raise NotImplementedError(
143
+ "CORDISProjectHTTPReader does not support being chained after another reader"
144
+ )
145
+
146
+ if self._origin == "HE":
147
+ file_url = "https://cordis.europa.eu/data/cordis-HORIZONprojects-xml.zip"
148
+ elif self._origin == "H2020":
149
+ file_url = "https://cordis.europa.eu/data/cordis-h2020projects-xml.zip"
150
+ elif self._origin == "FP7":
151
+ file_url = "https://cordis.europa.eu/data/cordis-fp7projects-xml.zip"
152
+ else:
153
+ raise ReaderError(
154
+ "The --origin option should be either 'HE' (for Horizon Europe) or 'H2020' (for Horizon 2020) or 'FP7'"
155
+ )
156
+
157
+ # Download the ZIP file and fully load the response bytes content in memory.
158
+ # The bytes content are then wrapped by a BytesIO to be file-like object (as required by `zipfile.ZipFile`).
159
+ # Using directly `file_resp.raw` is not possible since `zipfile.ZipFile` requires the file-like object to be seekable.
160
+ file_resp = requests.get(file_url)
161
+ file_resp.raise_for_status()
162
+ yield io.BytesIO(file_resp.content)
163
+
164
+
165
+ class CORDISProjectTransformer(BaseTransformer):
166
+ """Transforms a CORDIS project record into an award record."""
167
+
168
+ def apply(self, stream_entry, **kwargs):
169
+ """Applies the transformation to the stream entry."""
170
+ record = stream_entry.entry
171
+ award = {}
172
+
173
+ # Here `id` is the project ID, which will be used to attach the update to the existing project.
174
+ award["id"] = (
175
+ f"{current_app.config['VOCABULARIES_AWARDS_EC_ROR_ID']}::{record['id']}"
176
+ )
177
+
178
+ categories = record.get("relations", {}).get("categories", {}).get("category")
179
+ if categories:
180
+ if isinstance(categories, dict):
181
+ categories = [categories]
182
+
183
+ award["subjects"] = [
184
+ {"id": f"euroscivoc:{vocab_id}"}
185
+ for category in categories
186
+ if category.get("@classification") == "euroSciVoc"
187
+ and (vocab_id := category["code"].split("/")[-1]).isdigit()
188
+ ]
189
+
190
+ organizations = (
191
+ record.get("relations", {}).get("associations", {}).get("organization")
192
+ )
193
+ if organizations:
194
+ # Projects with a single organization are not wrapped in a list,
195
+ # so we do this here to be able to iterate over it.
196
+ organizations = (
197
+ organizations if isinstance(organizations, list) else [organizations]
198
+ )
199
+ award["organizations"] = []
200
+ for organization in organizations:
201
+ # Some organizations in FP7 projects do not have a "legalname" key,
202
+ # for instance the 14th participant in "SAGE" https://cordis.europa.eu/project/id/999902.
203
+ # In this case, fully skip the organization entry.
204
+ if "legalname" not in organization:
205
+ continue
206
+
207
+ organization_data = {
208
+ "organization": organization["legalname"],
209
+ }
210
+
211
+ # Some organizations in FP7 projects do not have an "id" key (the PIC identifier),
212
+ # for instance "AIlGreenVehicles" in "MOTORBRAIN" https://cordis.europa.eu/project/id/270693.
213
+ # In this case, still store the name but skip the identifier part.
214
+ if "id" in organization:
215
+ organization_data.update(
216
+ {
217
+ "scheme": "pic",
218
+ "id": organization["id"],
219
+ }
220
+ )
221
+
222
+ award["organizations"].append(organization_data)
223
+
224
+ programmes = (
225
+ record.get("relations", {}).get("associations", {}).get("programme", {})
226
+ )
227
+ if programmes:
228
+ # Projects with a single programme (this is the case of some projects in FP7) are not wrapped in a list,
229
+ # so we do this here to be able to iterate over it.
230
+ programmes = programmes if isinstance(programmes, list) else [programmes]
231
+
232
+ programmes_related_legal_basis = [
233
+ {
234
+ "code": programme["code"],
235
+ "uniqueprogrammepart": programme.get("@uniqueprogrammepart"),
236
+ }
237
+ for programme in programmes
238
+ if programme.get("@type") == "relatedLegalBasis"
239
+ ]
240
+
241
+ if len(programmes_related_legal_basis) == 0:
242
+ raise TransformerError(
243
+ _(
244
+ "No related legal basis programme found for project {project_id}".format(
245
+ project_id=record["id"]
246
+ )
247
+ )
248
+ )
249
+ elif len(programmes_related_legal_basis) == 1:
250
+ # FP7 projects have only one related legal basis programme and do not have a 'uniqueprogrammepart' field.
251
+ unique_programme_related_legal_basis = programmes_related_legal_basis[0]
252
+ elif len(programmes_related_legal_basis) >= 1:
253
+ # The entry with the field 'uniqueprogrammepart' == 'true' is the high level programme code,
254
+ # while the other entry is a more specific sub-programme.
255
+ unique_programme_related_legal_basis = [
256
+ programme_related_legal_basis
257
+ # A few H2020 projects have more than one 'uniqueprogrammepart' == 'true',
258
+ # for instance https://cordis.europa.eu/project/id/825673 (showing as "main programme" in the page)
259
+ # which has one entry with the code 'H2020-EU.1.2.',
260
+ # and one with the code 'H2020-EU.1.2.3.'.
261
+ # We sort them from the shortest code to the longest code, and take the first item,
262
+ # so that it conforms more with other projects which all have the shortest code as the main one.
263
+ for programme_related_legal_basis in sorted(
264
+ programmes_related_legal_basis, key=lambda d: len(d["code"])
265
+ )
266
+ if programme_related_legal_basis["uniqueprogrammepart"] == "true"
267
+ ][0]
268
+
269
+ # Store the code of the programme.
270
+ # For instance the code "HORIZON.1.2" which means "Marie Skłodowska-Curie Actions (MSCA)"
271
+ # See https://cordis.europa.eu/programme/id/HORIZON.1.2
272
+ award["program"] = unique_programme_related_legal_basis["code"]
273
+
274
+ stream_entry.entry = award
275
+ return stream_entry
276
+
277
+
278
+ class CORDISAwardsServiceWriter(ServiceWriter):
279
+ """CORDIS Awards service writer."""
280
+
281
+ def __init__(self, *args, **kwargs):
282
+ """Constructor."""
283
+ service_or_name = kwargs.pop("service_or_name", "awards")
284
+ # Here we only update and we do not insert, since CORDIS data is used to augment existing awards
285
+ # (with subjects, organizations, and program information) and is not used to create new awards.
286
+ super().__init__(
287
+ service_or_name=service_or_name, insert=False, update=True, *args, **kwargs
288
+ )
289
+
290
+ def _entry_id(self, entry):
291
+ """Get the id from an entry."""
292
+ return entry["id"]
293
+
294
+
295
+ VOCABULARIES_DATASTREAM_READERS = {
296
+ "cordis-project-http": CORDISProjectHTTPReader,
297
+ }
298
+
299
+ VOCABULARIES_DATASTREAM_TRANSFORMERS = {
300
+ "openaire-award": OpenAIREProjectTransformer,
301
+ "cordis-award": CORDISProjectTransformer,
302
+ }
303
+ """ORCiD Data Streams transformers."""
304
+
305
+ VOCABULARIES_DATASTREAM_WRITERS = {
306
+ "awards-service": AwardsServiceWriter,
307
+ "cordis-awards-service": CORDISAwardsServiceWriter,
308
+ }
309
+ """ORCiD Data Streams transformers."""
310
+
311
+ DATASTREAM_CONFIG_CORDIS = {
312
+ "readers": [
313
+ {"type": "cordis-project-http"},
314
+ {
315
+ "type": "zip",
316
+ "args": {
317
+ "regex": "\\.xml$",
318
+ "mode": "r",
319
+ },
320
+ },
321
+ {
322
+ "type": "xml",
323
+ "args": {
324
+ "root_element": "project",
325
+ },
326
+ },
327
+ ],
328
+ "transformers": [
329
+ {"type": "cordis-award"},
330
+ ],
331
+ "writers": [
332
+ {
333
+ "type": "cordis-awards-service",
334
+ "args": {
335
+ "identity": system_identity,
336
+ },
337
+ }
338
+ ],
339
+ }
340
+ """Data Stream configuration.
341
+
342
+ An origin is required for the reader.
343
+ """
344
+
345
+ DATASTREAM_CONFIG = {
346
+ "readers": [
347
+ {
348
+ "type": "tar",
349
+ "args": {
350
+ "regex": "\\.json.gz$",
351
+ "mode": "r",
352
+ },
353
+ },
354
+ {"type": "gzip"},
355
+ {"type": "jsonl"},
356
+ ],
357
+ "transformers": [
358
+ {"type": "openaire-award"},
359
+ ],
360
+ "writers": [
361
+ {
362
+ "type": "awards-service",
363
+ "args": {
364
+ "identity": system_identity,
365
+ },
366
+ }
367
+ ],
368
+ }
369
+ """Data Stream configuration.
370
+
371
+ An origin is required for the reader.
372
+ """
@@ -0,0 +1,9 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2022 CERN.
4
+ #
5
+ # Invenio-Vocabularies is free software; you can redistribute it and/or
6
+ # modify it under the terms of the MIT License; see LICENSE file for more
7
+ # details.
8
+
9
+ """Awards JSONSchemas module."""
@@ -0,0 +1,91 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "local://awards/award-v1.0.0.json",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "properties": {
7
+ "$schema": {
8
+ "$ref": "local://definitions-v1.0.0.json#/$schema"
9
+ },
10
+ "tags": {
11
+ "$ref": "local://vocabularies/definitions-v1.0.0.json#/tags"
12
+ },
13
+ "identifiers": {
14
+ "description": "Alternate identifiers for the award.",
15
+ "type": "array",
16
+ "items": {
17
+ "$ref": "local://definitions-v1.0.0.json#/identifiers_with_scheme"
18
+ },
19
+ "uniqueItems": true
20
+ },
21
+ "number": {
22
+ "type": "string"
23
+ },
24
+ "title": {
25
+ "$ref": "local://vocabularies/definitions-v1.0.0.json#/title"
26
+ },
27
+ "funder": {
28
+ "description": "Award's funder.",
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "properties": {
32
+ "id": {
33
+ "$ref": "local://definitions-v1.0.0.json#/identifier"
34
+ },
35
+ "name": {
36
+ "type": "string"
37
+ }
38
+ }
39
+ },
40
+ "acronym": {
41
+ "type": "string"
42
+ },
43
+ "program": {
44
+ "type": "string"
45
+ },
46
+ "start_date": {
47
+ "type": "string"
48
+ },
49
+ "end_date": {
50
+ "type": "string"
51
+ },
52
+ "description": {
53
+ "$ref": "local://vocabularies/definitions-v1.0.0.json#/description"
54
+ },
55
+ "subjects": {
56
+ "description": "Award's subjects.",
57
+ "type": "array",
58
+ "properties": {
59
+ "id": {
60
+ "$ref": "local://definitions-v1.0.0.json#/identifier"
61
+ },
62
+ "subject": {
63
+ "description": "Human readable label.",
64
+ "type": "string"
65
+ }
66
+ }
67
+ },
68
+ "organizations": {
69
+ "description": "Award's organizations.",
70
+ "type": "array",
71
+ "items": {
72
+ "type": "object",
73
+ "additionalProperties": false,
74
+ "properties": {
75
+ "scheme": {
76
+ "description": "Identifier of the organization scheme.",
77
+ "$ref": "local://definitions-v1.0.0.json#/identifier"
78
+ },
79
+ "id": {
80
+ "description": "Identifier of the organization for the given scheme.",
81
+ "$ref": "local://definitions-v1.0.0.json#/identifier"
82
+ },
83
+ "organization": {
84
+ "description": "Human readable label.",
85
+ "type": "string"
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
@@ -0,0 +1,9 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2022 CERN.
4
+ #
5
+ # Invenio-Vocabularies is free software; you can redistribute it and/or
6
+ # modify it under the terms of the MIT License; see LICENSE file for more
7
+ # details.
8
+
9
+ """Awards search mappings."""
@@ -0,0 +1,9 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2022 CERN.
4
+ #
5
+ # Invenio-Vocabularies is free software; you can redistribute it and/or
6
+ # modify it under the terms of the MIT License; see LICENSE file for more
7
+ # details.
8
+
9
+ """Awards OpenSearch v1 mappings."""