invenio-vocabularies 3.4.2__py2.py3-none-any.whl → 4.1.1__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.

Potentially problematic release.


This version of invenio-vocabularies might be problematic. Click here for more details.

Files changed (69) hide show
  1. invenio_vocabularies/__init__.py +1 -1
  2. invenio_vocabularies/administration/__init__.py +10 -0
  3. invenio_vocabularies/administration/views/__init__.py +10 -0
  4. invenio_vocabularies/administration/views/vocabularies.py +44 -0
  5. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/CustomAwardForm.js +8 -20
  6. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingField.js +2 -2
  7. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/FundingModal.js +5 -7
  8. invenio_vocabularies/assets/semantic-ui/js/invenio_vocabularies/src/contrib/forms/Funding/NoAwardResults.js +3 -3
  9. invenio_vocabularies/cli.py +10 -39
  10. invenio_vocabularies/config.py +33 -3
  11. invenio_vocabularies/contrib/affiliations/config.py +2 -2
  12. invenio_vocabularies/contrib/affiliations/datastreams.py +67 -0
  13. invenio_vocabularies/contrib/affiliations/jsonschemas/affiliations/affiliation-v1.0.0.json +38 -1
  14. invenio_vocabularies/contrib/affiliations/mappings/os-v1/affiliations/affiliation-v1.0.0.json +21 -0
  15. invenio_vocabularies/contrib/affiliations/mappings/os-v2/affiliations/affiliation-v1.0.0.json +21 -0
  16. invenio_vocabularies/contrib/affiliations/mappings/v7/affiliations/affiliation-v1.0.0.json +21 -0
  17. invenio_vocabularies/contrib/affiliations/schema.py +17 -3
  18. invenio_vocabularies/contrib/awards/datastreams.py +90 -3
  19. invenio_vocabularies/contrib/awards/jsonschemas/awards/award-v1.0.0.json +3 -0
  20. invenio_vocabularies/contrib/awards/mappings/os-v1/awards/award-v1.0.0.json +3 -0
  21. invenio_vocabularies/contrib/awards/mappings/os-v2/awards/award-v1.0.0.json +3 -0
  22. invenio_vocabularies/contrib/awards/mappings/v7/awards/award-v1.0.0.json +3 -0
  23. invenio_vocabularies/contrib/common/__init__.py +9 -0
  24. invenio_vocabularies/contrib/common/ror/__init__.py +9 -0
  25. invenio_vocabularies/contrib/common/ror/datastreams.py +166 -0
  26. invenio_vocabularies/contrib/funders/config.py +2 -0
  27. invenio_vocabularies/contrib/funders/datastreams.py +10 -59
  28. invenio_vocabularies/contrib/funders/jsonschemas/funders/funder-v1.0.0.json +36 -1
  29. invenio_vocabularies/contrib/funders/mappings/os-v1/funders/funder-v1.0.0.json +21 -0
  30. invenio_vocabularies/contrib/funders/mappings/os-v2/funders/funder-v1.0.0.json +21 -0
  31. invenio_vocabularies/contrib/funders/mappings/v7/funders/funder-v1.0.0.json +21 -0
  32. invenio_vocabularies/contrib/funders/schema.py +8 -0
  33. invenio_vocabularies/contrib/funders/serializer.py +2 -1
  34. invenio_vocabularies/contrib/names/jsonschemas/names/name-v1.0.0.json +3 -0
  35. invenio_vocabularies/contrib/names/mappings/os-v1/names/name-v1.0.0.json +3 -0
  36. invenio_vocabularies/contrib/names/mappings/os-v2/names/name-v1.0.0.json +3 -0
  37. invenio_vocabularies/contrib/names/mappings/v7/names/name-v1.0.0.json +3 -0
  38. invenio_vocabularies/contrib/subjects/jsonschemas/subjects/subject-v1.0.0.json +3 -0
  39. invenio_vocabularies/contrib/subjects/mappings/os-v1/subjects/subject-v1.0.0.json +3 -0
  40. invenio_vocabularies/contrib/subjects/mappings/os-v2/subjects/subject-v1.0.0.json +3 -0
  41. invenio_vocabularies/contrib/subjects/mappings/v7/subjects/subject-v1.0.0.json +3 -0
  42. invenio_vocabularies/datastreams/factories.py +1 -2
  43. invenio_vocabularies/datastreams/readers.py +96 -3
  44. invenio_vocabularies/datastreams/writers.py +2 -2
  45. invenio_vocabularies/ext.py +22 -7
  46. invenio_vocabularies/factories.py +93 -0
  47. invenio_vocabularies/proxies.py +2 -2
  48. invenio_vocabularies/records/jsonschemas/vocabularies/definitions-v1.0.0.json +7 -0
  49. invenio_vocabularies/records/jsonschemas/vocabularies/vocabulary-v1.0.0.json +1 -4
  50. invenio_vocabularies/resources/__init__.py +8 -1
  51. invenio_vocabularies/resources/config.py +105 -0
  52. invenio_vocabularies/resources/resource.py +31 -41
  53. invenio_vocabularies/services/__init__.py +5 -2
  54. invenio_vocabularies/services/config.py +179 -0
  55. invenio_vocabularies/services/permissions.py +3 -1
  56. invenio_vocabularies/services/results.py +110 -0
  57. invenio_vocabularies/services/schema.py +1 -1
  58. invenio_vocabularies/services/service.py +41 -86
  59. invenio_vocabularies/services/tasks.py +31 -1
  60. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabularies-list.html +12 -0
  61. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabulary-details.html +71 -0
  62. invenio_vocabularies/views.py +7 -0
  63. {invenio_vocabularies-3.4.2.dist-info → invenio_vocabularies-4.1.1.dist-info}/METADATA +32 -7
  64. {invenio_vocabularies-3.4.2.dist-info → invenio_vocabularies-4.1.1.dist-info}/RECORD +69 -56
  65. {invenio_vocabularies-3.4.2.dist-info → invenio_vocabularies-4.1.1.dist-info}/entry_points.txt +7 -0
  66. {invenio_vocabularies-3.4.2.dist-info → invenio_vocabularies-4.1.1.dist-info}/AUTHORS.rst +0 -0
  67. {invenio_vocabularies-3.4.2.dist-info → invenio_vocabularies-4.1.1.dist-info}/LICENSE +0 -0
  68. {invenio_vocabularies-3.4.2.dist-info → invenio_vocabularies-4.1.1.dist-info}/WHEEL +0 -0
  69. {invenio_vocabularies-3.4.2.dist-info → invenio_vocabularies-4.1.1.dist-info}/top_level.txt +0 -0
@@ -8,6 +8,9 @@
8
8
  "$schema": {
9
9
  "$ref": "local://definitions-v1.0.0.json#/$schema"
10
10
  },
11
+ "tags": {
12
+ "$ref": "local://vocabularies/definitions-v1.0.0.json#/tags"
13
+ },
11
14
  "scheme": {
12
15
  "description": "Identifier of the name scheme.",
13
16
  "$ref": "local://definitions-v1.0.0.json#/identifier"
@@ -24,6 +24,9 @@
24
24
  "id": {
25
25
  "type": "keyword"
26
26
  },
27
+ "tags": {
28
+ "type": "keyword"
29
+ },
27
30
  "name_sort": {
28
31
  "type": "keyword"
29
32
  },
@@ -24,6 +24,9 @@
24
24
  "id": {
25
25
  "type": "keyword"
26
26
  },
27
+ "tags": {
28
+ "type": "keyword"
29
+ },
27
30
  "name_sort": {
28
31
  "type": "keyword"
29
32
  },
@@ -24,6 +24,9 @@
24
24
  "id": {
25
25
  "type": "keyword"
26
26
  },
27
+ "tags": {
28
+ "type": "keyword"
29
+ },
27
30
  "name_sort": {
28
31
  "type": "keyword"
29
32
  },
@@ -8,6 +8,9 @@
8
8
  "$schema": {
9
9
  "$ref": "local://definitions-v1.0.0.json#/$schema"
10
10
  },
11
+ "tags": {
12
+ "$ref": "local://vocabularies/definitions-v1.0.0.json#/tags"
13
+ },
11
14
  "id": {
12
15
  "description": "URI or classification code as identifier - globally unique among all subject schemes.",
13
16
  "$ref": "local://definitions-v1.0.0.json#/identifier"
@@ -55,6 +55,9 @@
55
55
  "type": "keyword"
56
56
  }
57
57
  }
58
+ },
59
+ "tags": {
60
+ "type": "keyword"
58
61
  }
59
62
  }
60
63
  }
@@ -55,6 +55,9 @@
55
55
  "type": "keyword"
56
56
  }
57
57
  }
58
+ },
59
+ "tags": {
60
+ "type": "keyword"
58
61
  }
59
62
  }
60
63
  }
@@ -55,6 +55,9 @@
55
55
  "type": "keyword"
56
56
  }
57
57
  }
58
+ },
59
+ "tags": {
60
+ "type": "keyword"
58
61
  }
59
62
  }
60
63
  }
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2021-2022 CERN.
3
+ # Copyright (C) 2021-2024 CERN.
4
4
  #
5
5
  # Invenio-Vocabularies is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the MIT License; see LICENSE file for more
@@ -36,7 +36,6 @@ class Factory:
36
36
  try:
37
37
  type_ = config["type"]
38
38
  args = config.get("args", {})
39
-
40
39
  return cls.options()[type_](**args)
41
40
  except KeyError:
42
41
  raise FactoryError(name=cls.FACTORY_NAME, key=type_)
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2021-2024 CERN.
4
+ # Copyright (C) 2024 University of Münster.
4
5
  #
5
6
  # Invenio-Vocabularies is free software; you can redistribute it and/or
6
7
  # modify it under the terms of the MIT License; see LICENSE file for more
@@ -15,16 +16,21 @@ import re
15
16
  import tarfile
16
17
  import zipfile
17
18
  from abc import ABC, abstractmethod
18
- from collections import defaultdict
19
19
  from json.decoder import JSONDecodeError
20
20
 
21
21
  import requests
22
22
  import yaml
23
+ from lxml import etree
23
24
  from lxml.html import parse as html_parse
24
25
 
25
26
  from .errors import ReaderError
26
27
  from .xml import etree_to_dict
27
28
 
29
+ try:
30
+ import oaipmh_scythe
31
+ except ImportError:
32
+ oaipmh_scythe = None
33
+
28
34
 
29
35
  class BaseReader(ABC):
30
36
  """Base reader."""
@@ -80,7 +86,12 @@ class TarReader(BaseReader):
80
86
  def read(self, item=None, *args, **kwargs):
81
87
  """Opens a tar archive or uses the given file pointer."""
82
88
  if item:
83
- yield from self._iter(fp=item, *args, **kwargs)
89
+ if isinstance(item, tarfile.TarFile):
90
+ yield from self._iter(fp=item, *args, **kwargs)
91
+ else:
92
+ # If the item is not already a TarFile (e.g. if it is a BytesIO), try to create a TarFile from the item.
93
+ with tarfile.open(mode=self._mode, fileobj=item) as archive:
94
+ yield from self._iter(fp=archive, *args, **kwargs)
84
95
  else:
85
96
  with tarfile.open(self._origin, self._mode) as archive:
86
97
  yield from self._iter(fp=archive, *args, **kwargs)
@@ -136,7 +147,12 @@ class ZipReader(BaseReader):
136
147
  """Opens a Zip archive or uses the given file pointer."""
137
148
  # https://docs.python.org/3/library/zipfile.html
138
149
  if item:
139
- yield from self._iter(fp=item, *args, **kwargs)
150
+ if isinstance(item, zipfile.ZipFile):
151
+ yield from self._iter(fp=item, *args, **kwargs)
152
+ else:
153
+ # If the item is not already a ZipFile (e.g. if it is a BytesIO), try to create a ZipFile from the item.
154
+ with zipfile.ZipFile(item, **self._options) as archive:
155
+ yield from self._iter(fp=archive, *args, **kwargs)
140
156
  else:
141
157
  with zipfile.ZipFile(self._origin, **self._options) as archive:
142
158
  yield from self._iter(fp=archive, *args, **kwargs)
@@ -217,3 +233,80 @@ class XMLReader(BaseReader):
217
233
  raise ReaderError(f"Record not found in XML entry.")
218
234
 
219
235
  yield record
236
+
237
+
238
+ class OAIPMHReader(BaseReader):
239
+ """OAIPMH reader."""
240
+
241
+ def __init__(
242
+ self,
243
+ *args,
244
+ base_url=None,
245
+ metadata_prefix=None,
246
+ set=None,
247
+ from_date=None,
248
+ until_date=None,
249
+ verb=None,
250
+ **kwargs,
251
+ ):
252
+ """Constructor."""
253
+ self._base_url = base_url
254
+ self._metadata_prefix = metadata_prefix if not None else "oai_dc"
255
+ self._set = set
256
+ self._until = until_date
257
+ self._from = from_date
258
+ self._verb = verb if not None else "ListRecords"
259
+ super().__init__(*args, **kwargs)
260
+
261
+ def _iter(self, scythe, *args, **kwargs):
262
+ """Read and parse an OAIPMH stream to dict."""
263
+
264
+ class OAIRecord(oaipmh_scythe.models.Record):
265
+ """An XML unpacking implementation for more complicated formats."""
266
+
267
+ def get_metadata(self):
268
+ """Extract and return the record's metadata as a dictionary."""
269
+ return xml_to_dict(
270
+ self.xml.find(f".//{self._oai_namespace}metadata").getchildren()[0],
271
+ )
272
+
273
+ scythe.class_mapping["ListRecords"] = OAIRecord
274
+ try:
275
+ records = scythe.list_records(
276
+ from_=self._from,
277
+ until=self._until,
278
+ metadata_prefix=self._metadata_prefix,
279
+ set_=self._set,
280
+ ignore_deleted=True,
281
+ )
282
+ for record in records:
283
+ yield {"record": record}
284
+ except oaipmh_scythe.NoRecordsMatch:
285
+ raise ReaderError(f"No records found in OAI-PMH request.")
286
+
287
+ def read(self, item=None, *args, **kwargs):
288
+ """Reads from item or opens the file descriptor from origin."""
289
+ if item:
290
+ raise NotImplementedError(
291
+ "OAIPMHReader does not support being chained after another reader"
292
+ )
293
+ else:
294
+ with oaipmh_scythe.Scythe(self._base_url) as scythe:
295
+ yield from self._iter(scythe=scythe, *args, **kwargs)
296
+
297
+
298
+ def xml_to_dict(tree: etree._Element):
299
+ """Convert an XML tree to a dictionary.
300
+
301
+ This function takes an XML element tree and converts it into a dictionary.
302
+
303
+ Args:
304
+ tree: The root element of the XML tree to be converted.
305
+
306
+ Returns:
307
+ A dictionary with the key "record".
308
+ """
309
+ dict_obj = dict()
310
+ dict_obj["record"] = etree.tostring(tree)
311
+
312
+ return dict_obj
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2021-2022 CERN.
3
+ # Copyright (C) 2021-2024 CERN.
4
4
  #
5
5
  # Invenio-Vocabularies is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the MIT License; see LICENSE file for more
@@ -103,6 +103,6 @@ class YamlWriter(BaseWriter):
103
103
  with open(self._filepath, "a") as file:
104
104
  # made into array for safer append
105
105
  # will always read array (good for reader)
106
- yaml.safe_dump([stream_entry.entry], file)
106
+ yaml.safe_dump([stream_entry.entry], file, allow_unicode=True)
107
107
 
108
108
  return stream_entry
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2020-2022 CERN.
3
+ # Copyright (C) 2020-2024 CERN.
4
4
  # Copyright (C) 2023 Graz University of Technology.
5
5
  #
6
6
  # Invenio-Vocabularies is free software; you can redistribute it and/or
@@ -40,8 +40,14 @@ from .contrib.subjects import (
40
40
  SubjectsService,
41
41
  SubjectsServiceConfig,
42
42
  )
43
- from .resources.resource import VocabulariesResource
44
- from .services.service import VocabulariesService
43
+ from .resources import (
44
+ VocabulariesAdminResource,
45
+ VocabulariesResource,
46
+ VocabulariesResourceConfig,
47
+ VocabularyTypeResourceConfig,
48
+ )
49
+ from .services.config import VocabularyTypesServiceConfig
50
+ from .services.service import VocabulariesService, VocabularyTypeService
45
51
 
46
52
 
47
53
  class InvenioVocabularies(object):
@@ -76,6 +82,7 @@ class InvenioVocabularies(object):
76
82
  funders = FundersServiceConfig
77
83
  names = NamesServiceConfig
78
84
  subjects = SubjectsServiceConfig
85
+ vocabulary_types = VocabularyTypesServiceConfig
79
86
 
80
87
  return ServiceConfigs
81
88
 
@@ -93,9 +100,12 @@ class InvenioVocabularies(object):
93
100
  self.funders_service = FundersService(config=service_configs.funders)
94
101
  self.names_service = NamesService(config=service_configs.names)
95
102
  self.subjects_service = SubjectsService(config=service_configs.subjects)
96
- self.service = VocabulariesService(
103
+ self.vocabularies_service = VocabulariesService(
97
104
  config=app.config["VOCABULARIES_SERVICE_CONFIG"],
98
105
  )
106
+ self.vocabulary_types_service = VocabularyTypeService(
107
+ config=service_configs.vocabulary_types
108
+ )
99
109
 
100
110
  def init_resource(self, app):
101
111
  """Initialize vocabulary resources."""
@@ -121,9 +131,13 @@ class InvenioVocabularies(object):
121
131
  config=SubjectsResourceConfig,
122
132
  )
123
133
  self.resource = VocabulariesResource(
124
- service=self.service,
134
+ service=self.vocabularies_service,
125
135
  config=app.config["VOCABULARIES_RESOURCE_CONFIG"],
126
136
  )
137
+ self.vocabulary_admin_resource = VocabulariesAdminResource(
138
+ service=self.vocabulary_types_service,
139
+ config=VocabularyTypeResourceConfig,
140
+ )
127
141
 
128
142
 
129
143
  def finalize_app(app):
@@ -153,7 +167,8 @@ def init(app):
153
167
  sregistry.register(ext.funders_service, service_id="funders")
154
168
  sregistry.register(ext.names_service, service_id="names")
155
169
  sregistry.register(ext.subjects_service, service_id="subjects")
156
- sregistry.register(ext.service, service_id="vocabularies")
170
+ sregistry.register(ext.vocabularies_service, service_id="vocabularies")
171
+ sregistry.register(ext.vocabulary_types_service, service_id="vocabulary-types")
157
172
  # Register indexers
158
173
  iregistry = app.extensions["invenio-indexer"].registry
159
174
  iregistry.register(ext.affiliations_service.indexer, indexer_id="affiliations")
@@ -161,4 +176,4 @@ def init(app):
161
176
  iregistry.register(ext.funders_service.indexer, indexer_id="funders")
162
177
  iregistry.register(ext.names_service.indexer, indexer_id="names")
163
178
  iregistry.register(ext.subjects_service.indexer, indexer_id="subjects")
164
- iregistry.register(ext.service.indexer, indexer_id="vocabularies")
179
+ iregistry.register(ext.vocabularies_service.indexer, indexer_id="vocabularies")
@@ -0,0 +1,93 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2024 CERN.
4
+ # Copyright (C) 2024 KTH Royal Institute of Technology.
5
+ #
6
+ # Invenio-Vocabularies is free software; you can redistribute it and/or
7
+ # modify it under the terms of the MIT License; see LICENSE file for more
8
+ # details.
9
+ """Generate Vocabulary Config."""
10
+ from copy import deepcopy
11
+
12
+ import yaml
13
+ from invenio_records_resources.proxies import current_service_registry
14
+
15
+ from .contrib.affiliations.datastreams import (
16
+ DATASTREAM_CONFIG as affiliations_ds_config,
17
+ )
18
+ from .contrib.awards.datastreams import DATASTREAM_CONFIG as awards_ds_config
19
+ from .contrib.funders.datastreams import DATASTREAM_CONFIG as funders_ds_config
20
+ from .contrib.names.datastreams import DATASTREAM_CONFIG as names_ds_config
21
+
22
+
23
+ class VocabularyConfig:
24
+ """Vocabulary Config Factory."""
25
+
26
+ config = None
27
+ vocabulary_name = None
28
+
29
+ def get_config(self, filepath=None, origin=None):
30
+ """Get the configuration for the vocabulary."""
31
+ config = deepcopy(self.config)
32
+ if filepath:
33
+ with open(filepath, encoding="utf-8") as f:
34
+ config = yaml.safe_load(f).get(self.vocabulary_name)
35
+ if origin:
36
+ config["readers"][0].setdefault("args", {})
37
+ config["readers"][0]["args"]["origin"] = origin
38
+ return config
39
+
40
+ def get_service(self):
41
+ """Get the service for the vocabulary."""
42
+ return current_service_registry.get(self.vocabulary_name)
43
+
44
+
45
+ class NamesVocabularyConfig(VocabularyConfig):
46
+ """Names Vocabulary Config."""
47
+
48
+ config = names_ds_config
49
+ vocabulary_name = "names"
50
+
51
+
52
+ class FundersVocabularyConfig(VocabularyConfig):
53
+ """Funders Vocabulary Config."""
54
+
55
+ config = funders_ds_config
56
+ vocabulary_name = "funders"
57
+
58
+ def get_service(self):
59
+ """Get the service for the vocabulary."""
60
+ raise NotImplementedError("Service not implemented for Funders")
61
+
62
+
63
+ class AwardsVocabularyConfig(VocabularyConfig):
64
+ """Awards Vocabulary Config."""
65
+
66
+ config = awards_ds_config
67
+ vocabulary_name = "awards"
68
+
69
+ def get_service(self):
70
+ """Get the service for the vocabulary."""
71
+ raise NotImplementedError("Service not implemented for Awards")
72
+
73
+
74
+ class AffiliationsVocabularyConfig(VocabularyConfig):
75
+ """Affiliations Vocabulary Config."""
76
+
77
+ config = affiliations_ds_config
78
+ vocabulary_name = "affiliations"
79
+
80
+ def get_service(self):
81
+ """Get the service for the vocabulary."""
82
+ raise NotImplementedError("Service not implemented for Affiliations")
83
+
84
+
85
+ def get_vocabulary_config(vocabulary):
86
+ """Factory function to get the appropriate Vocabulary Config."""
87
+ vocab_config = {
88
+ "names": NamesVocabularyConfig,
89
+ "funders": FundersVocabularyConfig,
90
+ "awards": AwardsVocabularyConfig,
91
+ "affiliations": AffiliationsVocabularyConfig,
92
+ }
93
+ return vocab_config.get(vocabulary, VocabularyConfig)()
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2021 CERN.
3
+ # Copyright (C) 2021-2024 CERN.
4
4
  # Copyright (C) 2021 Northwestern University.
5
5
  #
6
6
  # Invenio-Vocabularies is free software; you can redistribute it and/or
@@ -19,7 +19,7 @@ def _ext_proxy(attr):
19
19
  )
20
20
 
21
21
 
22
- current_service = _ext_proxy("service")
22
+ current_service = _ext_proxy("vocabularies_service")
23
23
  """Proxy to the instantiated vocabulary service."""
24
24
 
25
25
 
@@ -10,5 +10,12 @@
10
10
  },
11
11
  "icon": {
12
12
  "type": "string"
13
+ },
14
+ "tags": {
15
+ "type": "array",
16
+ "description": "Tags for a vocabulary item.",
17
+ "items": {
18
+ "type": "string"
19
+ }
13
20
  }
14
21
  }
@@ -34,10 +34,7 @@
34
34
  }
35
35
  },
36
36
  "tags": {
37
- "type": "array",
38
- "items": {
39
- "type": "string"
40
- }
37
+ "$ref": "local://vocabularies/definitions-v1.0.0.json#/tags"
41
38
  },
42
39
  "title": {
43
40
  "$ref": "local://vocabularies/definitions-v1.0.0.json#/title"
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2020-2021 CERN.
3
+ # Copyright (C) 2020-2024 CERN.
4
4
  #
5
5
  # Invenio-Vocabularies is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the MIT License; see LICENSE file for more
@@ -9,7 +9,14 @@
9
9
  """Resources module."""
10
10
  from invenio_vocabularies.resources.schema import L10NString, VocabularyL10Schema
11
11
 
12
+ from .config import VocabulariesResourceConfig, VocabularyTypeResourceConfig
13
+ from .resource import VocabulariesAdminResource, VocabulariesResource
14
+
12
15
  __all__ = (
13
16
  "VocabularyL10Schema",
14
17
  "L10NString",
18
+ "VocabulariesResourceConfig",
19
+ "VocabularyTypeResourceConfig",
20
+ "VocabulariesAdminResource",
21
+ "VocabulariesResource",
15
22
  )
@@ -0,0 +1,105 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2024 CERN.
4
+ # Copyright (C) 2024 University of Münster.
5
+ #
6
+ # Invenio-Vocabularies is free software; you can redistringibute it and/or modify it
7
+ # under the terms of the MIT License; see LICENSE file for more details.
8
+
9
+ """Resources config."""
10
+
11
+ import marshmallow as ma
12
+ from flask_resources import (
13
+ BaseListSchema,
14
+ HTTPJSONException,
15
+ JSONSerializer,
16
+ MarshmallowSerializer,
17
+ ResourceConfig,
18
+ ResponseHandler,
19
+ create_error_handler,
20
+ )
21
+ from invenio_records_resources.resources import (
22
+ RecordResource,
23
+ RecordResourceConfig,
24
+ SearchRequestArgsSchema,
25
+ )
26
+ from invenio_records_resources.resources.errors import ErrorHandlersMixin
27
+ from invenio_records_resources.resources.records.args import SearchRequestArgsSchema
28
+ from invenio_records_resources.resources.records.headers import etag_headers
29
+ from invenio_records_resources.services.base.config import ConfiguratorMixin
30
+
31
+ from .serializer import VocabularyL10NItemSchema
32
+
33
+
34
+ class VocabularySearchRequestArgsSchema(SearchRequestArgsSchema):
35
+ """Vocabularies search request parameters."""
36
+
37
+ tags = ma.fields.Str()
38
+ active = ma.fields.Boolean()
39
+ status = ma.fields.Boolean()
40
+
41
+
42
+ class VocabulariesResourceConfig(RecordResourceConfig):
43
+ """Vocabulary resource configuration."""
44
+
45
+ blueprint_name = "vocabularies"
46
+ url_prefix = "/vocabularies"
47
+ routes = {
48
+ "list": "/<type>",
49
+ "item": "/<type>/<pid_value>",
50
+ "tasks": "/tasks",
51
+ }
52
+
53
+ request_view_args = {
54
+ "pid_value": ma.fields.Str(),
55
+ "type": ma.fields.Str(required=True),
56
+ }
57
+
58
+ request_search_args = VocabularySearchRequestArgsSchema
59
+
60
+ response_handlers = {
61
+ "application/json": ResponseHandler(JSONSerializer(), headers=etag_headers),
62
+ "application/vnd.inveniordm.v1+json": ResponseHandler(
63
+ MarshmallowSerializer(
64
+ format_serializer_cls=JSONSerializer,
65
+ object_schema_cls=VocabularyL10NItemSchema,
66
+ list_schema_cls=BaseListSchema,
67
+ ),
68
+ headers=etag_headers,
69
+ ),
70
+ }
71
+
72
+
73
+ class VocabularyTypeResourceConfig(ResourceConfig, ConfiguratorMixin):
74
+ """Vocabulary list resource config."""
75
+
76
+ # /vocabulary/vocabulary_id
77
+ # Blueprint configuration
78
+ blueprint_name = "vocabulary_types"
79
+ url_prefix = "/vocabularies"
80
+
81
+ routes = {"list": "/"}
82
+
83
+ # Request parsing
84
+ request_read_args = {}
85
+ request_view_args = {
86
+ "pid_value": ma.fields.String,
87
+ "type": ma.fields.String,
88
+ }
89
+ request_search_args = VocabularySearchRequestArgsSchema
90
+
91
+ error_handlers = {
92
+ **ErrorHandlersMixin.error_handlers,
93
+ # TODO: Add custom error handlers here
94
+ }
95
+ response_handlers = {
96
+ "application/json": ResponseHandler(JSONSerializer(), headers=etag_headers),
97
+ "application/vnd.inveniordm.v1+json": ResponseHandler(
98
+ MarshmallowSerializer(
99
+ format_serializer_cls=JSONSerializer,
100
+ object_schema_cls=VocabularyL10NItemSchema,
101
+ list_schema_cls=BaseListSchema,
102
+ ),
103
+ headers=etag_headers,
104
+ ),
105
+ }