invenio-vocabularies 4.0.0__py2.py3-none-any.whl → 4.2.0__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 (76) 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 +45 -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 +5 -3
  10. invenio_vocabularies/config.py +35 -4
  11. invenio_vocabularies/contrib/affiliations/api.py +1 -2
  12. invenio_vocabularies/contrib/affiliations/config.py +2 -2
  13. invenio_vocabularies/contrib/affiliations/datastreams.py +92 -0
  14. invenio_vocabularies/contrib/affiliations/jsonschemas/affiliations/affiliation-v1.0.0.json +38 -1
  15. invenio_vocabularies/contrib/affiliations/mappings/os-v1/affiliations/affiliation-v1.0.0.json +21 -0
  16. invenio_vocabularies/contrib/affiliations/mappings/os-v2/affiliations/affiliation-v1.0.0.json +21 -0
  17. invenio_vocabularies/contrib/affiliations/mappings/v7/affiliations/affiliation-v1.0.0.json +21 -0
  18. invenio_vocabularies/contrib/affiliations/schema.py +17 -3
  19. invenio_vocabularies/contrib/affiliations/services.py +1 -2
  20. invenio_vocabularies/contrib/awards/awards.py +2 -1
  21. invenio_vocabularies/contrib/awards/datastreams.py +1 -0
  22. invenio_vocabularies/contrib/awards/jsonschemas/awards/award-v1.0.0.json +3 -0
  23. invenio_vocabularies/contrib/awards/mappings/os-v1/awards/award-v1.0.0.json +3 -0
  24. invenio_vocabularies/contrib/awards/mappings/os-v2/awards/award-v1.0.0.json +3 -0
  25. invenio_vocabularies/contrib/awards/mappings/v7/awards/award-v1.0.0.json +3 -0
  26. invenio_vocabularies/contrib/awards/services.py +1 -2
  27. invenio_vocabularies/contrib/common/ror/datastreams.py +140 -6
  28. invenio_vocabularies/contrib/funders/datastreams.py +36 -93
  29. invenio_vocabularies/contrib/funders/funders.py +2 -1
  30. invenio_vocabularies/contrib/funders/jsonschemas/funders/funder-v1.0.0.json +3 -0
  31. invenio_vocabularies/contrib/funders/mappings/os-v1/funders/funder-v1.0.0.json +3 -0
  32. invenio_vocabularies/contrib/funders/mappings/os-v2/funders/funder-v1.0.0.json +3 -0
  33. invenio_vocabularies/contrib/funders/mappings/v7/funders/funder-v1.0.0.json +3 -0
  34. invenio_vocabularies/contrib/funders/serializer.py +2 -1
  35. invenio_vocabularies/contrib/names/jsonschemas/names/name-v1.0.0.json +3 -0
  36. invenio_vocabularies/contrib/names/mappings/os-v1/names/name-v1.0.0.json +3 -0
  37. invenio_vocabularies/contrib/names/mappings/os-v2/names/name-v1.0.0.json +3 -0
  38. invenio_vocabularies/contrib/names/mappings/v7/names/name-v1.0.0.json +3 -0
  39. invenio_vocabularies/contrib/subjects/jsonschemas/subjects/subject-v1.0.0.json +3 -0
  40. invenio_vocabularies/contrib/subjects/mappings/os-v1/subjects/subject-v1.0.0.json +3 -0
  41. invenio_vocabularies/contrib/subjects/mappings/os-v2/subjects/subject-v1.0.0.json +3 -0
  42. invenio_vocabularies/contrib/subjects/mappings/v7/subjects/subject-v1.0.0.json +3 -0
  43. invenio_vocabularies/datastreams/factories.py +1 -2
  44. invenio_vocabularies/datastreams/readers.py +103 -0
  45. invenio_vocabularies/datastreams/tasks.py +25 -0
  46. invenio_vocabularies/datastreams/writers.py +21 -2
  47. invenio_vocabularies/ext.py +22 -7
  48. invenio_vocabularies/factories.py +16 -0
  49. invenio_vocabularies/proxies.py +2 -2
  50. invenio_vocabularies/records/jsonschemas/vocabularies/definitions-v1.0.0.json +7 -0
  51. invenio_vocabularies/records/jsonschemas/vocabularies/vocabulary-v1.0.0.json +1 -4
  52. invenio_vocabularies/records/models.py +2 -4
  53. invenio_vocabularies/records/pidprovider.py +1 -2
  54. invenio_vocabularies/resources/__init__.py +9 -1
  55. invenio_vocabularies/resources/config.py +105 -0
  56. invenio_vocabularies/resources/resource.py +31 -41
  57. invenio_vocabularies/resources/schema.py +2 -1
  58. invenio_vocabularies/services/__init__.py +5 -2
  59. invenio_vocabularies/services/config.py +179 -0
  60. invenio_vocabularies/services/custom_fields/subject.py +2 -1
  61. invenio_vocabularies/services/custom_fields/vocabulary.py +1 -1
  62. invenio_vocabularies/services/permissions.py +3 -1
  63. invenio_vocabularies/services/results.py +110 -0
  64. invenio_vocabularies/services/schema.py +11 -2
  65. invenio_vocabularies/services/service.py +41 -86
  66. invenio_vocabularies/services/tasks.py +1 -31
  67. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabularies-list.html +12 -0
  68. invenio_vocabularies/templates/semantic-ui/invenio_vocabularies/vocabulary-details.html +71 -0
  69. invenio_vocabularies/views.py +7 -0
  70. {invenio_vocabularies-4.0.0.dist-info → invenio_vocabularies-4.2.0.dist-info}/METADATA +33 -1
  71. {invenio_vocabularies-4.0.0.dist-info → invenio_vocabularies-4.2.0.dist-info}/RECORD +76 -66
  72. {invenio_vocabularies-4.0.0.dist-info → invenio_vocabularies-4.2.0.dist-info}/entry_points.txt +4 -0
  73. {invenio_vocabularies-4.0.0.dist-info → invenio_vocabularies-4.2.0.dist-info}/AUTHORS.rst +0 -0
  74. {invenio_vocabularies-4.0.0.dist-info → invenio_vocabularies-4.2.0.dist-info}/LICENSE +0 -0
  75. {invenio_vocabularies-4.0.0.dist-info → invenio_vocabularies-4.2.0.dist-info}/WHEEL +0 -0
  76. {invenio_vocabularies-4.0.0.dist-info → invenio_vocabularies-4.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,179 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2024 CERN.
4
+ # Copyright (C) 2024 Uni Münster.
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
+
10
+ """Vocabulary services configs."""
11
+
12
+ import sqlalchemy as sa
13
+ from flask import current_app
14
+ from invenio_i18n import lazy_gettext as _
15
+ from invenio_records_resources.services import (
16
+ Link,
17
+ LinksTemplate,
18
+ RecordService,
19
+ RecordServiceConfig,
20
+ SearchOptions,
21
+ pagination_links,
22
+ )
23
+ from invenio_records_resources.services.base import (
24
+ ConditionalLink,
25
+ Service,
26
+ ServiceListResult,
27
+ )
28
+ from invenio_records_resources.services.records.components import DataComponent
29
+ from invenio_records_resources.services.records.params import (
30
+ FilterParam,
31
+ SuggestQueryParser,
32
+ )
33
+
34
+ from ..records.api import Vocabulary
35
+ from ..records.models import VocabularyType
36
+ from . import results
37
+ from .components import PIDComponent, VocabularyTypeComponent
38
+ from .permissions import PermissionPolicy
39
+ from .schema import TaskSchema, VocabularySchema
40
+
41
+
42
+ def is_custom_vocabulary_type(vocabulary_type, context):
43
+ """Check if the vocabulary type is a custom vocabulary type."""
44
+ return vocabulary_type["id"] in current_app.config.get(
45
+ "VOCABULARIES_CUSTOM_VOCABULARY_TYPES", []
46
+ )
47
+
48
+
49
+ class VocabularySearchOptions(SearchOptions):
50
+ """Search options for vocabularies."""
51
+
52
+ params_interpreters_cls = [
53
+ FilterParam.factory(param="tags", field="tags"),
54
+ ] + SearchOptions.params_interpreters_cls
55
+
56
+ suggest_parser_cls = SuggestQueryParser.factory(
57
+ fields=[
58
+ "id.text^100",
59
+ "id.text._2gram",
60
+ "id.text._3gram",
61
+ "title.en^5",
62
+ "title.en._2gram",
63
+ "title.en._3gram",
64
+ ],
65
+ )
66
+
67
+ sort_default = "bestmatch"
68
+
69
+ sort_default_no_query = "title"
70
+
71
+ sort_options = {
72
+ "bestmatch": dict(
73
+ title=_("Best match"),
74
+ fields=["_score"], # ES defaults to desc on `_score` field
75
+ ),
76
+ "title": dict(
77
+ title=_("Title"),
78
+ fields=["title_sort"],
79
+ ),
80
+ "newest": dict(
81
+ title=_("Newest"),
82
+ fields=["-created"],
83
+ ),
84
+ "oldest": dict(
85
+ title=_("Oldest"),
86
+ fields=["created"],
87
+ ),
88
+ }
89
+
90
+
91
+ class VocabularyTypeSearchOptions(SearchOptions):
92
+ """Search options for vocabulary types."""
93
+
94
+ sort_options = {
95
+ "id": dict(
96
+ title=_("ID"),
97
+ fields=["id"],
98
+ ),
99
+ }
100
+
101
+ sort_default = "id"
102
+
103
+ sort_default_no_query = "id"
104
+
105
+ sort_direction_options = {
106
+ "asc": dict(title=_("Ascending"), fn=sa.asc),
107
+ "desc": dict(title=_("Descending"), fn=sa.desc),
108
+ }
109
+
110
+ sort_direction_default = "asc"
111
+
112
+
113
+ class VocabulariesServiceConfig(RecordServiceConfig):
114
+ """Vocabulary service configuration."""
115
+
116
+ service_id = "vocabularies"
117
+ indexer_queue_name = "vocabularies"
118
+ permission_policy_cls = PermissionPolicy
119
+ record_cls = Vocabulary
120
+ schema = VocabularySchema
121
+ task_schema = TaskSchema
122
+
123
+ search = VocabularySearchOptions
124
+
125
+ components = [
126
+ # Order of components are important!
127
+ VocabularyTypeComponent,
128
+ DataComponent,
129
+ PIDComponent,
130
+ ]
131
+
132
+ links_item = {
133
+ "self": Link(
134
+ "{+api}/vocabularies/{type}/{id}",
135
+ vars=lambda record, vars: vars.update(
136
+ {
137
+ "id": record.pid.pid_value,
138
+ "type": record.type.id,
139
+ }
140
+ ),
141
+ ),
142
+ }
143
+
144
+ links_search = pagination_links("{+api}/vocabularies/{type}{?args*}")
145
+
146
+
147
+ class VocabularyTypesServiceConfig(RecordServiceConfig):
148
+ """Vocabulary types service configuration."""
149
+
150
+ service_id = "vocabulary_types"
151
+ permission_policy_cls = PermissionPolicy
152
+ record_cls = VocabularyType
153
+ schema = VocabularySchema # Works but should be VocabularyTypeSchema if this is defined at some point
154
+ result_list_cls = results.VocabularyTypeList
155
+
156
+ links_item = {
157
+ "self": ConditionalLink(
158
+ cond=is_custom_vocabulary_type,
159
+ if_=Link(
160
+ "{+api}/{id}",
161
+ vars=lambda vocab_type, vars: vars.update({"id": vocab_type["id"]}),
162
+ ),
163
+ else_=Link(
164
+ "{+api}/vocabularies/{id}",
165
+ vars=lambda vocab_type, vars: vars.update({"id": vocab_type["id"]}),
166
+ ),
167
+ )
168
+ }
169
+
170
+ search = VocabularyTypeSearchOptions
171
+
172
+ components = [
173
+ # Order of components are important!
174
+ VocabularyTypeComponent,
175
+ DataComponent,
176
+ PIDComponent,
177
+ ]
178
+
179
+ links_search = pagination_links("{+api}/vocabularies/{type}{?args*}")
@@ -7,6 +7,7 @@
7
7
 
8
8
 
9
9
  """Custom fields."""
10
+
10
11
  from invenio_i18n import lazy_gettext as _
11
12
 
12
13
  from ...contrib.subjects.api import Subject
@@ -25,7 +26,7 @@ class SubjectCF(VocabularyCF):
25
26
  vocabulary_id="subjects",
26
27
  schema=SubjectRelationSchema,
27
28
  ui_schema=SubjectRelationSchema,
28
- **kwargs
29
+ **kwargs,
29
30
  )
30
31
  self.pid_field = Subject.pid
31
32
 
@@ -39,7 +39,7 @@ class VocabularyCF(BaseCF):
39
39
  sort_by=None,
40
40
  schema=VocabularyRelationSchema,
41
41
  ui_schema=VocabularyL10NItemSchema,
42
- **kwargs
42
+ **kwargs,
43
43
  ):
44
44
  """Constructor."""
45
45
  super().__init__(name, **kwargs)
@@ -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
@@ -21,3 +21,5 @@ class PermissionPolicy(RecordPermissionPolicy):
21
21
  can_update = [SystemProcess()]
22
22
  can_delete = [SystemProcess()]
23
23
  can_manage = [SystemProcess()]
24
+ # this permission is needed for the /api/vocabularies/ endpoint
25
+ can_list_vocabularies = [SystemProcess(), AnyUser()]
@@ -0,0 +1,110 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2024 CERN.
4
+ # Copyright (C) 2024 Uni Münster.
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
+
10
+ """Vocabulary results."""
11
+
12
+ from flask import current_app
13
+ from invenio_records_resources.proxies import current_service_registry
14
+ from invenio_records_resources.services import RecordServiceConfig
15
+ from invenio_records_resources.services.records.results import RecordList
16
+ from invenio_search import current_search_client
17
+
18
+ from ..proxies import current_service
19
+
20
+
21
+ class VocabularyTypeList(RecordList):
22
+ """Ensures that vocabulary type metadata is returned in the proper format."""
23
+
24
+ @property
25
+ def total(self):
26
+ """Get total number of hits."""
27
+ return self._results.total
28
+
29
+ @property
30
+ def custom_vocabulary_names(self):
31
+ """Checks whether vocabulary is a custom vocabulary."""
32
+ return current_app.config.get("VOCABULARIES_CUSTOM_VOCABULARY_TYPES", [])
33
+
34
+ def to_dict(self):
35
+ """Formats result to a dict of hits."""
36
+ config_vocab_types = current_app.config.get(
37
+ "INVENIO_VOCABULARY_TYPE_METADATA", {}
38
+ )
39
+
40
+ count_terms_agg = {}
41
+ generic_stats = self._generic_vocabulary_statistics()
42
+ custom_stats = self._custom_vocabulary_statistics()
43
+
44
+ for k in generic_stats.keys() | custom_stats.keys():
45
+ count_terms_agg[k] = generic_stats.get(k, 0) + custom_stats.get(k, 0)
46
+
47
+ hits = self._results.items
48
+
49
+ # Extend database data with configuration & aggregation data.
50
+ results = []
51
+ for db_vocab_type in hits:
52
+ result = {
53
+ "id": db_vocab_type.id,
54
+ "pid_type": db_vocab_type.pid_type,
55
+ "count": count_terms_agg.get(db_vocab_type.id, 0),
56
+ "is_custom_vocabulary": db_vocab_type.id
57
+ in self.custom_vocabulary_names,
58
+ }
59
+
60
+ if db_vocab_type.id in config_vocab_types:
61
+ for k, v in config_vocab_types[db_vocab_type.id].items():
62
+ result[k] = v
63
+
64
+ results.append(result)
65
+
66
+ for hit in results:
67
+ if self._links_item_tpl:
68
+ hit["links"] = self._links_item_tpl.expand(self._identity, hit)
69
+
70
+ res = {
71
+ "hits": {
72
+ "hits": results,
73
+ "total": self.total,
74
+ }
75
+ }
76
+
77
+ if self._params:
78
+ if self._links_tpl:
79
+ res["links"] = self._links_tpl.expand(self._identity, self.pagination)
80
+
81
+ return res
82
+
83
+ def _custom_vocabulary_statistics(self):
84
+ # query database for count of terms in custom vocabularies
85
+ returndict = {}
86
+ for vocab_type in self.custom_vocabulary_names:
87
+ custom_service = current_service_registry.get(vocab_type)
88
+ record_cls = custom_service.config.record_cls
89
+ returndict[vocab_type] = record_cls.model_cls.query.count()
90
+
91
+ return returndict
92
+
93
+ def _generic_vocabulary_statistics(self):
94
+ # Opensearch query for generic vocabularies
95
+ config: RecordServiceConfig = (
96
+ current_service.config
97
+ ) # TODO: Where to get the config from here? current_service is None
98
+ search_opts = config.search
99
+
100
+ search = search_opts.search_cls(
101
+ using=current_search_client,
102
+ index=config.record_cls.index.search_alias,
103
+ )
104
+
105
+ search.aggs.bucket("vocabularies", {"terms": {"field": "type.id", "size": 100}})
106
+
107
+ search_result = search.execute()
108
+ buckets = search_result.aggs.to_dict()["vocabularies"]["buckets"]
109
+
110
+ return {bucket["key"]: bucket["doc_count"] for bucket in buckets}
@@ -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
  #
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
@@ -35,6 +35,9 @@ class BaseVocabularyRelationSchema(Schema):
35
35
 
36
36
  id = SanitizedUnicode(required=True)
37
37
 
38
+ # Nested field type for administration UI form generation
39
+ administration_schema_type = "vocabulary"
40
+
38
41
 
39
42
  class VocabularyRelationSchema(BaseVocabularyRelationSchema):
40
43
  """Vocabulary relation schema."""
@@ -63,6 +66,9 @@ class ContribVocabularyRelationSchema(Schema):
63
66
  ftf_name = None # free text field name
64
67
  parent_field_name = None
65
68
 
69
+ # Nested field type for administration UI form generation
70
+ administration_schema_type = "vocabulary"
71
+
66
72
  @validates_schema
67
73
  def validate_relation_schema(self, data, **kwargs):
68
74
  """Validates that either id either the free text field are present."""
@@ -90,13 +96,16 @@ class BaseVocabularySchema(BaseRecordSchema):
90
96
  title = i18n_strings
91
97
  description = i18n_strings
92
98
  icon = fields.Str(allow_none=False)
99
+ tags = fields.List(SanitizedUnicode())
100
+
101
+ # Nested field type for administration UI form generation
102
+ administration_schema_type = "vocabulary"
93
103
 
94
104
 
95
105
  class VocabularySchema(BaseVocabularySchema):
96
106
  """Service schema for vocabulary records."""
97
107
 
98
108
  props = fields.Dict(allow_none=False, keys=fields.Str(), values=fields.Str())
99
- tags = fields.List(SanitizedUnicode())
100
109
  type = fields.Str(attribute="type.id", required=True)
101
110
 
102
111
 
@@ -1,7 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2020-2021 CERN.
3
+ # Copyright (C) 2024 CERN.
4
4
  # Copyright (C) 2021 Northwestern University.
5
+ # Copyright (C) 2024 Uni Münster.
5
6
  #
6
7
  # Invenio-Vocabularies is free software; you can redistribute it and/or
7
8
  # modify it under the terms of the MIT License; see LICENSE file for more
@@ -9,9 +10,8 @@
9
10
 
10
11
  """Vocabulary service."""
11
12
 
13
+ import sqlalchemy as sa
12
14
  from invenio_cache import current_cache
13
- from invenio_db import db
14
- from invenio_i18n import lazy_gettext as _
15
15
  from invenio_records_resources.services import (
16
16
  Link,
17
17
  LinksTemplate,
@@ -20,97 +20,52 @@ from invenio_records_resources.services import (
20
20
  SearchOptions,
21
21
  pagination_links,
22
22
  )
23
- from invenio_records_resources.services.records.components import DataComponent
24
- from invenio_records_resources.services.records.params import (
25
- FilterParam,
26
- SuggestQueryParser,
27
- )
23
+ from invenio_records_resources.services.base.utils import map_search_params
28
24
  from invenio_records_resources.services.records.schema import ServiceSchemaWrapper
29
25
  from invenio_records_resources.services.uow import unit_of_work
30
26
  from invenio_search.engine import dsl
31
27
 
32
- from ..records.api import Vocabulary
33
28
  from ..records.models import VocabularyType
34
- from .components import PIDComponent, VocabularyTypeComponent
35
- from .permissions import PermissionPolicy
36
- from .schema import TaskSchema, VocabularySchema
37
29
  from .tasks import process_datastream
38
30
 
39
31
 
40
- class VocabularySearchOptions(SearchOptions):
41
- """Search options."""
42
-
43
- params_interpreters_cls = [
44
- FilterParam.factory(param="tags", field="tags"),
45
- ] + SearchOptions.params_interpreters_cls
46
-
47
- suggest_parser_cls = SuggestQueryParser.factory(
48
- fields=[
49
- "id.text^100",
50
- "id.text._2gram",
51
- "id.text._3gram",
52
- "title.en^5",
53
- "title.en._2gram",
54
- "title.en._3gram",
55
- ],
56
- )
57
-
58
- sort_default = "bestmatch"
59
-
60
- sort_default_no_query = "title"
61
-
62
- sort_options = {
63
- "bestmatch": dict(
64
- title=_("Best match"),
65
- fields=["_score"], # ES defaults to desc on `_score` field
66
- ),
67
- "title": dict(
68
- title=_("Title"),
69
- fields=["title_sort"],
70
- ),
71
- "newest": dict(
72
- title=_("Newest"),
73
- fields=["-created"],
74
- ),
75
- "oldest": dict(
76
- title=_("Oldest"),
77
- fields=["created"],
78
- ),
79
- }
80
-
81
-
82
- class VocabulariesServiceConfig(RecordServiceConfig):
83
- """Vocabulary service configuration."""
84
-
85
- service_id = "vocabularies"
86
- indexer_queue_name = "vocabularies"
87
- permission_policy_cls = PermissionPolicy
88
- record_cls = Vocabulary
89
- schema = VocabularySchema
90
- task_schema = TaskSchema
91
-
92
- search = VocabularySearchOptions
93
-
94
- components = [
95
- # Order of components are important!
96
- VocabularyTypeComponent,
97
- DataComponent,
98
- PIDComponent,
99
- ]
100
-
101
- links_item = {
102
- "self": Link(
103
- "{+api}/vocabularies/{type}/{id}",
104
- vars=lambda record, vars: vars.update(
105
- {
106
- "id": record.pid.pid_value,
107
- "type": record.type.id,
108
- }
109
- ),
110
- ),
111
- }
32
+ class VocabularyTypeService(RecordService):
33
+ """Vocabulary type service."""
34
+
35
+ def search(self, identity, params=None):
36
+ """Search for vocabulary types entries."""
37
+ self.require_permission(identity, "list_vocabularies")
38
+
39
+ search_params = map_search_params(self.config.search, params)
40
+
41
+ query_param = search_params["q"]
42
+
43
+ filters = []
44
+ if query_param:
45
+ filters.extend([VocabularyType.id.ilike(f"%{query_param}%")])
46
+
47
+ vocabulary_types = (
48
+ VocabularyType.query.filter(sa.or_(*filters))
49
+ .order_by(
50
+ search_params["sort_direction"](
51
+ sa.text(",".join(search_params["sort"]))
52
+ )
53
+ )
54
+ .paginate(
55
+ page=search_params["page"],
56
+ per_page=search_params["size"],
57
+ error_out=False,
58
+ )
59
+ )
112
60
 
113
- links_search = pagination_links("{+api}/vocabularies/{type}{?args*}")
61
+ return self.config.result_list_cls(
62
+ self,
63
+ identity,
64
+ vocabulary_types,
65
+ search_params,
66
+ links_tpl=LinksTemplate(self.config.links_search, context={"args": params}),
67
+ links_item_tpl=self.links_item_tpl,
68
+ )
114
69
 
115
70
 
116
71
  class VocabulariesService(RecordService):
@@ -145,7 +100,7 @@ class VocabulariesService(RecordService):
145
100
  params,
146
101
  search_preference,
147
102
  extra_filter=dsl.Q("term", type__id=vocabulary_type.id),
148
- **kwargs
103
+ **kwargs,
149
104
  ).execute()
150
105
 
151
106
  return self.result_list(
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2022 CERN.
3
+ # Copyright (C) 2022-2024 CERN.
4
4
  #
5
5
  # Invenio-Vocabularies is free software; you can redistribute it and/or modify
6
6
  # it under the terms of the MIT License; see LICENSE file for more details.
@@ -11,7 +11,6 @@ from celery import shared_task
11
11
  from flask import current_app
12
12
 
13
13
  from ..datastreams.factories import DataStreamFactory
14
- from ..factories import get_vocabulary_config
15
14
 
16
15
 
17
16
  @shared_task(ignore_result=True)
@@ -27,32 +26,3 @@ def process_datastream(config):
27
26
  if result.errors:
28
27
  for err in result.errors:
29
28
  current_app.logger.error(err)
30
-
31
-
32
- @shared_task()
33
- def import_funders():
34
- """Import the funders vocabulary.
35
-
36
- Only new records are imported.
37
- Existing records are not updated.
38
- """
39
- vc = get_vocabulary_config("funders")
40
- config = vc.get_config()
41
-
42
- # When importing funders via a Celery task, make sure that we are automatically downloading the ROR file,
43
- # instead of relying on a local file on the file system.
44
- if config["readers"][0]["type"] == "ror-http":
45
- readers_config_with_ror_http = config["readers"]
46
- else:
47
- readers_config_with_ror_http = [{"type": "ror-http"}] + config["readers"]
48
-
49
- ds = DataStreamFactory.create(
50
- readers_config=readers_config_with_ror_http,
51
- transformers_config=config.get("transformers"),
52
- writers_config=config["writers"],
53
- )
54
-
55
- for result in ds.process():
56
- if result.errors:
57
- for err in result.errors:
58
- current_app.logger.error(err)
@@ -0,0 +1,12 @@
1
+ {#
2
+ Copyright (C) 2024 Uni Münster.
3
+
4
+ Invenio App RDM is free software; you can redistribute it and/or modify it
5
+ under the terms of the MIT License; see LICENSE file for more details.
6
+ #}
7
+ {% extends "invenio_administration/search.html" %}
8
+
9
+ {% block javascript %}
10
+ {{ super() }}
11
+ {{ webpack['invenio-vocabularies-search.js'] }}
12
+ {% endblock %}
@@ -0,0 +1,71 @@
1
+ {#
2
+ Copyright (C) 2024 CERN.
3
+
4
+ Invenio App RDM is free software; you can redistribute it and/or modify it
5
+ under the terms of the MIT License; see LICENSE file for more details.
6
+ #}
7
+
8
+ {%- from "invenio_administration/macros.html" import go_back %}
9
+
10
+ {% extends "invenio_administration/search.html" %}
11
+
12
+ {% block admin_main_column %}
13
+ <main id="admin-main-content"
14
+ class="ten wide mobile twelve wide tablet thirteen wide computer fourteen wide widescreen column">
15
+
16
+ <div class="ui container fluid pl-10 pr-10 pt-10 pb-10">
17
+ {{ go_back() }}
18
+ <div class="ui grid">
19
+ <div class="column six wide">
20
+ <h1 class="ui header">{{ title or name }}</h1>
21
+ </div>
22
+ <div class="column ten wide right aligned">
23
+ <a class="ui icon labeled button"
24
+ href="{{ edit_endpoint }}">
25
+ <i aria-hidden="true"
26
+ class="cog icon"></i>{{ _("Settings") }}
27
+ </a>
28
+ <a class="ui icon labeled button"
29
+ href="{{ create_ui_endpoint }}">
30
+ <i aria-hidden="true"
31
+ class="calendar icon"></i>{{ _("Schedule") }}
32
+ </a>
33
+ <a class="ui icon labeled button"
34
+ href="{{ run_endpoint }}">
35
+ <i aria-hidden="true"
36
+ class="play icon"></i>{{ _("Run now") }}
37
+ </a>
38
+ </div>
39
+ </div>
40
+ {% block admin_page_content %}
41
+ <div class="ui divider" aria-hidden="true"></div>
42
+
43
+ {%- block search_app %}
44
+ <div
45
+ id="invenio-search-config"
46
+ data-title='{{ title | tojson }}'
47
+ data-resource-name='{{ resource_name | tojson }}'
48
+ data-invenio-search-config='{{ search_config() | tojson }}'
49
+ data-fields='{{ fields | tojson }}'
50
+ data-display-search='{{ display_search | tojson }}'
51
+ data-display-read='{{ display_read | tojson }}'
52
+ data-display-edit='{{ display_edit | tojson }}'
53
+ data-display-delete='{{ display_delete | tojson }}'
54
+ data-resource-schema='{{ resource_schema | tojson }}'
55
+ data-actions='{{ actions | tojson }}'
56
+ data-api-endpoint='{{ api_endpoint }}'
57
+ data-pid-path='{{ pid_path | tojson }}'
58
+ data-create-endpoint='{{ create_ui_endpoint }}'
59
+ data-list-endpoint='{{ list_ui_endpoint }}'
60
+ >
61
+ </div>
62
+ {%- endblock search_app %}
63
+ {% endblock admin_page_content %}
64
+ </div>
65
+ </main>
66
+ {% endblock %}
67
+
68
+ {% block javascript %}
69
+ {{ super() }}
70
+ {{ webpack['invenio-jobs-details.js'] }}
71
+ {% endblock %}
@@ -44,3 +44,10 @@ def create_names_blueprint_from_app(app):
44
44
  def create_subjects_blueprint_from_app(app):
45
45
  """Create app blueprint."""
46
46
  return app.extensions["invenio-vocabularies"].subjects_resource.as_blueprint()
47
+
48
+
49
+ def create_list_blueprint_from_app(app):
50
+ """Create app blueprint."""
51
+ return app.extensions[
52
+ "invenio-vocabularies"
53
+ ].vocabulary_admin_resource.as_blueprint()