Skip to content

Commit

Permalink
jsonschema: configure the holding editor
Browse files Browse the repository at this point in the history
The holding JSONSchema is adapted to be usable by the admin ui editor.

* Fixes permissions in the API REST serializer: create is renamed to
cannot_create.
* Fixes the holding importation by defining a default value for the
holding harvested properties.
* Fixes the returned http status when wrong data are posted to the api
holding views.

Co-Authored-by: Johnny Mariéthoz <Johnny.Mariethoz@rero.ch>
Co-Authored-by: Aly Badr <aly.badr@rero.ch>
  • Loading branch information
jma and Aly Badr committed Apr 2, 2020
1 parent 3d90b65 commit 7ed7dfb
Show file tree
Hide file tree
Showing 14 changed files with 1,255 additions and 237 deletions.
1 change: 0 additions & 1 deletion data/patterns.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@
},
{
"name": "level_2",
"starting_value": 1,
"mapping_values": [
"printemps",
"\u00e9t\u00e9",
Expand Down
2 changes: 1 addition & 1 deletion rero_ils/modules/documents/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def is_available(self, view_code):
@property
def harvested(self):
"""Is this record harvested from an external service."""
return self.get('harvested')
return self.get('harvested', False)

@property
def can_edit(self):
Expand Down
35 changes: 32 additions & 3 deletions rero_ils/modules/holdings/api_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@

from __future__ import absolute_import, print_function

from flask import Blueprint, abort, jsonify
from functools import wraps

from flask import Blueprint, abort, current_app, jsonify
from flask import request as flask_request
from jinja2.exceptions import TemplateSyntaxError, UndefinedError
from werkzeug.exceptions import NotFound

from .api import Holding
from ..items.api_views import check_authentication, jsonify_error
from ..items.api_views import check_authentication

api_blueprint = Blueprint(
'api_holding',
Expand All @@ -33,6 +37,31 @@
)


def jsonify_error(func):
"""Jsonify errors.
:param func: function that use this decorator
"""
@wraps(func)
def decorated_view(*args, **kwargs):
try:
return func(*args, **kwargs)
except NotFound as error:
raise(error)
except TemplateSyntaxError as error:
return jsonify({'status': 'error: {error}'.format(
error=error)}), 400
except UndefinedError as error:
return jsonify({'status': 'error: {error}'.format(
error=error)}), 400
except Exception as error:
raise(error)
current_app.logger.error(str(error))
return jsonify({'status': 'error: {error}'.format(
error=error)}), 500
return decorated_view


@api_blueprint.route('/availabilty/<holding_pid>', methods=['GET'])
@check_authentication
@jsonify_error
Expand All @@ -46,7 +75,7 @@ def holding_availability(holding_pid):
})


@api_blueprint.route('/<holding_pid>/patterns/preview/', methods=['GET'])
@api_blueprint.route('/<holding_pid>/patterns/preview', methods=['GET'])
@check_authentication
@jsonify_error
def patterns_preview(holding_pid):
Expand Down
212 changes: 142 additions & 70 deletions rero_ils/modules/holdings/jsonschemas/holdings/holding-v0.0.1.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"title": "Holding",
"description": "JSON schema for holdings.",
"type": "object",
"additionalProperties": false,
"required": [
"$schema",
Expand All @@ -12,6 +12,13 @@
"location",
"document"
],
"propertiesOrder": [
"call_number",
"circulation_category",
"location",
"holdings_type",
"patterns"
],
"properties": {
"$schema": {
"title": "Schema",
Expand All @@ -34,22 +41,36 @@
"circulation_category": {
"title": "Circulation type",
"type": "object",
"required": [
"$ref"
],
"properties": {
"$ref": {
"title": "circulation category URI",
"type": "string",
"pattern": "^https://ils.rero.ch/api/item_types/.*?$"
"pattern": "^https://ils.rero.ch/api/item_types/.*?$",
"form": {
"remoteOptions": {
"type": "item_types"
}
}
}
}
},
"location": {
"title": "Location",
"type": "object",
"required": [
"$ref"
],
"properties": {
"$ref": {
"title": "Location URI",
"type": "string",
"pattern": "^https://ils.rero.ch/api/locations/.*?$"
"pattern": "^https://ils.rero.ch/api/locations/.+?$",
"form": {
"fieldMap": "location"
}
}
}
},
Expand Down Expand Up @@ -92,116 +113,167 @@
},
"holdings_type": {
"type": "string",
"title": "Type of the holdings",
"title": "Holding Type",
"enum": [
"standard",
"electronic",
"serial"
],
"default": "standard"
"default": "serial",
"form": {
"hideExpression": "true"
}
},
"patterns": {
"title": "Captions for the patterns enumeration and chronology.",
"form": {
"expressionProperties": {
"templateOptions.required": "true"
}
},
"title": "Serial Configuration",
"type": "object",
"propertiesOrder": [
"template",
"values"
],
"required": [
"values",
"template"
],
"additionalProperties": false,
"properties": {
"template": {
"title": "Template for the display of the holdings issues.",
"title": "Issue Display Template",
"description": "This template define how a prediction is displayed. i.e. year 2020; vol.1, iss. 4. It should contains the variable field between {{}} with the corresponding pattern and level name: i.e. {{chronology.year}}; vol. {{enumeration.volume}}, iss. {{enumeration.issue}}.",
"type": "string",
"minLength": 3
"minLength": 3,
"pattern": ".*?\\{\\{.*?\\}\\}.*?",
"form": {
"validation": {
"messages": {
"pattern": "Should contains at least one variable between {{ }}."
}
}
}
},
"values": {
"title": "Values of the captions information.",
"title": "Prediction Patterns",
"type": "array",
"minItems": 1,
"items": {
"title": "Captions",
"title": "Prediction Pattern",
"type": "object",
"required": [
"name"
"name",
"levels"
],
"propertiesOrder": [
"name",
"levels"
],
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"title": "Name of the caption chronology or enumeration.",
"title": "Name",
"description": "Name of the pattern. It should be used in the display template. i.e. chronology, enumeration.",
"minLength": 1
},
"levels": {
"title": "Caption's chronology or enumeration levels.",
"title": "Chronology Levels",
"type": "array",
"minItems": 1,
"default": [],
"items": {
"title": "Caption's chronology or enumeration levels.",
"title": "Chronology Level",
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string",
"title": "Name of the chronology or enumeration level.",
"minLength": 1
},
"starting_value": {
"type": "integer",
"title": "The starting value of current level.",
"minimum": 1
},
"next_value": {
"type": "integer",
"title": "The next value of current level.",
"minimum": 1
},
"completion_value": {
"type": "integer",
"title": "Units per next higher level.",
"minimum": 1
"oneOf": [
{
"title": "Number Based Prediction",
"additionalProperties": false,
"propertiesOrder": [
"name",
"starting_value",
"completion_value",
"next_value"
],
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"title": "Name",
"description": "Name of the pattern level. It should be used in the display template. i.e. year, month, volume, issue, etc.",
"minLength": 1
},
"starting_value": {
"type": "integer",
"title": "Starting Value",
"description": "First value of the sequence. Default: 1.",
"minimum": 1
},
"completion_value": {
"type": "integer",
"title": "Completion of the Values",
"description": "Last value of the sequence. If it is not defined the sequence will continue until the infinity.",
"minimum": 1
},
"next_value": {
"type": "integer",
"title": "Next Predicted Value",
"description": "Can be used to correct the next current prediction.",
"minimum": 1
}
}
},
"mapping_values": {
"title": "Mapping values for the chronology or enumeration level",
"type": "array",
"uniqueItems": true,
"minItems": 1,
"items": {
"title": "Elements of the mapping values.",
"type": "string",
"minLength": 1
{
"title": "List Based Prediction",
"additionalProperties": false,
"required": [
"name",
"mapping_values"
],
"propertiesOrder": [
"name",
"mapping_values",
"next_value"
],
"properties": {
"name": {
"type": "string",
"description": "Name of the pattern level. It should be used in the display template. i.e. year, month, volume, issue",
"title": "Name",
"minLength": 1
},
"mapping_values": {
"title": "Values",
"type": "array",
"uniqueItems": true,
"minItems": 1,
"default": [],
"items": {
"title": "Value",
"description": "Use a value instead of a number. i.e. january, 2nd, quarter",
"type": "string",
"minLength": 1
}
},
"next_value": {
"type": "integer",
"title": "Next Predicted Value",
"description": "Can be used to correct the next current prediction. The value is the current position of the value in the list.",
"minimum": 1
}
}
}
}
]
}
}
}
}
}
}
}
},
"oneOf": [
{
"properties": {
"holdings_type": {
"enum": [
"serial"
]
}
},
"required": [
"patterns"
]
},
{
"properties": {
"holdings_type": {
"enum": [
"standard",
"electronic"
]
}
}
}
]
}
}
2 changes: 1 addition & 1 deletion rero_ils/modules/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def post_process_serialize_search(self, results, pid_fetcher):
'invenio_records_rest.{pid_type}_list'.format(
pid_type=pid_type), _external=True)
else:
permissions['create'] = {
permissions['cannot_create'] = {
'permission': "permission denied"}
results['permissions'] = permissions
results['links'].update(links)
Expand Down

0 comments on commit 7ed7dfb

Please sign in to comment.