diff --git a/invenio_app_ils/cli.py b/invenio_app_ils/cli.py index 9a4214c88..f3b5a3f9b 100644 --- a/invenio_app_ils/cli.py +++ b/invenio_app_ils/cli.py @@ -304,6 +304,7 @@ def generate(self): "value": "demo", }, "document_pid": random.choice(doc_pids), + "eitem_type": random.choice(EItem.EITEM_TYPES), "description": "{}".format(lorem.text()), "internal_notes": "{}".format(lorem.text()), "urls": [ diff --git a/invenio_app_ils/config.py b/invenio_app_ils/config.py index e2b05f9ed..87ff77524 100644 --- a/invenio_app_ils/config.py +++ b/invenio_app_ils/config.py @@ -829,6 +829,7 @@ def _(x): eitems=dict( aggs=dict( access=dict(terms=dict(field="open_access")), + eitem_type=dict(terms=dict(field="eitem_type")), has_files=dict( filters=dict( filters=dict( @@ -841,6 +842,7 @@ def _(x): ), ), post_filters=dict( + eitem_type=terms_filter("eitem_type"), access=terms_filter("open_access"), has_files=exists_value_filter("files.file_id", filter_value="has_files"), ), diff --git a/invenio_app_ils/documents/api.py b/invenio_app_ils/documents/api.py index e0c711829..8b43edf81 100644 --- a/invenio_app_ils/documents/api.py +++ b/invenio_app_ils/documents/api.py @@ -49,6 +49,7 @@ class Document(IlsRecordWithRelations): "STANDARD", "SERIAL_ISSUE", "ARTICLE", + "MULTIMEDIA", ] _pid_type = DOCUMENT_PID_TYPE diff --git a/invenio_app_ils/documents/jsonresolvers/document_eitem.py b/invenio_app_ils/documents/jsonresolvers/document_eitem.py index 9374be6f1..6ff5d89b4 100644 --- a/invenio_app_ils/documents/jsonresolvers/document_eitem.py +++ b/invenio_app_ils/documents/jsonresolvers/document_eitem.py @@ -31,6 +31,7 @@ def eitems_resolver(document_pid): eitems.append( { "pid": eitem.get("pid"), + "eitem_type": eitem.get("eitem_type"), "description": eitem.get("description"), "identifiers": eitem.get("identifiers", []), "internal_notes": eitem.get("internal_notes"), diff --git a/invenio_app_ils/documents/jsonresolvers/document_stock.py b/invenio_app_ils/documents/jsonresolvers/document_stock.py index a8369c74d..7d21c3aaf 100644 --- a/invenio_app_ils/documents/jsonresolvers/document_stock.py +++ b/invenio_app_ils/documents/jsonresolvers/document_stock.py @@ -11,6 +11,7 @@ from werkzeug.routing import Rule from invenio_app_ils.proxies import current_app_ils +from invenio_app_ils.eitems.api import EItem # Note: there must be only one resolver per file, # otherwise only the last one is registered @@ -32,9 +33,11 @@ def stock_resolver(document_pid): mediums = [ bucket.key for bucket in search_response.aggregations.mediums.buckets ] - eitems_count = eitem_search.search_by_document_pid(document_pid).count() - if eitems_count > 0: - mediums.append("E-BOOK") + eitems = eitem_search.search_by_document_pid(document_pid) + for type in EItem.EITEM_TYPES: + type_count = eitems.filter("term", eitem_type=type).count() + if type_count > 0: + mediums.append(type) return { "mediums": mediums, } diff --git a/invenio_app_ils/eitems/api.py b/invenio_app_ils/eitems/api.py index d78adb08b..75b262ffd 100644 --- a/invenio_app_ils/eitems/api.py +++ b/invenio_app_ils/eitems/api.py @@ -57,8 +57,14 @@ def validate(self, record, **kwargs): class EItem(IlsRecord): """EItem record class.""" + EITEM_TYPES = [ + "E-BOOK", + "AUDIOBOOK", + "VIDEO", + ] + _pid_type = EITEM_PID_TYPE - _schema = "eitems/eitem-v1.0.0.json" + _schema = "eitems/eitem-v2.0.0.json" _document_resolver_path = ( "{scheme}://{host}/api/resolver/eitems/{eitem_pid}/document" ) diff --git a/invenio_app_ils/eitems/loaders/jsonschemas/eitems.py b/invenio_app_ils/eitems/loaders/jsonschemas/eitems.py index 017b55b98..7dd64b320 100644 --- a/invenio_app_ils/eitems/loaders/jsonschemas/eitems.py +++ b/invenio_app_ils/eitems/loaders/jsonschemas/eitems.py @@ -8,8 +8,9 @@ """EItems schema for marshmallow loader.""" from invenio_records_rest.schemas import RecordMetadataSchemaJSONV1 -from marshmallow import EXCLUDE, Schema, fields, pre_load +from marshmallow import EXCLUDE, Schema, fields, pre_load, validate +from invenio_app_ils.eitems.api import EItem from invenio_app_ils.documents.loaders.jsonschemas.document import IdentifierSchema from invenio_app_ils.records.loaders.schemas.changed_by import ( ChangedBySchema, @@ -58,6 +59,7 @@ class Meta: created_by = fields.Nested(ChangedBySchema) description = fields.Str() document_pid = fields.Str(required=True) + eitem_type = fields.Str(required=True, validate=validate.OneOf(EItem.EITEM_TYPES)) files = fields.List(fields.Nested(FileSchema)) identifiers = fields.List(fields.Nested(IdentifierSchema)) internal_notes = fields.Str() diff --git a/invenio_app_ils/eitems/mappings/os-v1/eitems/eitem-v2.0.0.json b/invenio_app_ils/eitems/mappings/os-v1/eitems/eitem-v2.0.0.json new file mode 100644 index 000000000..426ea48fe --- /dev/null +++ b/invenio_app_ils/eitems/mappings/os-v1/eitems/eitem-v2.0.0.json @@ -0,0 +1,142 @@ +{ + "mappings": { + "date_detection": false, + "numeric_detection": false, + "properties": { + "$schema": { + "type": "keyword" + }, + "_created": { + "type": "date" + }, + "_updated": { + "type": "date" + }, + "bucket_id": { + "type": "keyword" + }, + "created_by": { + "properties": { + "type": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + }, + "type": "object" + }, + "description": { + "type": "text" + }, + "document": { + "properties": { + "authors": { + "type": "text" + }, + "cover_metadata": { + "properties": {}, + "type": "object" + }, + "edition": { + "type": "text" + }, + "pid": { + "type": "keyword" + }, + "publication_year": { + "type": "keyword" + }, + "title": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword" + } + } + } + }, + "type": "object" + }, + "document_pid": { + "type": "keyword" + }, + "eitem_type": { + "type": "keyword" + }, + "files": { + "properties": { + "bucket": { + "type": "keyword" + }, + "checksum": { + "type": "keyword" + }, + "file_id": { + "type": "keyword" + }, + "key": { + "type": "keyword" + }, + "size": { + "type": "keyword" + }, + "version_id": { + "type": "keyword" + } + }, + "type": "object" + }, + "identifiers": { + "properties": { + "material": { + "type": "keyword" + }, + "scheme": { + "type": "keyword" + }, + "value": { + "type": "keyword", + "fields": { + "text": { + "type": "text" + } + } + } + }, + "type": "object" + }, + "internal_notes": { + "type": "text" + }, + "open_access": { + "type": "boolean" + }, + "pid": { + "type": "keyword" + }, + "source": { + "type": "keyword", + "fields": { + "text": { + "type": "text" + } + } + }, + "urls": { + "properties": { + "description": { + "type": "text" + }, + "value": { + "type": "keyword" + }, + "login_required": { + "type": "boolean" + } + }, + "type": "object" + } + } + } +} diff --git a/invenio_app_ils/eitems/mappings/os-v2/eitems/eitem-v2.0.0.json b/invenio_app_ils/eitems/mappings/os-v2/eitems/eitem-v2.0.0.json new file mode 100644 index 000000000..426ea48fe --- /dev/null +++ b/invenio_app_ils/eitems/mappings/os-v2/eitems/eitem-v2.0.0.json @@ -0,0 +1,142 @@ +{ + "mappings": { + "date_detection": false, + "numeric_detection": false, + "properties": { + "$schema": { + "type": "keyword" + }, + "_created": { + "type": "date" + }, + "_updated": { + "type": "date" + }, + "bucket_id": { + "type": "keyword" + }, + "created_by": { + "properties": { + "type": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + }, + "type": "object" + }, + "description": { + "type": "text" + }, + "document": { + "properties": { + "authors": { + "type": "text" + }, + "cover_metadata": { + "properties": {}, + "type": "object" + }, + "edition": { + "type": "text" + }, + "pid": { + "type": "keyword" + }, + "publication_year": { + "type": "keyword" + }, + "title": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword" + } + } + } + }, + "type": "object" + }, + "document_pid": { + "type": "keyword" + }, + "eitem_type": { + "type": "keyword" + }, + "files": { + "properties": { + "bucket": { + "type": "keyword" + }, + "checksum": { + "type": "keyword" + }, + "file_id": { + "type": "keyword" + }, + "key": { + "type": "keyword" + }, + "size": { + "type": "keyword" + }, + "version_id": { + "type": "keyword" + } + }, + "type": "object" + }, + "identifiers": { + "properties": { + "material": { + "type": "keyword" + }, + "scheme": { + "type": "keyword" + }, + "value": { + "type": "keyword", + "fields": { + "text": { + "type": "text" + } + } + } + }, + "type": "object" + }, + "internal_notes": { + "type": "text" + }, + "open_access": { + "type": "boolean" + }, + "pid": { + "type": "keyword" + }, + "source": { + "type": "keyword", + "fields": { + "text": { + "type": "text" + } + } + }, + "urls": { + "properties": { + "description": { + "type": "text" + }, + "value": { + "type": "keyword" + }, + "login_required": { + "type": "boolean" + } + }, + "type": "object" + } + } + } +} diff --git a/invenio_app_ils/eitems/mappings/v7/eitems/eitem-v2.0.0.json b/invenio_app_ils/eitems/mappings/v7/eitems/eitem-v2.0.0.json new file mode 100644 index 000000000..426ea48fe --- /dev/null +++ b/invenio_app_ils/eitems/mappings/v7/eitems/eitem-v2.0.0.json @@ -0,0 +1,142 @@ +{ + "mappings": { + "date_detection": false, + "numeric_detection": false, + "properties": { + "$schema": { + "type": "keyword" + }, + "_created": { + "type": "date" + }, + "_updated": { + "type": "date" + }, + "bucket_id": { + "type": "keyword" + }, + "created_by": { + "properties": { + "type": { + "type": "keyword" + }, + "value": { + "type": "keyword" + } + }, + "type": "object" + }, + "description": { + "type": "text" + }, + "document": { + "properties": { + "authors": { + "type": "text" + }, + "cover_metadata": { + "properties": {}, + "type": "object" + }, + "edition": { + "type": "text" + }, + "pid": { + "type": "keyword" + }, + "publication_year": { + "type": "keyword" + }, + "title": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword" + } + } + } + }, + "type": "object" + }, + "document_pid": { + "type": "keyword" + }, + "eitem_type": { + "type": "keyword" + }, + "files": { + "properties": { + "bucket": { + "type": "keyword" + }, + "checksum": { + "type": "keyword" + }, + "file_id": { + "type": "keyword" + }, + "key": { + "type": "keyword" + }, + "size": { + "type": "keyword" + }, + "version_id": { + "type": "keyword" + } + }, + "type": "object" + }, + "identifiers": { + "properties": { + "material": { + "type": "keyword" + }, + "scheme": { + "type": "keyword" + }, + "value": { + "type": "keyword", + "fields": { + "text": { + "type": "text" + } + } + } + }, + "type": "object" + }, + "internal_notes": { + "type": "text" + }, + "open_access": { + "type": "boolean" + }, + "pid": { + "type": "keyword" + }, + "source": { + "type": "keyword", + "fields": { + "text": { + "type": "text" + } + } + }, + "urls": { + "properties": { + "description": { + "type": "text" + }, + "value": { + "type": "keyword" + }, + "login_required": { + "type": "boolean" + } + }, + "type": "object" + } + } + } +} diff --git a/invenio_app_ils/eitems/schemas/eitems/eitem-v2.0.0.json b/invenio_app_ils/eitems/schemas/eitems/eitem-v2.0.0.json new file mode 100644 index 000000000..6b4dd9c57 --- /dev/null +++ b/invenio_app_ils/eitems/schemas/eitems/eitem-v2.0.0.json @@ -0,0 +1,120 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Schema EItem", + "type": "object", + "required": ["$schema", "pid", "document_pid", "created_by", "eitem_type"], + "properties": { + "$schema": { + "type": "string" + }, + "bucket_id": { + "type": "string", + "title": "The bucket identifier for this EItem" + }, + "created_by": { + "additionalProperties": false, + "properties": { + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "description": { + "type": "string", + "title": "Any extra description for this EItem" + }, + "document_pid": { + "type": "string", + "title": "The persistent identifier of its Document" + }, + "eitem_type": { + "title": "EItem type", + "type": "string" + }, + "document": { + "type": "object", + "properties": { + "$ref": { + "type": "string" + } + } + }, + "files": { + "type": "object", + "properties": { + "$ref": { + "type": "string" + } + } + }, + "identifiers": { + "items": { + "properties": { + "material": { + "title": "Material to which the identifiers refers to.", + "type": "string" + }, + "scheme": { + "title": "Scheme of the identifier (Vocabulary)", + "type": "string" + }, + "value": { + "title": "Value of the identifier", + "type": "string" + } + }, + "required": ["value", "scheme"] + }, + "title": "List of Identifiers of the record", + "type": "array" + }, + "internal_notes": { + "type": "string", + "title": "Any extra description for this EItem reserved for internal usage" + }, + "open_access": { + "type": "boolean", + "title": "Indicate if the access to this EItem is open or not", + "default": true + }, + "pid": { + "type": "string", + "title": "The persistent identifier of this EItem" + }, + "source": { + "type": "string", + "title": "Source of the record." + }, + "urls": { + "items": { + "additionalProperties": false, + "properties": { + "description": { + "minLength": 1, + "type": "string" + }, + "value": { + "format": "uri", + "minLength": 1, + "type": "string" + }, + "login_required": { + "type": "boolean", + "title": "Indicate if the access to this link requires login", + "default": false + } + }, + "required": ["value"], + "title": "URL of external resource", + "type": "object" + }, + "minItems": 1, + "type": "array", + "uniqueItems": true + } + } +} diff --git a/tests/api/ils/eitems/test_eitems_crud.py b/tests/api/ils/eitems/test_eitems_crud.py index 1c45ad492..71731b35d 100644 --- a/tests/api/ils/eitems/test_eitems_crud.py +++ b/tests/api/ils/eitems/test_eitems_crud.py @@ -18,6 +18,7 @@ def test_eitem_refs(app, testdata): eitem = EItem.create( dict( pid="eitemid-99", + eitem_type="E-BOOK", document_pid="docid-1", created_by=dict(type="script", value="demo"), ) diff --git a/tests/api/ils/eitems/test_eitems_permissions.py b/tests/api/ils/eitems/test_eitems_permissions.py index e9d6fa43b..9f2bdd417 100644 --- a/tests/api/ils/eitems/test_eitems_permissions.py +++ b/tests/api/ils/eitems/test_eitems_permissions.py @@ -23,6 +23,7 @@ def test_eitems_permissions(client, testdata, json_headers, users): """Test eitems endpoints permissions.""" dummy_eitem = dict( document_pid="docid-1", + eitem_type="E-BOOK", internal_notes="An internal note", description="Description of the electronic item", open_access=True, diff --git a/tests/data/eitems.json b/tests/data/eitems.json index 2dae04bfa..de6488858 100644 --- a/tests/data/eitems.json +++ b/tests/data/eitems.json @@ -3,6 +3,7 @@ "pid": "eitemid-1", "created_by": {"type": "script", "value": "demo"}, "document_pid": "docid-1", + "eitem_type": "E-BOOK", "internal_notes": "An internal note", "description": "Description of the electronic item", "open_access": true, @@ -14,6 +15,7 @@ "pid": "eitemid-2", "created_by": {"type": "script", "value": "demo"}, "document_pid": "docid-2", + "eitem_type": "E-BOOK", "internal_notes": "An internal note", "description": "Description of the electronic item", "open_access": false, @@ -22,9 +24,10 @@ } }, { - "$schema": "https://127.0.0.1:5000/schemas/eitems/eitem-v1.0.0.json", + "$schema": "https://127.0.0.1:5000/schemas/eitems/eitem-v2.0.0.json", "bucket_id": "5d877356-59b2-4886-9e7f-0ba2cb6a5fd3", "document_pid": "docid-3", + "eitem_type": "E-BOOK", "files": [ { "bucket": "5d877356-59b2-4886-9e7f-0ba2cb6a5fd3", @@ -48,16 +51,18 @@ "created_by": {"type": "script", "value": "demo"} }, { - "$schema": "https://127.0.0.1:5000/schemas/eitems/eitem-v1.0.0.json", + "$schema": "https://127.0.0.1:5000/schemas/eitems/eitem-v2.0.0.json", "document_pid": "docid-1", + "eitem_type": "E-BOOK", "files": [], "open_access": true, "pid": "eitemid-4", "created_by": {"type": "script", "value": "demo"} }, { - "$schema": "https://127.0.0.1:5000/schemas/eitems/eitem-v1.0.0.json", + "$schema": "https://127.0.0.1:5000/schemas/eitems/eitem-v2.0.0.json", "document_pid": "docid-1", + "eitem_type": "E-BOOK", "files": [], "open_access": false, "pid": "eitemid-5",