diff --git a/storage_service/.pytest_cache/v/cache/lastfailed b/storage_service/.pytest_cache/v/cache/lastfailed new file mode 100644 index 000000000..cc05491da --- /dev/null +++ b/storage_service/.pytest_cache/v/cache/lastfailed @@ -0,0 +1,3 @@ +{ + "locations/tests/test_api_v3.py": true +} \ No newline at end of file diff --git a/storage_service/.pytest_cache/v/cache/nodeids b/storage_service/.pytest_cache/v/cache/nodeids new file mode 100644 index 000000000..c4c983472 --- /dev/null +++ b/storage_service/.pytest_cache/v/cache/nodeids @@ -0,0 +1,10 @@ +[ + "locations/tests/test_api_v3.py::TestV3FileAPI::test_auth", + "locations/tests/test_api_v3.py::TestV3FileAPI::test_files_search", + "locations/tests/test_api_v3.py::TestV3FileAPI::test_get_create_update_data", + "locations/tests/test_api_v3.py::TestV3FileAPI::test_get_many_files", + "locations/tests/test_api_v3.py::TestV3FileAPI::test_mutate_location", + "locations/tests/test_api_v3.py::TestV3FileAPI::test_mutate_space", + "locations/tests/test_api_v3.py::TestV3FileAPI::test_new_search", + "locations/tests/test_api_v3.py::TestV3FileAPI::test_read_only_resources" +] \ No newline at end of file diff --git a/storage_service/locations/api/urls.py b/storage_service/locations/api/urls.py index 90445ae22..438f33b59 100644 --- a/storage_service/locations/api/urls.py +++ b/storage_service/locations/api/urls.py @@ -20,9 +20,9 @@ v2_api.register(v2.AsyncResource()) urlpatterns = [ - url(r'v3/', include(v3_api.urls)), url(r'', include(v1_api.urls)), url(r'v1/sword/$', views.service_document, name='sword_service_document'), url(r'', include(v2_api.urls)), url(r'v2/sword/$', views.service_document, name='sword_service_document'), + url(r'v3/', include(v3_api.urls)), ] diff --git a/storage_service/locations/api/v3/__init__.py b/storage_service/locations/api/v3/__init__.py index 1a7c983e7..de9f0684b 100644 --- a/storage_service/locations/api/v3/__init__.py +++ b/storage_service/locations/api/v3/__init__.py @@ -19,15 +19,15 @@ | Purpose | HTTP Method | Path | Method | +-----------------+-------------+----------------------------+------------+ | Create new | POST | // | create | - | Create data | GET | //new/ | new | + | Get create data | GET | //new/ | new | | Read all | GET | // | index | | Read specific | GET | /// | show | | Update specific | PUT | /// | update | - | Update data | GET | ///edit/ | edit | + | Get update data | GET | ///edit/ | edit | | Delete specific | DELETE | /// | delete | | Search | SEARCH | // | search | | Search | POST | //search/ | search | - | Search data | GET | //new_search/ | new_search | + | Get search data | GET | //new_search/ | new_search | +-----------------+-------------+----------------------------+------------+ .. note:: To remove the search-related routes for a given resource, create a @@ -45,6 +45,7 @@ from locations.api.v3.remple import API from locations.api.v3.resources import ( + Files, Locations, Packages, Spaces, @@ -56,9 +57,11 @@ resources = { 'location': {'resource_cls': Locations}, - 'package': {'resource_cls': Packages}, # Readonly because of super-class of ``Packages`` 'space': {'resource_cls': Spaces}, 'pipeline': {'resource_cls': Pipelines}, + # The following resources are read-only because of their super-classes + 'file': {'resource_cls': Files}, + 'package': {'resource_cls': Packages}, } api = API(api_version=API_VERSION, service_name=SERVICE_NAME) diff --git a/storage_service/locations/api/v3/remple/__init__.py b/storage_service/locations/api/v3/remple/__init__.py index bcc5d5b39..17b3f48dc 100644 --- a/storage_service/locations/api/v3/remple/__init__.py +++ b/storage_service/locations/api/v3/remple/__init__.py @@ -24,8 +24,8 @@ get_member_targeting_regex, ) from . import utils -from .schemata import ValidModelObject +from .schemata import ResourceURI __all__ = ('API', 'UUID_PATT', 'ID_PATT', 'utils', 'ReadonlyResources', - 'QueryBuilder', 'Resources', 'ValidModelObject', + 'QueryBuilder', 'Resources', 'ResourceURI', 'get_collection_targeting_regex', 'get_member_targeting_regex',) diff --git a/storage_service/locations/api/v3/remple/clientbuilder.py b/storage_service/locations/api/v3/remple/clientbuilder.py index b35f45dd9..0527ce64f 100644 --- a/storage_service/locations/api/v3/remple/clientbuilder.py +++ b/storage_service/locations/api/v3/remple/clientbuilder.py @@ -299,6 +299,10 @@ def get_param_docstring_line(arg, arg_cfg): if arg_type: _, arg_type = openapitype2pythontype.get(arg_type, (None, arg_type)) arg_format = arg_cfg.get('format', arg_cfg.get('schema', {}).get('format')) + if (not arg_format) and arg_type == 'list': + arg_format = arg_cfg.get('items', {}).get('format') + if arg_format: + arg_format = 'each element is a {}'.format(arg_format) if arg_format: arg_line.append(' ({}; {}):'.format(arg_type, arg_format)) else: diff --git a/storage_service/locations/api/v3/remple/constants.py b/storage_service/locations/api/v3/remple/constants.py index 2c8b353aa..2d9fc31d9 100644 --- a/storage_service/locations/api/v3/remple/constants.py +++ b/storage_service/locations/api/v3/remple/constants.py @@ -1,3 +1,24 @@ +from django.db.models.fields import ( + AutoField, + BigIntegerField, + IntegerField, + BooleanField, + CharField, + TextField, + UUIDField, + DateTimeField, +) +from jsonfield.fields import JSONField +from formencode.validators import ( + Int, + IPAddress, + OneOf, + Bool, + UnicodeString, + URL, +) + + JSONDecodeErrorResponse = { 'error': 'JSON decode error: the parameters provided were not valid' ' JSON.' @@ -10,27 +31,28 @@ READONLY_RSLT = {'error': 'This resource is read-only.'} OK_STATUS = 200 +CREATED_STATUS = 201 BAD_REQUEST_STATUS = 400 FORBIDDEN_STATUS = 403 NOT_FOUND_STATUS = 404 METHOD_NOT_ALLOWED_STATUS = 405 -django_field_class2openapi_type = { - 'AutoField': 'integer', - 'BigIntegerField': 'integer', - 'IntegerField': 'integer', - 'BooleanField': 'boolean', - 'CharField': 'string', - 'TextField': 'string', - 'UUIDField': 'string', - 'DateTimeField': 'string', - 'JSONField': 'object', +django_field2openapi_type = { + AutoField: 'integer', + BigIntegerField: 'integer', + IntegerField: 'integer', + BooleanField: 'boolean', + CharField: 'string', + TextField: 'string', + UUIDField: 'string', + DateTimeField: 'string', + JSONField: 'object', } -django_field_class2openapi_format = { - 'UUIDField': 'uuid', - 'DateTimeField': 'date-time', +django_field2openapi_format = { + UUIDField: 'uuid', + DateTimeField: 'date-time', } python_type2openapi_type = { @@ -39,16 +61,16 @@ float: 'integer', } -formencode_field_class2openapi_type = { - 'UnicodeString': 'string', - 'OneOf': 'string', # note: not universally accurate - 'IPAddress': 'string', - 'URL': 'string', - 'Int': 'integer', - 'Bool': 'boolean', +formencode_field2openapi_type = { + UnicodeString: 'string', + OneOf: 'string', # note: not universally accurate + IPAddress: 'string', + URL: 'string', + Int: 'integer', + Bool: 'boolean', } -formencode_field_class2openapi_format = { - 'IPAddress': 'ipv4', - 'URL': 'uri', +formencode_field2openapi_format = { + IPAddress: 'ipv4', + URL: 'uri', } diff --git a/storage_service/locations/api/v3/remple/openapi.py b/storage_service/locations/api/v3/remple/openapi.py index 399f5fb0d..b132dd50e 100644 --- a/storage_service/locations/api/v3/remple/openapi.py +++ b/storage_service/locations/api/v3/remple/openapi.py @@ -15,17 +15,21 @@ OneToOneRel, ) from django.db.models.fields import NOT_PROVIDED +from formencode.foreach import ForEach +from formencode.compound import Any +from formencode.validators import OneOf from .schemata import schemata from .resources import Resources from .constants import ( - django_field_class2openapi_type, - django_field_class2openapi_format, + django_field2openapi_type, + django_field2openapi_format, python_type2openapi_type, - formencode_field_class2openapi_type, - formencode_field_class2openapi_format, + formencode_field2openapi_type, + formencode_field2openapi_format, ) from .querybuilder import QueryBuilder +from .schemata import ResourceURI def dict_representer(dumper, data): @@ -635,7 +639,7 @@ def _get_api_info(self): ('description', self._get_api_description()), ]) - def _get_dflt_server_path(self): + def get_dflt_server_path(self): return '{}{}'.format( self.path_prefix, self.get_api_version_slug()) @@ -645,7 +649,7 @@ def _get_api_servers(self): """ return [ OrderedDict([ - ('url', self._get_dflt_server_path()), + ('url', self.get_dflt_server_path()), ('description', self._get_dflt_server_description()), ]), ] @@ -896,7 +900,7 @@ def _get_filter_schemas(self, resource_name, resource_cfg, read_schema): self._get_filter_schema(resource_name, resource_cfg)]) def _get_simple_filter_schema(self, resource_name, resource_cfg): - model_name = resource_cfg['resource_cls'].model_cls.__name__ + model_cls = resource_cfg['resource_cls'].model_cls simple_schema_name = self._get_simple_filter_schema_name(resource_name) simple_schema = OrderedDict([ ('type', 'object'), @@ -904,7 +908,7 @@ def _get_simple_filter_schema(self, resource_name, resource_cfg): ('attribute', OrderedDict([ ('type', 'string'), ('enum', self._get_simple_attributes( - model_name, resource_cfg)), + model_cls, resource_cfg)), ])), ('relation', OrderedDict([ ('type', 'string'), @@ -923,22 +927,22 @@ def _get_query_schemata(self, resource_cfg): return query_builder.schemata def _get_relational_attributes(self, resource_name, resource_cfg): - model_name = resource_cfg['resource_cls'].model_cls.__name__ + model_cls = resource_cfg['resource_cls'].model_cls query_schemata = self._get_query_schemata(resource_cfg) return [(attr, cfg.get('foreign_model')) for attr, cfg in - query_schemata[model_name].items() + query_schemata[model_cls].items() if cfg.get('foreign_model')] - def _get_simple_attributes(self, model_cls_name, resource_cfg): + def _get_simple_attributes(self, model_cls, resource_cfg): query_schemata = self._get_query_schemata(resource_cfg) return [attr for attr, cfg in - query_schemata[model_cls_name].items() + query_schemata[model_cls].items() if not cfg.get('foreign_model')] - def _get_related_attributes(self, resource_cfg, related_model_name): + def _get_related_attributes(self, resource_cfg, related_model): query_schemata = self._get_query_schemata(resource_cfg) - return [attr for attr, cfg in query_schemata[related_model_name].items() + return [attr for attr, cfg in query_schemata[related_model].items() if not cfg.get('foreign_model')] def _get_relations(self, resource_name, resource_cfg): @@ -948,7 +952,7 @@ def _get_relations(self, resource_name, resource_cfg): def _get_related_filter_schemas(self, resource_name, resource_cfg): schemas = [] - for attribute, related_model_name in self._get_relational_attributes( + for attribute, related_model_cls in self._get_relational_attributes( resource_name, resource_cfg): related_schema_name = self._get_related_filter_schema_name( resource_name, attribute) @@ -962,7 +966,7 @@ def _get_related_filter_schemas(self, resource_name, resource_cfg): ('subattribute', OrderedDict([ ('type', 'string'), ('enum', self._get_related_attributes( - resource_cfg, related_model_name)), + resource_cfg, related_model_cls)), ])), ('relation', OrderedDict([ ('type', 'string'), @@ -1095,14 +1099,16 @@ def _get_new_schema(self, resource_name, resource_cfg, read_schema): new_schema = OrderedDict([('type', 'object')]) properties = OrderedDict() resource_cls = resource_cfg['resource_cls'] + resource_inst = resource_cls( + None, server_path=self.get_dflt_server_path(), + other_resources=self.resources) required_fields = [] - for field_name in resource_cls._get_new_edit_collections(): + for field_name in resource_inst._get_new_edit_collections(): properties[field_name] = OrderedDict([ ('type', 'array'), ('items', OrderedDict([ ('type', 'string'), - ('format', 'uuid of an instance of the {} resource'.format( - field_name)), + ('format', 'URI of a(n) {} resource'.format(field_name)), ])), ]) required_fields.append(field_name) @@ -1148,17 +1154,16 @@ def _get_create_update_schema(resource_name, resource_cfg, fields = schema_cls.fields required_fields = [] for field_name, field in fields.items(): - field_cls_name = field.__class__.__name__ field_dict = { - 'ValidModelObject': single_reference_mut_field_dict, - 'ForEach': multi_reference_mut_field_dict, - 'OneOf': enum_field_dict, - 'Any': disjunctive_field_dict, - }.get(field_cls_name, scalar_mut_field_dict)( - **{'field_cls_name': field_cls_name, 'field': field}) + ResourceURI: single_reference_mut_field_dict, + ForEach: multi_reference_mut_field_dict, + OneOf: enum_field_dict, + Any: disjunctive_field_dict, + }.get(type(field), scalar_mut_field_dict)( + **{'field': field}) if not field_dict.get('type') and not field_dict.get('anyOf'): print('WARNING: {}.{} is of unknown type (class {})'.format( - resource_name, field_name, field_cls_name)) + resource_name, field_name, type(field))) continue default = read_schema['properties'].get(field_name, {}).get( 'default', NOT_PROVIDED) @@ -1191,18 +1196,14 @@ def _get_read_schema(self, resource_name, resource_cfg): required_fields = [] for field in fields: field_name = field.name - field_cls = field.__class__ - field_cls_name = field_cls.__name__ field_name, field_dict = { ForeignKey: single_reference_field_dict, OneToOneRel: single_reference_field_dict, ManyToManyField: multi_reference_field_dict, ManyToManyRel: multi_reference_field_dict, ManyToOneRel: multi_reference_field_dict, - }.get(field_cls, scalar_field_dict)( - **{'field_name': field_name, - 'field_cls_name': field_cls_name, - 'field': field}) + }.get(type(field), scalar_field_dict)( + field_name=field_name, field=field) choices = get_choices(field) if choices: field_dict['enum'] = choices @@ -1211,12 +1212,12 @@ def _get_read_schema(self, resource_name, resource_cfg): default = get_default(field) if default != NOT_PROVIDED: field_dict['default'] = default - required = get_required(field, default, field_cls_name) + required = get_required(field, default) if required: required_fields.append(field_name) if not field_dict.get('type'): print('WARNING: {}.{} is of unknown type (class {})'.format( - resource_name, field.name, field_cls_name)) + resource_name, field.name, type(field))) continue description = getattr(field, 'help_text', None) if description: @@ -1263,7 +1264,7 @@ def _get_api_version_slug(version): def single_reference_field_dict(**kwargs): """Return an OpenAPI OrderedDict for a Django ForeingKey or OneToOneRel. """ - if kwargs.get('field_cls_name') == 'OneToOneRel': + if isinstance(kwargs['field'], OneToOneRel): return (kwargs['field'].get_accessor_name(), OrderedDict([('type', 'string'), ('format', 'uri')])) return (kwargs['field_name'], @@ -1275,7 +1276,7 @@ def multi_reference_field_dict(**kwargs): ManyToManyRel, or ManyToOneRel. """ field_name = kwargs.get('field_name') - if kwargs.get('field_cls_name') == 'ManyToOneRel': + if isinstance(kwargs['field'], ManyToOneRel): field_name = kwargs['field'].get_accessor_name() return field_name, OrderedDict([ ('type', 'array'), @@ -1287,12 +1288,12 @@ def scalar_field_dict(**kwargs): """Return an OpenAPI OrderedDict for a Django scalar field, e.g., a string or an int. """ - field_cls_name = kwargs.get('field_cls_name') - openapi_type = django_field_class2openapi_type.get( - field_cls_name) + field = kwargs.get('field') + openapi_type = django_field2openapi_type.get( + type(field)) field_dict = OrderedDict([('type', openapi_type)]) - openapi_format = django_field_class2openapi_format.get( - field_cls_name) + openapi_format = django_field2openapi_format.get( + type(field)) if openapi_format: field_dict['format'] = openapi_format return kwargs['field_name'], field_dict @@ -1309,8 +1310,8 @@ def get_default(field): return getattr(field, 'default', NOT_PROVIDED) -def get_required(field, default, field_cls_name): - if field_cls_name.endswith('Rel'): +def get_required(field, default): + if isinstance(field, (OneToOneRel, ManyToManyRel, ManyToOneRel)): return False field_blank = getattr(field, 'blank', False) if (not field_blank) and (default == NOT_PROVIDED): @@ -1318,20 +1319,19 @@ def get_required(field, default, field_cls_name): return False -def _get_format_from_valid_model_validator(valid_model_validator): - resource_name = valid_model_validator.model_cls.__name__.lower() - pk_attr = getattr(valid_model_validator, 'pk', 'uuid') - return '{} of a {} resource'.format(pk_attr, resource_name) +def _get_format_from_resource_uri_validator(resource_uri_validator): + resource_name = resource_uri_validator.model_cls.__name__.lower() + return 'URI of a {} resource'.format(resource_name) def single_reference_mut_field_dict(**kwargs): - format_ = _get_format_from_valid_model_validator(kwargs['field']) + format_ = _get_format_from_resource_uri_validator(kwargs['field']) return OrderedDict([('type', 'string'), ('format', format_)]) def multi_reference_mut_field_dict(**kwargs): - format_ = _get_format_from_valid_model_validator( + format_ = _get_format_from_resource_uri_validator( kwargs['field'].validators[0]) return OrderedDict([ ('type', 'array'), @@ -1355,12 +1355,11 @@ def disjunctive_field_dict(**kwargs): field_dict = OrderedDict([('anyOf', anyOf)]) for validator in kwargs['field'].validators: validator_dict = OrderedDict() - validator_cls = validator.__class__.__name__ - validator_dict['type'] = formencode_field_class2openapi_type.get( - validator_cls, 'string') + validator_dict['type'] = formencode_field2openapi_type.get( + type(validator), 'string') validator_format = ( - formencode_field_class2openapi_format.get( - validator_cls)) + formencode_field2openapi_format.get( + type(validator))) if validator_format: validator_dict['format'] = validator_format anyOf.append(validator_dict) @@ -1368,11 +1367,11 @@ def disjunctive_field_dict(**kwargs): def scalar_mut_field_dict(**kwargs): - openapi_type = formencode_field_class2openapi_type.get( - kwargs['field_cls_name']) + openapi_type = formencode_field2openapi_type.get( + type(kwargs['field'])) field_dict = OrderedDict([('type', openapi_type)]) - openapi_format = formencode_field_class2openapi_format.get( - kwargs['field_cls_name']) + openapi_format = formencode_field2openapi_format.get( + type(kwargs['field'])) if openapi_format: field_dict['format'] = openapi_format field = kwargs['field'] diff --git a/storage_service/locations/api/v3/remple/querybuilder.py b/storage_service/locations/api/v3/remple/querybuilder.py index 41a834304..5d37ae91a 100644 --- a/storage_service/locations/api/v3/remple/querybuilder.py +++ b/storage_service/locations/api/v3/remple/querybuilder.py @@ -79,7 +79,16 @@ import logging import operator +from django.db.models.fields.related import ( + ForeignKey, + ManyToManyRel, + ManyToManyField, + ManyToOneRel, + OneToOneRel, +) +from django.db.models import DateTimeField, DateField from django.db.models import Q +from django.utils.dateparse import parse_datetime from . import utils @@ -290,7 +299,7 @@ def _get_datetime_value(self, datetime_string): # None can be used on datetime comparisons so assume this is what # was intended return datetime_string - datetime_ = utils.datetime_string2datetime(datetime_string) + datetime_ = parse_datetime(datetime_string) if datetime_ is None: self._add_to_errors( 'datetime %s' % str(datetime_string), @@ -641,31 +650,32 @@ def schemata(self): model_clses = set([model_cls]) fields = model_cls._meta.get_fields() for field in fields: - field_cls_name = field.__class__.__name__ - if field_cls_name in ('ForeignKey', 'OneToOneRel', - 'ManyToManyField', 'ManyToManyRel', - 'ManyToOneRel',): + if isinstance(field, (ForeignKey, OneToOneRel, + ManyToManyField, ManyToManyRel, + ManyToOneRel)): model_clses.add(field.related_model) for model_cls in model_clses: model_schema = {} - model_cls_name = model_cls.__name__ fields = model_cls._meta.get_fields() for field in fields: - field_cls_name = field.__class__.__name__ field_name = field.name field_val = {} - if field_cls_name in ('ForeignKey', 'OneToOneRel'): - if field_cls_name == 'OneToOneRel': + if isinstance(field, DateTimeField): + field_val = {'value_converter': '_get_datetime_value'} + elif isinstance(field, DateField): + field_val = {'value_converter': '_get_date_value'} + elif isinstance(field, (ForeignKey, OneToOneRel)): + if isinstance(field, OneToOneRel): field_name = field.get_accessor_name() field_val = {'foreign_model': field.related_model.__name__, 'type': 'scalar'} - elif field_cls_name in ('ManyToManyField', 'ManyToManyRel', - 'ManyToOneRel',): - if field_cls_name == 'ManyToOneRel': + elif isinstance(field, (ManyToManyField, ManyToManyRel, + ManyToOneRel)): + if isinstance(field, ManyToOneRel): field_name = field.get_accessor_name() field_val = {'foreign_model': field.related_model.__name__, 'type': 'collection'} model_schema[field_name] = field_val - _schemata[model_cls_name] = model_schema + _schemata[model_cls.__name__] = model_schema self._schemata = _schemata return self._schemata diff --git a/storage_service/locations/api/v3/remple/resources.py b/storage_service/locations/api/v3/remple/resources.py index 5b84c7018..3f98455e6 100644 --- a/storage_service/locations/api/v3/remple/resources.py +++ b/storage_service/locations/api/v3/remple/resources.py @@ -15,8 +15,9 @@ import logging from django.db import OperationalError -from django.db.models.fields.related import ManyToManyField +from django.db.models.fields.related import ManyToManyField, ForeignKey from formencode.validators import Invalid, UnicodeString +from formencode.foreach import ForEach import inflect from .constants import ( @@ -24,12 +25,13 @@ FORBIDDEN_STATUS, JSONDecodeErrorResponse, NOT_FOUND_STATUS, + CREATED_STATUS, OK_STATUS, READONLY_RSLT, UNAUTHORIZED_MSG, ) from .querybuilder import QueryBuilder, SearchParseError -from .schemata import PaginatorSchema, ValidModelObject +from .schemata import PaginatorSchema, ResourceURI from .utils import normalize @@ -69,9 +71,10 @@ class ReadonlyResources(object): inflect_p = inflect.engine() inflect_p.classical() - def __init__(self, request, server_path='/api/0_1_0/'): + def __init__(self, request, server_path='/api/0_1_0/', other_resources=None): self.request = request self.server_path = server_path + self.other_resources = other_resources or [] self._logged_in_user = None self._query_builder = None # Names @@ -154,8 +157,7 @@ def index(self): headers_ctl = self._headers_control(result) if headers_ctl is not False: return headers_ctl - logger.info('Reading all %s', self.hmn_collection_name) - logger.info(result) + logger.info('Read all %s', self.hmn_collection_name) return result, OK_STATUS def show(self, pk): @@ -173,7 +175,7 @@ def show(self, pk): if self._model_access_unauth(resource_model) is not False: logger.warning(UNAUTHORIZED_MSG) return UNAUTHORIZED_MSG, FORBIDDEN_STATUS - logger.info('Reading a single %s', self.hmn_member_name) + logger.info('Read a single %s', self.hmn_member_name) return self._get_show_dict(resource_model), OK_STATUS def update(self, pk): @@ -389,6 +391,55 @@ def add_order_by(self, query_set, order_by_params, query_builder=None): inp_order_bys, primary_key=self.primary_key) return query_set.order_by(*order_by) + @staticmethod + def get_resource_uri(server_path, collection_name, primary_key): + return '{server_path}/{collection_name}/{primary_key}/'.format( + server_path=server_path, + collection_name=collection_name, + primary_key=primary_key) + + @staticmethod + def resource_uri2primary_key(resource_uri): + return filter(None, resource_uri.split('/'))[-1] + + def inst2rsrc_uri(self, related_instance): + related_primary_key = related_instance.pk + related_rsrc_name = related_instance.__class__.__name__.lower() + related_coll_name = self.inflect_p.plural(related_rsrc_name) + related_rsrc_cls = self.other_resources.get( + related_rsrc_name, {}).get('resource_cls') + if related_rsrc_cls: + related_primary_key = getattr( + related_instance, related_rsrc_cls.primary_key) + return self.get_resource_uri( + self.server_path, related_coll_name, + related_primary_key) + + def to_dict(self, instance): + opts = instance._meta + data = {'resource_uri': self.get_resource_uri( + self.server_path, self.collection_name, + getattr(instance, self.primary_key))} + for f in opts.concrete_fields + opts.many_to_many: + if isinstance(f, ManyToManyField): + if instance.pk is None: + data[f.name] = [] + else: + data[f.name] = [ + self.inst2rsrc_uri(related_instance) + for related_instance + in f.value_from_object(instance)] + elif isinstance(f, ForeignKey): + data[f.name] = f.value_from_object(instance) + val = None + related_instance = getattr(instance, f.name, None) + if related_instance: + val = self.inst2rsrc_uri(related_instance) + data[f.name] = val + else: + data[f.name] = f.value_from_object(instance) + return data + class Resources(ReadonlyResources): """Abstract base class for all (modifiable) resource views. RESTful @@ -425,11 +476,8 @@ def preprocess_user_data(self, validated_user_data, schema): schema_cls = schema.__class__ for field_name, field in schema_cls.fields.items(): value = validated_user_data[field_name] - field_cls_name = field.__class__.__name__ - if field_cls_name == 'ForEach' and isinstance( - field.validators[0], ValidModelObject): - # if value: - # processed_data[field_name] = value + if isinstance(field, ForEach) and isinstance( + field.validators[0], ResourceURI): processed_data[field_name] = value elif isinstance(field, UnicodeString): processed_data[field_name] = normalize(value) @@ -468,7 +516,7 @@ def create(self): resource.save() self._post_create(resource) logger.info('Created a new %s.', self.hmn_member_name) - return self._get_create_dict(resource), OK_STATUS + return self._get_create_dict(resource), CREATED_STATUS def new(self): """Return the data necessary to create a new resource. @@ -644,13 +692,19 @@ def _create_new_resource(self, validated_user_data, schema): if isinstance(self.model_cls._meta.get_field(attr), ManyToManyField)} ret = self.model_cls(**kwargs) + ret.save() for attr, vals in m2m.items(): - try: - getattr(ret, attr).clear() - except ValueError: - pass - for val in vals: - getattr(ret, attr).add(val) + existing_val = getattr(ret, attr) + through = getattr(existing_val, 'through', None) + if through and (not through._meta.auto_created): + this_attr = [f for f in through._meta.get_fields() + if isinstance(f, ForeignKey)][0].name + for rltd_mdl in vals: + through.objects.get_or_create( + **{attr: rltd_mdl, this_attr: ret}) + else: + for val in vals: + existing_val.add(val) return ret def _post_create(self, resource_model): @@ -695,13 +749,10 @@ def _update_resource_model(self, resource_model, validated_user_data, for attr, user_val in self.preprocess_user_data( validated_user_data, schema).items(): existing_val = getattr(resource_model, attr) - existing_val_cls_name = existing_val.__class__.__name__ through = getattr(existing_val, 'through', None) - if (existing_val_cls_name == 'ManyRelatedManager' and - through and - (not through._meta.auto_created)): + if through and (not through._meta.auto_created): this_attr = [f for f in through._meta.get_fields() - if f.__class__.__name__ == 'ForeignKey'][0].name + if isinstance(f, ForeignKey)][0].name for rltd_mdl in user_val: through.objects.get_or_create( **{attr: rltd_mdl, this_attr: resource_model}) @@ -720,9 +771,8 @@ def _distinct(self, attr, resource_model, new_val): have a special definition of "distinct". """ field = resource_model.__class__._meta.get_field(attr) - field_cls_name = field.__class__.__name__ existing_val = getattr(resource_model, attr) - if field_cls_name == 'ManyToManyField': + if isinstance(field, ManyToManyField): new_val = sorted(m.pk for m in new_val) existing_val = sorted(m.pk for m in existing_val.all()) field = resource_model.__class__._meta.get_field(attr) @@ -757,12 +807,11 @@ def _get_new_edit_data(self, get_params, mode='new'): result[collection] = getter() return result - @staticmethod - def _get_related_model_getter(field): + def _get_related_model_getter(self, field): related_model_cls = field.model_cls def getter(model_cls): - return [mi.uuid for mi in model_cls.objects.all()] + return [self.inst2rsrc_uri(mi) for mi in model_cls.objects.all()] return partial(getter, related_model_cls) @@ -771,51 +820,32 @@ def getter(field): return [c[0] for c in field.list] return partial(getter, field) - @classmethod - def _django_model_class_to_plural(cls, model_cls): - return cls.inflect_p.plural(model_cls.__name__.lower()) + def _django_model_class_to_plural(self, model_cls): + return self.inflect_p.plural(model_cls.__name__.lower()) - @classmethod - def _get_new_edit_collections(cls, mode='new'): + def _get_new_edit_collections(self, mode='new'): """Return a dict from collection names (e.g., "users" or "purpose") to getter functions that will return all instances of that collection, be they Django models or simple strings. This dict is constructed by - introspecting both ``cls.model_cls`` and ``cls.schema_cls``. + introspecting both ``self.model_cls`` and ``self.schema_cls``. """ collections = {} if mode == 'new': - schema_cls = cls.get_create_schema_cls() + schema_cls = self.get_create_schema_cls() else: - schema_cls = cls.get_update_schema_cls() + schema_cls = self.get_update_schema_cls() for field_name, field in schema_cls.fields.items(): - field_cls_name = field.__class__.__name__ - if field_cls_name == 'ValidModelObject': - key = cls._django_model_class_to_plural(field.model_cls) - collections[key] = cls._get_related_model_getter(field) - elif field_cls_name == 'ForEach': + if isinstance(field, ResourceURI): + key = self._django_model_class_to_plural(field.model_cls) + collections[key] = self._get_related_model_getter(field) + elif isinstance(field, ForEach): first_validator = field.validators[0] - field_cls_name = first_validator.__class__.__name__ - if field_cls_name == 'ValidModelObject': - key = cls._django_model_class_to_plural( + if isinstance(first_validator, ResourceURI): + key = self._django_model_class_to_plural( first_validator.model_cls) - collections[key] = cls._get_related_model_getter(first_validator) + collections[key] = self._get_related_model_getter(first_validator) return collections - def to_dict(self, instance): - opts = instance._meta - data = {'resource_uri': '{}/{}/{}/'.format( - self.server_path, self.collection_name, instance.uuid)} - for f in opts.concrete_fields + opts.many_to_many: - if isinstance(f, ManyToManyField): - if instance.pk is None: - data[f.name] = [] - else: - data[f.name] = list( - f.value_from_object(instance).values_list('uuid', flat=True)) - else: - data[f.name] = f.value_from_object(instance) - return data - class SchemaState(object): diff --git a/storage_service/locations/api/v3/remple/routebuilder.py b/storage_service/locations/api/v3/remple/routebuilder.py index 8840af6af..84afcd569 100644 --- a/storage_service/locations/api/v3/remple/routebuilder.py +++ b/storage_service/locations/api/v3/remple/routebuilder.py @@ -55,15 +55,11 @@ import string from django.conf.urls import url +from django.contrib.auth.models import User from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt import inflect -from tastypie.authentication import ( - BasicAuthentication, - ApiKeyAuthentication, - MultiAuthentication, - SessionAuthentication -) +from tastypie.models import ApiKey from .constants import ( METHOD_NOT_ALLOWED_STATUS, @@ -124,6 +120,24 @@ def register_route(self, route): config['http_methods'] = http_methods_config self.routes[route.regex] = config + def is_authenticated(self, request): + auth_header = request.META.get('Authorization') + if not auth_header: + return False + try: + username_key = auth_header.split()[-1] + username, key = username_key.split(':', 1) + except ValueError: + return False + try: + user = User.objects.get(username=username) + api_key = str(ApiKey.objects.get(user=user)).split()[0] + except (User.DoesNotExist, ApiKey.DoesNotExist): + return False + if key == api_key: + return True + return False + def get_urlpatterns(self): """Return ``urlpatterns_``, a list of Django ``url`` instances that cause the appropriate instance method to be called for a given request. @@ -150,12 +164,9 @@ def resource_callable(config, request, **kwargs): request.method, list(http_methods_config.keys())), status=METHOD_NOT_ALLOWED_STATUS) instance = resource_cls( - request, server_path=self._get_dflt_server_path()) - authentication = MultiAuthentication( - BasicAuthentication(), ApiKeyAuthentication(), - SessionAuthentication()) - auth_result = authentication.is_authenticated(request) - if auth_result is True: + request, server_path=self.get_dflt_server_path(), + other_resources=self.resources) + if self.is_authenticated(request): method = getattr(instance, method_name) response, status = method(**kwargs) else: @@ -180,18 +191,21 @@ def yield_standard_routes(self, rsrc_member_name, resource_cls): for action in self.RESOURCE_ACTIONS: method_name = action http_method = self.ACTIONS2METHODS.get(action, self.DEFAULT_METHOD) + api_v_slug = self.get_api_version_slug() if action in self.COLLECTION_TARGETING: - route_name = rsrc_collection_name + route_name = '{}_{}'.format(api_v_slug, rsrc_collection_name) regex = get_collection_targeting_regex(rsrc_collection_name) elif action in self.MEMBER_TARGETING: - route_name = rsrc_member_name + route_name = '{}_{}'.format(api_v_slug, rsrc_member_name) regex = get_member_targeting_regex(rsrc_collection_name, pk_patt) elif action == 'new': - route_name = '{}_new'.format(rsrc_collection_name) + route_name = '{}_{}_new'.format( + api_v_slug, rsrc_collection_name) regex = get_collection_targeting_regex( rsrc_collection_name, modifiers=['new']) else: # edit is default case - route_name = '{}_edit'.format(rsrc_member_name) + route_name = '{}_{}_edit'.format( + api_v_slug, rsrc_member_name) regex = get_member_targeting_regex( rsrc_collection_name, pk_patt, modifiers=['edit']) yield Route(name=route_name, @@ -222,24 +236,24 @@ def register_resources(self, resources_): for rsrc_member_name, rsrc_config in resources_.items(): self.register_routes_for_resource(rsrc_member_name, rsrc_config) - @staticmethod - def yield_search_routes(rsrc_member_name, resource_cls): + def yield_search_routes(self, rsrc_member_name, resource_cls): """Yield the ``Route()``s needed to configure search across the resource with member name ``rsrc_member_name``. """ rsrc_collection_name = inflp.plural(rsrc_member_name) - yield Route(name=rsrc_collection_name, + api_v_slug = self.get_api_version_slug() + yield Route(name='{}_{}'.format(api_v_slug, rsrc_collection_name), regex=get_collection_targeting_regex(rsrc_collection_name), http_method='SEARCH', resource_cls=resource_cls, method_name='search') - yield Route(name='{}_search'.format(rsrc_collection_name), + yield Route(name='{}_{}_search'.format(api_v_slug, rsrc_collection_name), regex=get_collection_targeting_regex( rsrc_collection_name, modifiers=['search']), http_method='POST', resource_cls=resource_cls, method_name='search') - yield Route(name='{}_new_search'.format(rsrc_collection_name), + yield Route(name='{}_{}_new_search'.format(api_v_slug, rsrc_collection_name), regex=get_collection_targeting_regex( rsrc_collection_name, modifiers=['new_search']), http_method='GET', diff --git a/storage_service/locations/api/v3/remple/schemata.py b/storage_service/locations/api/v3/remple/schemata.py index 6bfb0a532..1d63a922e 100644 --- a/storage_service/locations/api/v3/remple/schemata.py +++ b/storage_service/locations/api/v3/remple/schemata.py @@ -4,7 +4,7 @@ from formencode.schema import Schema from formencode.validators import Int, FancyValidator, Regex, Invalid -from .constants import formencode_field_class2openapi_type +from .constants import formencode_field2openapi_type class NotUsed(Exception): @@ -31,8 +31,8 @@ def extract_parameters(self): parameter['name'] = parameter_name parameter['required'] = config.get( 'required', formencode_cls.not_empty) - schema['type'] = formencode_field_class2openapi_type.get( - formencode_cls.__class__.__name__, 'string') + schema['type'] = formencode_field2openapi_type.get( + type(formencode_cls), 'string') minimum = formencode_cls.min if minimum is not None: schema['minimum'] = minimum @@ -82,32 +82,33 @@ def camel_case2lower_space(name): return re.sub('([a-z0-9])([A-Z])', r'\1 \2', s1).lower() -class ValidModelObject(FancyValidator): +class ResourceURI(FancyValidator): """Validator for input values that are primary keys of model objects. Value must be the pk of an existing model of the type specified in the ``model_cls`` kwarg. If valid, the model object is returned. Example - usage: ValidModelObject(model_cls=models.Package). + usage: ResourceURI(model_cls=models.Package). """ messages = { 'invalid_model': - 'There is no %(model_name_eng)s with pk %(pk)s.' + 'There is no %(model_name_eng)s with pk %(id)s.' } def _convert_to_python(self, value, state): - if value in ['', None]: + if value in ('', None): return None else: + pk = filter(None, value.split('/'))[-1] pk_validator = getattr(self, 'pk_validator', UUID) - pk = pk_validator().to_python(value, state) + pk = pk_validator().to_python(pk, state) pk_attr = getattr(self, 'pk', 'uuid') model_cls = self.model_cls try: model_object = model_cls.objects.get( - **{pk_attr: value}) + **{pk_attr: pk}) except model_cls.DoesNotExist: model_name_eng = camel_case2lower_space( - self.model_cls.__class__.__name__) + self.model_cls.__name__) raise Invalid( self.message('invalid_model', state, id=pk, model_name_eng=model_name_eng), @@ -116,4 +117,4 @@ def _convert_to_python(self, value, state): return model_object -__all__ = ('schemata', 'PaginatorSchema', 'ValidModelObject') +__all__ = ('schemata', 'PaginatorSchema', 'ResourceURI') diff --git a/storage_service/locations/api/v3/remple/utils.py b/storage_service/locations/api/v3/remple/utils.py index b5afc593a..13760ca2d 100644 --- a/storage_service/locations/api/v3/remple/utils.py +++ b/storage_service/locations/api/v3/remple/utils.py @@ -28,9 +28,9 @@ def datetime_string2datetime(datetime_string): """ try: parts = datetime_string.split('.') - years_to_seconds_string = parts[0] + years_to_seconds_string = parts[0] + ' +0000' datetime_object = datetime.datetime.strptime( - years_to_seconds_string, "%Y-%m-%dT%H:%M:%S") + years_to_seconds_string, "%Y-%m-%dT%H:%M:%S %z") except ValueError: return None try: diff --git a/storage_service/locations/api/v3/resources.py b/storage_service/locations/api/v3/resources.py index 52e6d0d14..eb9d42bc2 100644 --- a/storage_service/locations/api/v3/resources.py +++ b/storage_service/locations/api/v3/resources.py @@ -13,11 +13,12 @@ from locations.api.v3.remple import Resources, ReadonlyResources from locations.api.v3.schemata import ( LocationSchema, + PipelineSchema, SpaceCreateSchema, SpaceUpdateSchema, - PipelineSchema, ) from locations.models import ( + File, Location, Package, Space, @@ -27,6 +28,15 @@ logger = logging.getLogger(__name__) +class Files(ReadonlyResources): + model_cls = File + + +class Locations(Resources): + model_cls = Location + schema_cls = LocationSchema + + class Packages(ReadonlyResources): """TODO: Packages should not be creatable or editable via the REST API. However, the user should be able to delete them via the API or at least @@ -35,11 +45,6 @@ class Packages(ReadonlyResources): model_cls = Package -class Locations(Resources): - model_cls = Location - schema_cls = LocationSchema - - class Pipelines(Resources): model_cls = Pipeline schema_cls = PipelineSchema diff --git a/storage_service/locations/api/v3/schemata.py b/storage_service/locations/api/v3/schemata.py index b29f41e50..0a549eeb9 100644 --- a/storage_service/locations/api/v3/schemata.py +++ b/storage_service/locations/api/v3/schemata.py @@ -14,7 +14,7 @@ ) from locations import models -from locations.api.v3.remple import ValidModelObject +from locations.api.v3.remple import ResourceURI logger = logging.getLogger(__name__) @@ -25,9 +25,6 @@ def _flatten(choices): class PipelineSchema(Schema): - allow_extra_fields = True - filter_extra_fields = True - api_key = UnicodeString(max=256) api_username = UnicodeString(max=256) description = UnicodeString(max=256) @@ -36,53 +33,42 @@ class PipelineSchema(Schema): class SpaceUpdateSchema(Schema): - allow_extra_fields = True - filter_extra_fields = True - size = Int(min=0) path = UnicodeString(max=256) staging_path = UnicodeString(max=256) class SpaceCreateSchema(SpaceUpdateSchema): - allow_extra_fields = True - filter_extra_fields = True - access_protocol = OneOf( _flatten(models.Space.ACCESS_PROTOCOL_CHOICES)) class LocationSchema(Schema): - allow_extra_fields = True - filter_extra_fields = True - description = UnicodeString(max=256) purpose = OneOf(_flatten(models.Location.PURPOSE_CHOICES)) relative_path = UnicodeString() quota = Int(min=0) enabled = Bool() - space = ValidModelObject(model_cls=models.Space) - pipeline = ForEach(ValidModelObject(model_cls=models.Pipeline)) - replicators = ForEach(ValidModelObject(model_cls=models.Location)) + space = ResourceURI(model_cls=models.Space) + pipeline = ForEach(ResourceURI(model_cls=models.Pipeline)) + replicators = ForEach(ResourceURI(model_cls=models.Location)) # Note: it does not make sense to have a schema for the package resource since # it is not truly mutable via an external API. I am leaving this for now in # case it contains useful information in the future. class PackageSchema(Schema): - allow_extra_fields = True - filter_extra_fields = True - current_location = ValidModelObject(model_cls=models.Location) + current_location = ResourceURI(model_cls=models.Location) current_path = UnicodeString() description = UnicodeString(max=256) encryption_key_fingerprint = UnicodeString(max=512) misc_attributes = UnicodeString() - origin_pipeline = ValidModelObject(model_cls=models.Pipeline) + origin_pipeline = ResourceURI(model_cls=models.Pipeline) package_type = OneOf( _flatten(models.Package.PACKAGE_TYPE_CHOICES)) - pointer_file_location = ValidModelObject(model_cls=models.Location) + pointer_file_location = ResourceURI(model_cls=models.Location) pointer_file_path = UnicodeString() - related_packages = ForEach(ValidModelObject(model_cls=models.Package)) - replicated_package = ValidModelObject(model_cls=models.Package) + related_packages = ForEach(ResourceURI(model_cls=models.Package)) + replicated_package = ResourceURI(model_cls=models.Package) size = Int(min=0) status = OneOf(_flatten(models.Package.STATUS_CHOICES)) diff --git a/storage_service/locations/fixtures/files.json b/storage_service/locations/fixtures/files.json new file mode 100644 index 000000000..06a3f7c10 --- /dev/null +++ b/storage_service/locations/fixtures/files.json @@ -0,0 +1,65 @@ +[ +{ + "pk": 3, + "model": "locations.file", + "fields": { + "uuid": "aad59769-0c6b-48cd-b54a-63092b9718fc", + "package": 3, + "name": "test_sip/objects/file3.pdf", + "source_id": "aa24a977-ad7a-4886-b17c-8b32ab4a7955", + "source_package": "a59033c2-7fa7-41e2-9209-136f07174692", + "checksum": "", + "stored": false, + "accessionid": "", + "origin": "91d13621-d2c1-4c70-a67e-77e96dced036", + "ingestion_time": "2015-12-15T03:00:05.020871+00:00", + "size": 512, + "format_name": "Acrobat PDF 1.5 - Portable Document Format", + "pronom_id": "fmt/19", + "normalized": true, + "valid": true + } +}, +{ + "pk": 4, + "model": "locations.file", + "fields": { + "uuid": "bbd59769-0c6b-48cd-b54a-63092b9718fc", + "package": 7, + "name": "test_sip/objects/file3.pdf", + "source_id": "bb24a977-ad7a-4886-b17c-8b32ab4a7955", + "source_package": "a59033c2-7fa7-41e2-9209-136f07174692", + "checksum": "", + "stored": false, + "accessionid": "", + "origin": "91d13621-d2c1-4c70-a67e-77e96dced036", + "ingestion_time": "2015-12-16T03:00:05.020871+00:00", + "size": 512, + "format_name": "Acrobat PDF 1.5 - Portable Document Format", + "pronom_id": "fmt/19", + "normalized": true, + "valid": true + } +}, +{ + "pk": 5, + "model": "locations.file", + "fields": { + "uuid": "ccd59769-0c6b-48cd-b54a-63092b9718fc", + "package": 7, + "name": "test_sip/objects/file3.pdf", + "source_id": "cc24a977-ad7a-4886-b17c-8b32ab4a7955", + "source_package": "a59033c2-7fa7-41e2-9209-136f07174692", + "checksum": "", + "stored": false, + "accessionid": "", + "origin": "91d13621-d2c1-4c70-a67e-77e96dced036", + "ingestion_time": "2015-12-17T03:00:05.020871+00:00", + "size": 512, + "format_name": "Acrobat PDF 1.5 - Portable Document Format", + "pronom_id": "fmt/19", + "normalized": true, + "valid": true + } +} +] diff --git a/storage_service/locations/fixtures/package.json b/storage_service/locations/fixtures/package.json index c01ddff29..982e9a073 100644 --- a/storage_service/locations/fixtures/package.json +++ b/storage_service/locations/fixtures/package.json @@ -144,7 +144,13 @@ "checksum": "", "stored": false, "accessionid": "", - "origin": "bd17e3cf-afb6-4067-b7d0-472482767ee2" + "origin": "bd17e3cf-afb6-4067-b7d0-472482767ee2", + "ingestion_time": "2016-12-15T03:00:05.020871Z", + "size": 256, + "format_name": "Plain Text File", + "pronom_id": "x-fmt/111", + "normalized": true, + "valid": true } }, { @@ -159,7 +165,13 @@ "checksum": "", "stored": false, "accessionid": "", - "origin": "91d13621-d2c1-4c70-a67e-77e96dced036" + "origin": "91d13621-d2c1-4c70-a67e-77e96dced036", + "ingestion_time": "2015-12-15T03:00:05.020871Z", + "size": 512, + "format_name": "AutoCAD External Database Configuration File", + "pronom_id": "x-fmt/112", + "normalized": false, + "valid": false } } ] diff --git a/storage_service/locations/migrations/0019_add_fields_to_file.py b/storage_service/locations/migrations/0019_add_fields_to_file.py new file mode 100644 index 000000000..67eb84ce3 --- /dev/null +++ b/storage_service/locations/migrations/0019_add_fields_to_file.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('locations', '0018_create_async_table'), + ] + + operations = [ + migrations.AddField( + model_name='file', + name='format_name', + field=models.TextField(max_length=128, blank=True), + ), + migrations.AddField( + model_name='file', + name='ingestion_time', + field=models.DateTimeField(null=True), + ), + migrations.AddField( + model_name='file', + name='normalized', + field=models.BooleanField( + default=False, + help_text=b'Whether or not file has been normalized'), + ), + migrations.AddField( + model_name='file', + name='pronom_id', + field=models.TextField(max_length=128, blank=True), + ), + migrations.AddField( + model_name='file', + name='size', + field=models.IntegerField( + default=0, + help_text=b'Size in bytes of the file'), + ), + migrations.AddField( + model_name='file', + name='valid', + field=models.NullBooleanField( + default=None, + help_text=b'Indicates whether validation has occurred and, if' + ' so, whether or not the file was assessed as valid'), + ), + migrations.AlterField( + model_name='location', + name='pipeline', + field=models.ManyToManyField( + help_text='The Archivematica instance using this location.', + to='locations.Pipeline', verbose_name='Pipeline', + through='locations.LocationPipeline', blank=True), + ), + ] diff --git a/storage_service/locations/models/event.py b/storage_service/locations/models/event.py index 1f105cad1..4961a9685 100644 --- a/storage_service/locations/models/event.py +++ b/storage_service/locations/models/event.py @@ -135,9 +135,15 @@ class File(models.Model): help_text=_l("Unique identifier")) package = models.ForeignKey('Package', null=True) name = models.TextField(max_length=1000) + ingestion_time = models.DateTimeField(null=True) + source_id = models.TextField(max_length=128) source_package = models.TextField(blank=True, help_text=_l("Unique identifier of originating unit")) + size = models.IntegerField( + default=0, help_text=_l("Size in bytes of the file")) + format_name = models.TextField(blank=True, max_length=128) + pronom_id = models.TextField(blank=True, max_length=128) # Sized to fit sha512 checksum = models.TextField(max_length=128) stored = models.BooleanField(default=False) @@ -145,6 +151,11 @@ class File(models.Model): help_text=_l("Accession ID of originating transfer")) origin = UUIDField(editable=False, unique=False, version=4, blank=True, help_text=_l("Unique identifier of originating Archivematica dashboard")) + normalized = models.BooleanField(blank=False, default=False, + help_text="Whether or not file has been normalized") + valid = models.NullBooleanField(default=None, null=True, + help_text="Indicates whether validation has occurred and, if so," + " whether or not the file was assessed as valid") class Meta: verbose_name = _l("File") diff --git a/storage_service/locations/models/location.py b/storage_service/locations/models/location.py index a2f1d5315..53f5f3692 100644 --- a/storage_service/locations/models/location.py +++ b/storage_service/locations/models/location.py @@ -60,7 +60,7 @@ class Location(models.Model): pipeline = models.ManyToManyField('Pipeline', through='LocationPipeline', blank=True, verbose_name=_l('Pipeline'), - help_text=_l("UUID of the Archivematica instance using this location.")) + help_text=_l("The Archivematica instance using this location.")) relative_path = models.TextField( verbose_name=_l('Relative Path'), diff --git a/storage_service/locations/tests/test_api_v3.py b/storage_service/locations/tests/test_api_v3.py new file mode 100644 index 000000000..775b9f2f4 --- /dev/null +++ b/storage_service/locations/tests/test_api_v3.py @@ -0,0 +1,407 @@ +import json +import os +from uuid import uuid4 + +from django.contrib.auth.models import User +from django.test import TestCase +from django.utils.dateparse import parse_datetime +from tastypie.models import ApiKey + +from locations import models +from locations.api.v3 import api +from locations.api.v3.remple import Resources + +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) +FIXTURES_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', 'fixtures', '')) + + +SERVER_PATH = api.get_dflt_server_path() +API_PATH_PREFIX = '/api/v3/' + + +class TestV3FileAPI(TestCase): + + fixtures = ['base.json', 'pipelines.json', 'package.json', 'files.json'] + + def setUp(self): + user = User.objects.get(username='test') + api_key = str(ApiKey.objects.get(user=user)).split()[0] + self.client.defaults['Authorization'] = 'ApiKey test:{}'.format(api_key) + + def test_auth(self): + original_auth = self.client.defaults['Authorization'] + response = self.client.get('{}files/'.format(API_PATH_PREFIX), + content_type='application/json') + assert response.status_code == 200 + self.client.defaults['Authorization'] = 'monkeys' + response = self.client.get('{}files/'.format(API_PATH_PREFIX), + content_type='application/json') + assert response.status_code == 403 + self.client.defaults['Authorization'] = original_auth + + def test_get_many_files(self): + + known_files = {f.uuid: f for f in models.File.objects.all()} + assert known_files + known_file_count = len(known_files) + response = self.client.get('{}files/'.format(API_PATH_PREFIX), + content_type='application/json') + assert response.status_code == 200 + fetched_files = json.loads(response.content) + assert fetched_files['paginator']['count'] == known_file_count + fetched_files = {f['uuid']: f for f in fetched_files['items']} + for file_uuid, file_dict in fetched_files.items(): + file_instance = known_files[file_uuid] + for attr in ('accessionid', + 'checksum', + 'id', + 'name', + 'origin', + 'source_id', + 'source_package', + 'stored', + 'uuid', + 'size', + 'format_name', + 'pronom_id', + 'normalized', + 'valid',): + assert file_dict[attr] == getattr(file_instance, attr) + assert file_dict['resource_uri'] == Resources.get_resource_uri( + SERVER_PATH, 'files', file_uuid) + if file_instance.package: + assert file_dict['package'] == Resources.get_resource_uri( + SERVER_PATH, 'packages', file_instance.package.uuid) + + def test_files_search(self): + """Test searching over file resources.""" + + # Search for files with PRONOM id x-fmt/111. + known_files = {f.uuid: f for f in models.File.objects.all()} + known_matches = [f for f in known_files.values() + if f.pronom_id == 'x-fmt/111'] + query = {'query': {'filter': ['pronom_id', '=', 'x-fmt/111']}} + response = self.client.post('{}files/search/'.format(API_PATH_PREFIX), + json.dumps(query), + content_type='application/json') + assert response.status_code == 200 + response = json.loads(response.content) + assert sorted([f['uuid'] for f in response['items']]) == sorted( + [f.uuid for f in known_matches]) + + # Count the number of files with PRONOM id fmt/19 that were ingested + # between 2015-12-16 and 2015-12-17. Use ISO timezones in search terms. + fmt = 'fmt/19' + max_dt_iso = '2015-12-17T11:59:59+00:00' + min_dt_iso = '2015-12-16T00:00:00+00:00' + max_dt = parse_datetime(max_dt_iso) + min_dt = parse_datetime(min_dt_iso) + known_matches = models.File.objects\ + .filter(pronom_id__exact=fmt)\ + .filter(ingestion_time__lte=max_dt)\ + .filter(ingestion_time__gte=min_dt) + assert len(known_matches) == 2 + query = {'query': {'filter': [ + 'and', [['pronom_id', '=', fmt], + ['ingestion_time', '<=', max_dt_iso], + ['ingestion_time', '>=', min_dt_iso]]]}} + response = self.client.post('{}files/search/'.format(API_PATH_PREFIX), + json.dumps(query), + content_type='application/json') + assert response.status_code == 200 + response = json.loads(response.content) + assert response['paginator']['count'] == 2 + assert sorted([f['uuid'] for f in response['items']]) == sorted( + [f.uuid for f in known_matches]) + + # Count the number of files with PRONOM id fmt/19 that were ingested + # between 2015-12-16 and 2015-12-17. Use 'Z' for UTC timezone. + max_dt_iso = '2015-12-17T11:59:59Z' + min_dt_iso = '2015-12-16T00:00:00Z' + max_dt = parse_datetime(max_dt_iso) + min_dt = parse_datetime(min_dt_iso) + query = {'query': {'filter': [ + 'and', [['pronom_id', '=', fmt], + ['ingestion_time', '<=', max_dt_iso], + ['ingestion_time', '>=', min_dt_iso]]]}} + response = self.client.post('{}files/search/'.format(API_PATH_PREFIX), + json.dumps(query), + content_type='application/json') + assert response.status_code == 200 + response = json.loads(response.content) + assert response['paginator']['count'] == 2 + assert sorted([f['uuid'] for f in response['items']]) == sorted( + [f.uuid for f in known_matches]) + + # Search files based on the type of the package that they belong to: + # relational search. + files_in_aips = models.File.objects.filter(package__package_type='AIP') + query = {'query': {'filter': ['package', 'package_type', '=', 'AIP']}} + response = self.client.post('{}files/search/'.format(API_PATH_PREFIX), + json.dumps(query), + content_type='application/json') + assert response.status_code == 200 + response = json.loads(response.content) + assert response['paginator']['count'] == len(files_in_aips) + assert sorted([f['uuid'] for f in response['items']]) == sorted( + [f.uuid for f in files_in_aips]) + + def test_mutate_location(self): + """Test creation, updating and deletion of a location.""" + + # 1. Create a new location + existing_locations = models.Location.objects.all() + response = self.client.get( + '{}locations/'.format(API_PATH_PREFIX), content_type='application/json') + assert response.status_code == 200 + fetched_locations = json.loads(response.content) + assert sorted(l.uuid for l in existing_locations) == sorted( + l['uuid'] for l in fetched_locations['items']) + first_pipeline = models.Pipeline.objects.first() + pipeline_uri = Resources.get_resource_uri( + SERVER_PATH, 'pipelines', first_pipeline.uuid) + first_space = models.Space.objects.first() + space_uri = Resources.get_resource_uri( + SERVER_PATH, 'spaces', first_space.uuid) + new_loc_descr = 'My new location' + new_loc_purp = 'AS' + new_loc_rel_path = ( + 'var/archivematica/sharedDirectory/www/MyNewAIPsStore') + new_location = { + 'description': new_loc_descr, + 'enabled': True, + 'pipeline': [pipeline_uri], # list of AM pipeline URIs + 'purpose': new_loc_purp, + 'quota': None, + 'relative_path': new_loc_rel_path, + 'replicators': [], + 'space': space_uri # URI of a Space + } + response = self.client.post('{}locations/'.format(API_PATH_PREFIX), + json.dumps(new_location), + content_type='application/json') + assert response.status_code == 201 + new_location = json.loads(response.content) + assert new_location['description'] == new_loc_descr + assert new_location['purpose'] == new_loc_purp + assert new_location['relative_path'] == new_loc_rel_path + assert new_location['replicators'] == [] + for thing in new_location['pipeline']: + assert_is_resource_uri(thing, 'pipelines') + new_loc_uri = new_location['resource_uri'] + assert_is_resource_uri(new_loc_uri, 'locations') + assert_is_resource_uri(new_location['space'], 'spaces') + + # 2.a. Update the location. + updated_loc_descr = 'My new awesome transfer source location' + updated_loc_purp = 'TS' + updated_loc_rel_path = 'home' + updated_location = { + 'description': updated_loc_descr, + 'enabled': True, + 'pipeline': [pipeline_uri], + 'purpose': updated_loc_purp, + 'quota': None, + 'relative_path': updated_loc_rel_path, + 'replicators': [], + 'space': space_uri + } + response = self.client.put(new_loc_uri, + json.dumps(updated_location), + content_type='application/json') + assert response.status_code == 200 + updated_location = json.loads(response.content) + assert updated_location['description'] == updated_loc_descr + assert updated_location['purpose'] == updated_loc_purp + assert updated_location['relative_path'] == updated_loc_rel_path + assert updated_location['replicators'] == [] + assert updated_location['resource_uri'] == new_loc_uri + for thing in updated_location['pipeline']: + assert_is_resource_uri(thing, 'pipelines') + assert_is_resource_uri(updated_location['resource_uri'], 'locations') + assert_is_resource_uri(updated_location['space'], 'spaces') + + # 2.b. Invalid update attempt + bad_loc_purp = 'QQ' + bad_space_uuid = str(uuid4()) + bad_space_uri = Resources.get_resource_uri( + SERVER_PATH, 'spaces', bad_space_uuid) + bad_updated_location = { + 'description': updated_loc_descr, + 'enabled': True, + 'pipeline': [pipeline_uri], + 'purpose': bad_loc_purp, + 'quota': None, + 'relative_path': updated_loc_rel_path, + 'replicators': [], + 'space': bad_space_uri + } + bad_update_resp = self.client.put(new_loc_uri, + json.dumps(bad_updated_location), + content_type='application/json') + assert bad_update_resp.status_code == 400 + bad_update_resp = json.loads(bad_update_resp.content) + assert bad_update_resp['error']['purpose'].startswith( + 'Value must be one of: ') + assert bad_update_resp['error']['space'] == ( + 'There is no space with pk {}.'.format(bad_space_uuid)) + + # 3. Delete the location + response = self.client.delete( + new_loc_uri, content_type='application/json') + deleted_location = json.loads(response.content) + assert response.status_code == 200 + assert deleted_location == updated_location + response = self.client.get( + updated_location['resource_uri'], + content_type='application/json') + assert response.status_code == 404 + nonexistent_location = json.loads(response.content) + assert nonexistent_location['error'].startswith( + 'There is no location with uuid ') + + def test_mutate_space(self): + """Test creation, updating and deletion of a space. + + Space is somewhat special in that its access protocol should be + immutable after creation. + """ + + # 1. Create a new space + existing_spaces = models.Space.objects.all() + response = self.client.get( + '{}spaces/'.format(API_PATH_PREFIX), content_type='application/json') + assert response.status_code == 200 + fetched_spaces = json.loads(response.content) + assert sorted(l.uuid for l in existing_spaces) == sorted( + l['uuid'] for l in fetched_spaces['items']) + new_space_acc_prot = 'FS' + new_space_path = '/' + new_space_staging_path = '/var/archivematica/storage_service' + new_space = { + 'access_protocol': new_space_acc_prot, + 'path': new_space_path, + 'staging_path': new_space_staging_path, + 'size': None, + } + resp = self.client.post('{}spaces/'.format(API_PATH_PREFIX), + json.dumps(new_space), + content_type='application/json') + assert resp.status_code == 201 + new_space = json.loads(resp.content) + assert new_space['access_protocol'] == new_space_acc_prot + assert new_space['path'] == new_space_path + assert new_space['staging_path'] == new_space_staging_path + new_space_uri = new_space['resource_uri'] + assert_is_resource_uri(new_space_uri, 'spaces') + + # 2.a. Update the space + updated_space_path = '/abc' + updated_space = { + 'path': updated_space_path, + 'staging_path': new_space_staging_path, + 'size': None, + } + response = self.client.put(new_space_uri, + json.dumps(updated_space), + content_type='application/json') + assert response.status_code == 200 + updated_space = json.loads(response.content) + assert updated_space['access_protocol'] == new_space_acc_prot + assert updated_space['path'] == updated_space_path + assert updated_space['staging_path'] == new_space_staging_path + + # 2.b. Can't update a space's access protocol + updated_space = { + 'access_protocol': 'GPG', # This is BAD + 'path': updated_space_path, + 'staging_path': new_space_staging_path, + 'size': 100, + } + resp = self.client.put(new_space_uri, + json.dumps(updated_space), + content_type='application/json') + assert resp.status_code == 400 + resp = json.loads(resp.content) + assert resp['error'] == ( + 'The input field u\'access_protocol\' was not expected.') + + def test_get_create_update_data(self): + """Test that the GET //new/ and ///edit/ requests + return the data needed to create new and edit existing resources. + """ + + # GET locations/new/ should return a dict containing resource URIs for + # all locations, pipelines and spaces + response = self.client.get('{}locations/new/'.format(API_PATH_PREFIX), + content_type='application/json') + create_data = json.loads(response.content) + assert sorted(create_data.keys()) == sorted( + ['locations', 'pipelines', 'spaces']) + for resource_coll_name, value_list in create_data.items(): + for element in value_list: + assert_is_resource_uri(element, resource_coll_name) + + # GET locations//edit/ should return a dict containing resource + # URIs for all locations, pipelines and spaces + aloc = models.Location.objects.first() + response = self.client.get( + '{}locations/{}/edit/'.format(API_PATH_PREFIX, aloc.uuid), + content_type='application/json') + edit_data = json.loads(response.content) + assert edit_data['resource']['uuid'] == aloc.uuid + assert sorted(edit_data['data'].keys()) == sorted( + ['locations', 'pipelines', 'spaces']) + for resource_coll_name, value_list in edit_data['data'].items(): + for element in value_list: + assert_is_resource_uri(element, resource_coll_name) + + def test_new_search(self): + """Test that the GET //new_search/ request return the data needed + to perform a new search. + """ + response = self.client.get( + '{}locations/new_search/'.format(API_PATH_PREFIX), + content_type='application/json') + search_data = json.loads(response.content) + search_params = search_data['search_parameters'] + assert 'attributes' in search_params + assert 'relations' in search_params + assert search_params['attributes']['pipeline'][ + 'foreign_model'] == 'Pipeline' + assert search_params['attributes']['pipeline'][ + 'type'] == 'collection' + assert search_params['attributes']['space'][ + 'foreign_model'] == 'Space' + assert search_params['attributes']['space'][ + 'type'] == 'scalar' + assert search_params['attributes']['quota'] == {} + assert '=' in search_params['relations'] + assert 'regex' in search_params['relations'] + assert 'regexp' in search_params['relations'] + assert 'like' in search_params['relations'] + assert 'contains' in search_params['relations'] + assert '<=' in search_params['relations'] + + def test_read_only_resources(self): + for rsrc_coll in ('files', 'packages'): + response = self.client.post( + '{}{}/'.format(API_PATH_PREFIX, rsrc_coll), + json.dumps({'foo': 'bar'}), + content_type='application/json') + payload = json.loads(response.content) + assert response.status_code == 404 + assert payload['error'] == 'This resource is read-only.' + + +def assert_is_resource_uri(string, resource): + _, _, xtrctd_rsrc, xtrctd_uuid = list(filter(None, string.split('/'))) + assert resource == xtrctd_rsrc + recomposed = [] + parts = xtrctd_uuid.split('-') + assert [len(p) for p in parts] == [8, 4, 4, 4, 12] + for part in parts: + new_part = ''.join(c for c in part if c in '0123456789abcdef') + recomposed.append(new_part) + recomposed = '-'.join(recomposed) + assert recomposed == xtrctd_uuid diff --git a/storage_service/locations/tests/test_api_v3_urls.py b/storage_service/locations/tests/test_api_v3_urls.py index ffc321f97..b15217023 100644 --- a/storage_service/locations/tests/test_api_v3_urls.py +++ b/storage_service/locations/tests/test_api_v3_urls.py @@ -47,34 +47,35 @@ def test_urls_construction(): # Make assertions about ``urlpatterns`` urlpatterns_names_regexes = sorted( [(up.name, up.regex.pattern) for up in urlpatterns]) + api_v_slug = 'v0_1' expected = [ - ('location', '^locations/(?P{})/$'.format(UUID_PATT)), - ('location_edit', + ('{}_location'.format(api_v_slug), '^locations/(?P{})/$'.format(UUID_PATT)), + ('{}_location_edit'.format(api_v_slug), '^locations/(?P{})/edit/$'.format(UUID_PATT)), - ('locations', '^locations/$'), - ('locations_new', '^locations/new/$'), - ('locations_new_search', '^locations/new_search/$'), - ('locations_search', '^locations/search/$'), + ('{}_locations'.format(api_v_slug), '^locations/$'), + ('{}_locations_new'.format(api_v_slug), '^locations/new/$'), + ('{}_locations_new_search'.format(api_v_slug), '^locations/new_search/$'), + ('{}_locations_search'.format(api_v_slug), '^locations/search/$'), # Note the ID_PATT for /packages/ because of pk_patt above - ('package', '^packages/(?P{})/$'.format(ID_PATT)), - ('package_edit', + ('{}_package'.format(api_v_slug), '^packages/(?P{})/$'.format(ID_PATT)), + ('{}_package_edit'.format(api_v_slug), '^packages/(?P{})/edit/$'.format(ID_PATT)), - ('packages', '^packages/$'), - ('packages_new', '^packages/new/$'), - ('packages_new_search', '^packages/new_search/$'), - ('packages_search', '^packages/search/$'), - ('pipeline', '^pipelines/(?P{})/$'.format(UUID_PATT)), - ('pipeline_edit', + ('{}_packages'.format(api_v_slug), '^packages/$'), + ('{}_packages_new'.format(api_v_slug), '^packages/new/$'), + ('{}_packages_new_search'.format(api_v_slug), '^packages/new_search/$'), + ('{}_packages_search'.format(api_v_slug), '^packages/search/$'), + ('{}_pipeline'.format(api_v_slug), '^pipelines/(?P{})/$'.format(UUID_PATT)), + ('{}_pipeline_edit'.format(api_v_slug), '^pipelines/(?P{})/edit/$'.format(UUID_PATT)), - ('pipelines', '^pipelines/$'), - ('pipelines_new', '^pipelines/new/$'), - ('pipelines_new_search', '^pipelines/new_search/$'), - ('pipelines_search', '^pipelines/search/$'), + ('{}_pipelines'.format(api_v_slug), '^pipelines/$'), + ('{}_pipelines_new'.format(api_v_slug), '^pipelines/new/$'), + ('{}_pipelines_new_search'.format(api_v_slug), '^pipelines/new_search/$'), + ('{}_pipelines_search'.format(api_v_slug), '^pipelines/search/$'), # Note that the /spaces/ resource has no search-related routes. - ('space', '^spaces/(?P{})/$'.format(UUID_PATT)), - ('space_edit', '^spaces/(?P{})/edit/$'.format(UUID_PATT)), - ('spaces', '^spaces/$'), - ('spaces_new', '^spaces/new/$') + ('{}_space'.format(api_v_slug), '^spaces/(?P{})/$'.format(UUID_PATT)), + ('{}_space_edit'.format(api_v_slug), '^spaces/(?P{})/edit/$'.format(UUID_PATT)), + ('{}_spaces'.format(api_v_slug), '^spaces/$'), + ('{}_spaces_new'.format(api_v_slug), '^spaces/new/$') ] assert urlpatterns_names_regexes == expected @@ -83,26 +84,26 @@ def test_urls_construction(): 'http_methods': {'GET': (Locations, 'index'), 'POST': (Locations, 'create'), 'SEARCH': (Locations, 'search')}, - 'route_name': 'locations'} + 'route_name': '{}_locations'.format(api_v_slug)} assert api.routes[ r'^locations/(?P{})/$'.format(UUID_PATT)] == { 'http_methods': {'DELETE': (Locations, 'delete'), 'GET': (Locations, 'show'), 'PUT': (Locations, 'update')}, - 'route_name': 'location'} + 'route_name': '{}_location'.format(api_v_slug)} assert api.routes[ r'^locations/(?P{})/edit/$'.format(UUID_PATT)] == { 'http_methods': {'GET': (Locations, 'edit')}, - 'route_name': 'location_edit'} + 'route_name': '{}_location_edit'.format(api_v_slug)} assert api.routes['^locations/new/$'] == { 'http_methods': {'GET': (Locations, 'new')}, - 'route_name': 'locations_new'} + 'route_name': '{}_locations_new'.format(api_v_slug)} assert api.routes['^locations/new_search/$'] == { 'http_methods': {'GET': (Locations, 'new_search')}, - 'route_name': 'locations_new_search'} + 'route_name': '{}_locations_new_search'.format(api_v_slug)} assert api.routes['^locations/search/$'] == { 'http_methods': {'POST': (Locations, 'search')}, - 'route_name': 'locations_search'} + 'route_name': '{}_locations_search'.format(api_v_slug)} assert '^spaces/search/$' not in api.routes assert '^pipelines/search/$' in api.routes assert '^packages/search/$' in api.routes @@ -156,49 +157,49 @@ class Skies(Resources): # POST /skies/ assert cr.regex == '^skies/$' - assert cr.name == 'skies' + assert cr.name == 'v0_1_skies' assert cr.http_method == 'POST' assert cr.resource_cls == Skies assert cr.method_name == 'create' # DELETE /skies// assert dr.regex == r'^skies/(?P{})/$'.format(UUID_PATT) - assert dr.name == 'sky' + assert dr.name == 'v0_1_sky' assert dr.http_method == 'DELETE' assert dr.resource_cls == Skies assert dr.method_name == 'delete' # GET /skies//edit/ assert er.regex == r'^skies/(?P{})/edit/$'.format(UUID_PATT) - assert er.name == 'sky_edit' + assert er.name == 'v0_1_sky_edit' assert er.http_method == 'GET' assert er.resource_cls == Skies assert er.method_name == 'edit' # GET /skies/ assert ir.regex == '^skies/$' - assert ir.name == 'skies' + assert ir.name == 'v0_1_skies' assert ir.http_method == 'GET' assert ir.resource_cls == Skies assert ir.method_name == 'index' # GET /skies/new assert nr.regex == '^skies/new/$' - assert nr.name == 'skies_new' + assert nr.name == 'v0_1_skies_new' assert nr.http_method == 'GET' assert nr.resource_cls == Skies assert nr.method_name == 'new' # GET /skies// assert sr.regex == r'^skies/(?P{})/$'.format(UUID_PATT) - assert sr.name == 'sky' + assert sr.name == 'v0_1_sky' assert sr.http_method == 'GET' assert sr.resource_cls == Skies assert sr.method_name == 'show' # PUT /skies// assert ur.regex == r'^skies/(?P{})/$'.format(UUID_PATT) - assert ur.name == 'sky' + assert ur.name == 'v0_1_sky' assert ur.http_method == 'PUT' assert ur.resource_cls == Skies assert ur.method_name == 'update' @@ -217,21 +218,21 @@ class Octopodes(Resources): # SEARCH /octopodes/ assert r1.regex == '^octopodes/$' - assert r1.name == 'octopodes' + assert r1.name == 'v0_1_octopodes' assert r1.http_method == 'SEARCH' assert r1.resource_cls == Octopodes assert r1.method_name == 'search' # POST /octopodes/search/ assert r2.regex == '^octopodes/search/$' - assert r2.name == 'octopodes_search' + assert r2.name == 'v0_1_octopodes_search' assert r2.http_method == 'POST' assert r2.resource_cls == Octopodes assert r2.method_name == 'search' # GET /octopodes/new_search/ assert r3.regex == '^octopodes/new_search/$' - assert r3.name == 'octopodes_new_search' + assert r3.name == 'v0_1_octopodes_new_search' assert r3.http_method == 'GET' assert r3.resource_cls == Octopodes assert r3.method_name == 'new_search' diff --git a/storage_service/locations/tests/test_querybuilder.py b/storage_service/locations/tests/test_querybuilder.py index 5a7a0764b..d757317a0 100644 --- a/storage_service/locations/tests/test_querybuilder.py +++ b/storage_service/locations/tests/test_querybuilder.py @@ -2,13 +2,42 @@ """Tests for the querybuilder module.""" from __future__ import print_function +from datetime import datetime from django.db.models import Q -from locations.models import Package +from locations.models import Package, File from locations.api.v3.remple import QueryBuilder +def test_query_expression_construction_dates(): + qb = QueryBuilder(File, primary_key='uuid') + FILTER_1 = ['ingestion_time', '<=', '2015-12-17T11:59:59'] + qe = qb.get_query_expression(FILTER_1) + filter_obj = qe.children[0] + assert qb.errors == {} + assert isinstance(qe, Q) + assert qe.connector == 'AND' + assert len(qe.children) == 1 + assert filter_obj[0] == 'ingestion_time__lte' + assert isinstance(filter_obj[1], datetime) + FILTER_2 = [ + 'and', [['pronom_id', '=', 'fmt/19'], + ['ingestion_time', '<=', '2015-12-17T11:59:59'], + ['ingestion_time', '>=', '2015-12-16T00:00:01']]] + qe = qb.get_query_expression(FILTER_2) + assert qe.connector == 'AND' + assert isinstance(qe, Q) + assert qb.errors == {} + assert len(qe.children) == 3 + for filter_obj in qe.children: + for thing in filter_obj: + print('\n\n') + print(thing) + print(type(thing)) + print('\n\n') + + def test_query_expression_construction(): """Test that the ``get_query_expression`` method can convert Python lists to the corresponding Django Q expression. diff --git a/storage_service/static/openapi/openapispecs/client.py b/storage_service/static/openapi/openapispecs/client.py index dd7787cc3..9171b7ee5 100644 --- a/storage_service/static/openapi/openapispecs/client.py +++ b/storage_service/static/openapi/openapispecs/client.py @@ -73,7 +73,7 @@ OPENAPI_SPEC = ( - OrderedDict([('openapi', '3.0.0'), ('info', OrderedDict([('version', '3.0.0'), ('title', 'Archivematica Storage Service API'), ('description', 'An API for the Archivematica Storage Service.')])), ('servers', [OrderedDict([('url', '/api/v3'), ('description', 'The default server for the Archivematica Storage Service.')])]), ('security', [OrderedDict([('ApiKeyAuth', [])])]), ('components', OrderedDict([('securitySchemes', OrderedDict([('ApiKeyAuth', OrderedDict([('type', 'apiKey'), ('in', 'header'), ('name', 'Authorization')]))])), ('parameters', OrderedDict([('items_per_page', OrderedDict([('in', 'query'), ('name', 'items_per_page'), ('required', False), ('schema', OrderedDict([('type', 'integer'), ('minimum', 1), ('default', 10)])), ('description', 'The maximum number of items to return.')])), ('page', OrderedDict([('in', 'query'), ('name', 'page'), ('required', False), ('schema', OrderedDict([('type', 'integer'), ('minimum', 1), ('default', 1)])), ('description', 'The page number to return.')])), ('order_by_direction', OrderedDict([('in', 'query'), ('name', 'order_by_direction'), ('schema', OrderedDict([('type', 'string'), ('enum', ['-', 'ascending', 'asc', 'descending', 'desc'])])), ('required', False), ('description', 'The direction of the ordering; omitting this parameter means ascending direction.')])), ('order_by_attribute', OrderedDict([('in', 'query'), ('name', 'order_by_attribute'), ('schema', {'type': 'string'}), ('description', 'Attribute of the resource that view results should be ordered by.'), ('required', False)])), ('order_by_subattribute', OrderedDict([('in', 'query'), ('name', 'order_by_subattribute'), ('schema', {'type': 'string'}), ('required', False), ('description', 'Attribute of the related attribute order_by_attribute of the resource that view results should be ordered by.')]))])), ('schemas', OrderedDict([('ErrorSchema', OrderedDict([('type', 'object'), ('properties', OrderedDict([('error', OrderedDict([('type', 'string')]))])), ('required', ['error'])])), ('PaginatorSchema', OrderedDict([('type', 'object'), ('properties', OrderedDict([('count', {'type': 'integer'}), ('page', {'default': 1, 'minimum': 1, 'type': 'integer'}), ('items_per_page', {'default': 10, 'minimum': 1, 'type': 'integer'})])), ('required', ['page', 'items_per_page'])])), ('LocationView', {'required': ['space', 'purpose', 'relative_path'], 'type': 'object', 'properties': {u'masters': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'used': OrderedDict([('type', 'integer'), ('default', 0), ('description', 'Amount used, in bytes.')]), 'uuid': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Unique identifier')]), 'space': OrderedDict([('type', 'string'), ('format', 'uri')]), u'locationpipeline_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'True if space can be accessed.')]), 'quota': OrderedDict([('type', 'integer'), ('nullable', True), ('default', None), ('description', 'Size, in bytes (optional)')]), 'relative_path': OrderedDict([('type', 'string'), ('description', "Path to location, relative to the storage space's path.")]), u'package_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'purpose': OrderedDict([('type', 'string'), ('enum', ['AR', 'AS', 'CP', 'DS', 'SD', 'SS', 'BL', 'TS', 'RP']), ('description', 'Purpose of the space. Eg. AIP storage, Transfer source')]), 'replicators': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')])), ('description', 'Other locations that will be used to create replicas of the packages stored in this location')]), 'pipeline': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')])), ('description', 'UUID of the Archivematica instance using this location.')]), u'id': OrderedDict([('type', 'integer')]), 'description': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Human-readable description.')])}}), ('PaginatedSubsetOfLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('paginator', {'$ref': '#/components/schemas/PaginatorSchema'}), ('items', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/LocationView'})]))])), ('required', ['paginator', 'items'])])), ('LocationCreate', {'required': ['space', 'relative_path', 'purpose'], 'type': 'object', 'properties': {'pipeline': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uuid of a pipeline resource')])), ('description', 'UUID of the Archivematica instance using this location.')]), 'description': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Human-readable description.')]), 'space': OrderedDict([('type', 'string'), ('format', 'uuid of a space resource')]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'True if space can be accessed.')]), 'quota': OrderedDict([('type', 'integer'), ('default', None), ('description', 'Size, in bytes (optional)')]), 'relative_path': OrderedDict([('type', 'string'), ('description', "Path to location, relative to the storage space's path.")]), 'purpose': OrderedDict([('type', 'string'), ('enum', ['AR', 'AS', 'CP', 'DS', 'SD', 'SS', 'BL', 'TS', 'RP']), ('description', 'Purpose of the space. Eg. AIP storage, Transfer source')]), 'replicators': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uuid of a location resource')])), ('description', 'Other locations that will be used to create replicas of the packages stored in this location')])}}), ('LocationUpdate', {'required': ['space', 'relative_path', 'purpose'], 'type': 'object', 'properties': {'pipeline': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uuid of a pipeline resource')])), ('description', 'UUID of the Archivematica instance using this location.')]), 'description': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Human-readable description.')]), 'space': OrderedDict([('type', 'string'), ('format', 'uuid of a space resource')]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'True if space can be accessed.')]), 'quota': OrderedDict([('type', 'integer'), ('default', None), ('description', 'Size, in bytes (optional)')]), 'relative_path': OrderedDict([('type', 'string'), ('description', "Path to location, relative to the storage space's path.")]), 'purpose': OrderedDict([('type', 'string'), ('enum', ['AR', 'AS', 'CP', 'DS', 'SD', 'SS', 'BL', 'TS', 'RP']), ('description', 'Purpose of the space. Eg. AIP storage, Transfer source')]), 'replicators': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uuid of a location resource')])), ('description', 'Other locations that will be used to create replicas of the packages stored in this location')])}}), ('NewLocation', OrderedDict([('type', 'object'), ('properties', OrderedDict([('spaces', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uuid of an instance of the spaces resource')]))])), ('pipelines', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uuid of an instance of the pipelines resource')]))])), ('locations', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uuid of an instance of the locations resource')]))]))])), ('required', ['spaces', 'pipelines', 'locations'])])), ('EditALocation', OrderedDict([('type', 'object'), ('properties', OrderedDict([('data', {'$ref': '#/components/schemas/NewLocation'}), ('resource', {'$ref': '#/components/schemas/LocationView'})])), ('required', ['data', 'resource'])])), ('SimpleFilterOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsMasters', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'masters'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsSpace', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['space'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['last_verified', 'used', 'verified', 'uuid', 'access_protocol', 'staging_path', 'size', 'path', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsLocationpipeline_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'locationpipeline_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', [u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsPackage_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'package_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsReplicators', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['replicators'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsPipeline', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['pipeline'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['api_key', 'uuid', 'enabled', 'api_username', 'remote_name', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('CoordinativeFilterOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('conjunction', OrderedDict([('type', 'string'), ('enum', ['and', 'or'])])), ('complement', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FilterOverLocations'})]))]))])), ('NegativeFilterOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('negation', OrderedDict([('type', 'string'), ('enum', ['not'])])), ('complement', {'$ref': '#/components/schemas/FilterOverLocations'})]))])), ('ArrayFilterOverLocations', OrderedDict([('type', 'array'), ('items', {'oneOf': [{'type': 'string'}, {'type': 'integer'}]})])), ('ObjectFilterOverLocations', {'oneOf': [{'$ref': '#/components/schemas/CoordinativeFilterOverLocations'}, {'$ref': '#/components/schemas/NegativeFilterOverLocations'}, {'$ref': '#/components/schemas/SimpleFilterOverLocations'}, {'$ref': '#/components/schemas/FilterOverLocationsMasters'}, {'$ref': '#/components/schemas/FilterOverLocationsSpace'}, {'$ref': '#/components/schemas/FilterOverLocationsLocationpipeline_set'}, {'$ref': '#/components/schemas/FilterOverLocationsPackage_set'}, {'$ref': '#/components/schemas/FilterOverLocationsReplicators'}, {'$ref': '#/components/schemas/FilterOverLocationsPipeline'}]}), ('FilterOverLocations', {'oneOf': [{'$ref': '#/components/schemas/ObjectFilterOverLocations'}, {'$ref': '#/components/schemas/ArrayFilterOverLocations'}]}), ('SearchQueryOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('filter', {'$ref': '#/components/schemas/FilterOverLocations'}), ('order_by', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))]))]))])), ('required', ['filter'])])), ('SearchOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('query', {'$ref': '#/components/schemas/SearchQueryOverLocations'}), ('paginator', {'$ref': '#/components/schemas/PaginatorSchema'})])), ('required', ['query'])])), ('DataForNewSearchOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('search_parameters', OrderedDict([('type', 'string')]))])), ('required', ['search_parameters'])])), ('PackageView', {'required': ['current_location', 'current_path', 'package_type', 'related_packages'], 'type': 'object', 'properties': {'size': OrderedDict([('type', 'integer'), ('default', 0), ('description', 'Size in bytes of the package')]), 'status': OrderedDict([('type', 'string'), ('enum', ['PENDING', 'STAGING', 'UPLOADED', 'VERIFIED', 'FAIL', 'DEL_REQ', 'DELETED', 'FINALIZE']), ('default', 'FAIL'), ('description', 'Status of the package in the storage service.')]), 'package_type': OrderedDict([('type', 'string'), ('enum', ['AIP', 'AIC', 'SIP', 'DIP', 'transfer', 'file', 'deposit'])]), u'fixitylog_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'origin_pipeline': OrderedDict([('type', 'string'), ('format', 'uri'), ('nullable', True)]), 'uuid': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Unique identifier')]), u'replicas': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), u'event_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), u'file_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'replicated_package': OrderedDict([('type', 'string'), ('format', 'uri'), ('nullable', True)]), 'misc_attributes': OrderedDict([('type', 'object'), ('nullable', True), ('default', {}), ('description', 'For storing flexible, often Space-specific, attributes')]), 'pointer_file_location': OrderedDict([('type', 'string'), ('format', 'uri'), ('nullable', True)]), 'encryption_key_fingerprint': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'The fingerprint of the GPG key used to encrypt the package, if applicable')]), u'packagedownloadtask_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'current_location': OrderedDict([('type', 'string'), ('format', 'uri')]), 'pointer_file_path': OrderedDict([('type', 'string'), ('nullable', True)]), 'related_packages': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'current_path': OrderedDict([('type', 'string')]), u'id': OrderedDict([('type', 'integer')]), 'description': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Human-readable description.')])}}), ('PaginatedSubsetOfPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('paginator', {'$ref': '#/components/schemas/PaginatorSchema'}), ('items', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/PackageView'})]))])), ('required', ['paginator', 'items'])])), ('SimpleFilterOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesFixitylog_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'fixitylog_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['datetime_reported', 'error_details', u'id', 'success'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesOrigin_pipeline', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['origin_pipeline'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['api_key', 'uuid', 'enabled', 'api_username', 'remote_name', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesReplicas', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'replicas'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesEvent_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'event_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['status', 'user_id', 'event_type', 'store_data', 'status_time', 'status_reason', u'id', 'user_email', 'event_reason'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesFile_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'file_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['accessionid', 'origin', 'source_package', 'name', 'checksum', 'stored', 'source_id', u'id', 'uuid'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesReplicated_package', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['replicated_package'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesPointer_file_location', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['pointer_file_location'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesPackagedownloadtask_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'packagedownloadtask_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['uuid', 'download_completion_time', 'downloads_completed', u'id', 'downloads_attempted'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesCurrent_location', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['current_location'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesRelated_packages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['related_packages'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('CoordinativeFilterOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('conjunction', OrderedDict([('type', 'string'), ('enum', ['and', 'or'])])), ('complement', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FilterOverPackages'})]))]))])), ('NegativeFilterOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('negation', OrderedDict([('type', 'string'), ('enum', ['not'])])), ('complement', {'$ref': '#/components/schemas/FilterOverPackages'})]))])), ('ArrayFilterOverPackages', OrderedDict([('type', 'array'), ('items', {'oneOf': [{'type': 'string'}, {'type': 'integer'}]})])), ('ObjectFilterOverPackages', {'oneOf': [{'$ref': '#/components/schemas/CoordinativeFilterOverPackages'}, {'$ref': '#/components/schemas/NegativeFilterOverPackages'}, {'$ref': '#/components/schemas/SimpleFilterOverPackages'}, {'$ref': '#/components/schemas/FilterOverPackagesFixitylog_set'}, {'$ref': '#/components/schemas/FilterOverPackagesOrigin_pipeline'}, {'$ref': '#/components/schemas/FilterOverPackagesReplicas'}, {'$ref': '#/components/schemas/FilterOverPackagesEvent_set'}, {'$ref': '#/components/schemas/FilterOverPackagesFile_set'}, {'$ref': '#/components/schemas/FilterOverPackagesReplicated_package'}, {'$ref': '#/components/schemas/FilterOverPackagesPointer_file_location'}, {'$ref': '#/components/schemas/FilterOverPackagesPackagedownloadtask_set'}, {'$ref': '#/components/schemas/FilterOverPackagesCurrent_location'}, {'$ref': '#/components/schemas/FilterOverPackagesRelated_packages'}]}), ('FilterOverPackages', {'oneOf': [{'$ref': '#/components/schemas/ObjectFilterOverPackages'}, {'$ref': '#/components/schemas/ArrayFilterOverPackages'}]}), ('SearchQueryOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('filter', {'$ref': '#/components/schemas/FilterOverPackages'}), ('order_by', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))]))]))])), ('required', ['filter'])])), ('SearchOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('query', {'$ref': '#/components/schemas/SearchQueryOverPackages'}), ('paginator', {'$ref': '#/components/schemas/PaginatorSchema'})])), ('required', ['query'])])), ('DataForNewSearchOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('search_parameters', OrderedDict([('type', 'string')]))])), ('required', ['search_parameters'])])), ('PipelineView', {'required': ['uuid'], 'type': 'object', 'properties': {'api_key': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'API key to use when making API calls to the pipeline.')]), 'uuid': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Identifier for the Archivematica pipeline')]), u'event_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), u'locationpipeline_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'Enabled if this pipeline is able to access the storage service.')]), u'package_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'location': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'api_username': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Username to use when making API calls to the pipeline.')]), 'remote_name': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Host or IP address of the pipeline server for making API calls.')]), u'id': OrderedDict([('type', 'integer')]), 'description': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Human readable description of the Archivematica instance.')])}}), ('PaginatedSubsetOfPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('paginator', {'$ref': '#/components/schemas/PaginatorSchema'}), ('items', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/PipelineView'})]))])), ('required', ['paginator', 'items'])])), ('PipelineCreate', {'type': 'object', 'properties': {'remote_name': OrderedDict([('anyOf', [OrderedDict([('type', 'string'), ('format', 'ipv4')]), OrderedDict([('type', 'string'), ('format', 'uri')])]), ('default', None), ('description', 'Host or IP address of the pipeline server for making API calls.')]), 'api_key': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'API key to use when making API calls to the pipeline.')]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'Enabled if this pipeline is able to access the storage service.')]), 'description': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Human readable description of the Archivematica instance.')]), 'api_username': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Username to use when making API calls to the pipeline.')])}}), ('PipelineUpdate', {'type': 'object', 'properties': {'remote_name': OrderedDict([('anyOf', [OrderedDict([('type', 'string'), ('format', 'ipv4')]), OrderedDict([('type', 'string'), ('format', 'uri')])]), ('default', None), ('description', 'Host or IP address of the pipeline server for making API calls.')]), 'api_key': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'API key to use when making API calls to the pipeline.')]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'Enabled if this pipeline is able to access the storage service.')]), 'description': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Human readable description of the Archivematica instance.')]), 'api_username': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Username to use when making API calls to the pipeline.')])}}), ('NewPipeline', OrderedDict([('type', 'object'), ('properties', OrderedDict()), ('required', [])])), ('EditAPipeline', OrderedDict([('type', 'object'), ('properties', OrderedDict([('data', {'$ref': '#/components/schemas/NewPipeline'}), ('resource', {'$ref': '#/components/schemas/PipelineView'})])), ('required', ['data', 'resource'])])), ('SimpleFilterOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['api_key', 'uuid', 'enabled', 'api_username', 'remote_name', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPipelinesEvent_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'event_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['status', 'user_id', 'event_type', 'store_data', 'status_time', 'status_reason', u'id', 'user_email', 'event_reason'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPipelinesLocationpipeline_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'locationpipeline_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', [u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPipelinesPackage_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'package_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPipelinesLocation', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['location'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('CoordinativeFilterOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('conjunction', OrderedDict([('type', 'string'), ('enum', ['and', 'or'])])), ('complement', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FilterOverPipelines'})]))]))])), ('NegativeFilterOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('negation', OrderedDict([('type', 'string'), ('enum', ['not'])])), ('complement', {'$ref': '#/components/schemas/FilterOverPipelines'})]))])), ('ArrayFilterOverPipelines', OrderedDict([('type', 'array'), ('items', {'oneOf': [{'type': 'string'}, {'type': 'integer'}]})])), ('ObjectFilterOverPipelines', {'oneOf': [{'$ref': '#/components/schemas/CoordinativeFilterOverPipelines'}, {'$ref': '#/components/schemas/NegativeFilterOverPipelines'}, {'$ref': '#/components/schemas/SimpleFilterOverPipelines'}, {'$ref': '#/components/schemas/FilterOverPipelinesEvent_set'}, {'$ref': '#/components/schemas/FilterOverPipelinesLocationpipeline_set'}, {'$ref': '#/components/schemas/FilterOverPipelinesPackage_set'}, {'$ref': '#/components/schemas/FilterOverPipelinesLocation'}]}), ('FilterOverPipelines', {'oneOf': [{'$ref': '#/components/schemas/ObjectFilterOverPipelines'}, {'$ref': '#/components/schemas/ArrayFilterOverPipelines'}]}), ('SearchQueryOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('filter', {'$ref': '#/components/schemas/FilterOverPipelines'}), ('order_by', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))]))]))])), ('required', ['filter'])])), ('SearchOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('query', {'$ref': '#/components/schemas/SearchQueryOverPipelines'}), ('paginator', {'$ref': '#/components/schemas/PaginatorSchema'})])), ('required', ['query'])])), ('DataForNewSearchOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('search_parameters', OrderedDict([('type', 'string')]))])), ('required', ['search_parameters'])])), ('SpaceView', {'required': ['access_protocol', 'staging_path'], 'type': 'object', 'properties': {u'duracloud': OrderedDict([('type', 'string'), ('format', 'uri')]), u'lockssomatic': OrderedDict([('type', 'string'), ('format', 'uri')]), 'last_verified': OrderedDict([('type', 'string'), ('format', 'date-time'), ('nullable', True), ('default', None), ('description', 'Time this location was last verified to be accessible.')]), 'used': OrderedDict([('type', 'integer'), ('default', 0), ('description', 'Amount used in bytes')]), 'verified': OrderedDict([('type', 'boolean'), ('default', False), ('description', 'Whether or not the space has been verified to be accessible.')]), u'fedora': OrderedDict([('type', 'string'), ('format', 'uri')]), u'gpg': OrderedDict([('type', 'string'), ('format', 'uri')]), 'uuid': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Unique identifier')]), 'access_protocol': OrderedDict([('type', 'string'), ('enum', ['ARKIVUM', 'DV', 'DC', 'DSPACE', 'FEDORA', 'GPG', 'FS', 'LOM', 'NFS', 'PIPE_FS', 'SWIFT']), ('description', 'How the space can be accessed.')]), 'staging_path': OrderedDict([('type', 'string'), ('description', 'Absolute path to a staging area. Must be UNIX filesystem compatible, preferably on the same filesystem as the path.')]), u'dspace': OrderedDict([('type', 'string'), ('format', 'uri')]), u'nfs': OrderedDict([('type', 'string'), ('format', 'uri')]), u'arkivum': OrderedDict([('type', 'string'), ('format', 'uri')]), 'size': OrderedDict([('type', 'integer'), ('nullable', True), ('default', None), ('description', 'Size in bytes (optional)')]), u'dataverse': OrderedDict([('type', 'string'), ('format', 'uri')]), 'path': OrderedDict([('type', 'string'), ('default', ''), ('description', 'Absolute path to the space on the storage service machine.')]), u'location_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), u'localfilesystem': OrderedDict([('type', 'string'), ('format', 'uri')]), u'swift': OrderedDict([('type', 'string'), ('format', 'uri')]), u'id': OrderedDict([('type', 'integer')]), u'pipelinelocalfs': OrderedDict([('type', 'string'), ('format', 'uri')])}}), ('PaginatedSubsetOfSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('paginator', {'$ref': '#/components/schemas/PaginatorSchema'}), ('items', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/SpaceView'})]))])), ('required', ['paginator', 'items'])])), ('SpaceCreate', {'required': ['staging_path', 'access_protocol'], 'type': 'object', 'properties': {'path': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', ''), ('description', 'Absolute path to the space on the storage service machine.')]), 'size': OrderedDict([('type', 'integer'), ('default', None), ('description', 'Size in bytes (optional)')]), 'access_protocol': OrderedDict([('type', 'string'), ('enum', ['ARKIVUM', 'DV', 'DC', 'DSPACE', 'FEDORA', 'GPG', 'FS', 'LOM', 'NFS', 'PIPE_FS', 'SWIFT']), ('description', 'How the space can be accessed.')]), 'staging_path': OrderedDict([('type', 'string'), ('maxLength', 256), ('description', 'Absolute path to a staging area. Must be UNIX filesystem compatible, preferably on the same filesystem as the path.')])}}), ('SpaceUpdate', {'required': ['staging_path'], 'type': 'object', 'properties': {'path': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', ''), ('description', 'Absolute path to the space on the storage service machine.')]), 'staging_path': OrderedDict([('type', 'string'), ('maxLength', 256), ('description', 'Absolute path to a staging area. Must be UNIX filesystem compatible, preferably on the same filesystem as the path.')]), 'size': OrderedDict([('type', 'integer'), ('default', None), ('description', 'Size in bytes (optional)')])}}), ('NewSpace', OrderedDict([('type', 'object'), ('properties', OrderedDict()), ('required', [])])), ('EditASpace', OrderedDict([('type', 'object'), ('properties', OrderedDict([('data', {'$ref': '#/components/schemas/NewSpace'}), ('resource', {'$ref': '#/components/schemas/SpaceView'})])), ('required', ['data', 'resource'])])), ('SimpleFilterOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['last_verified', 'used', 'verified', 'uuid', 'access_protocol', 'staging_path', 'size', 'path', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesDuracloud', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'duracloud'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['duraspace', 'space', 'host', 'user', 'password', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesLockssomatic', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'lockssomatic'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['collection_iri', 'external_domain', 'space', 'content_provider_id', 'sd_iri', u'id', 'checksum_type', 'au_size', 'keep_local'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesFedora', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'fedora'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['fedora_name', 'fedora_password', 'fedora_user', u'id', 'space'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesGpg', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'gpg'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', [u'id', 'key', 'space'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesDspace', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'dspace'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['space', 'sd_iri', 'metadata_policy', 'user', 'archive_format', 'password', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesNfs', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'nfs'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['manually_mounted', 'space', 'remote_path', 'version', 'remote_name', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesArkivum', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'arkivum'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['host', 'remote_user', 'remote_name', u'id', 'space'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesDataverse', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'dataverse'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['agent_name', 'agent_identifier', 'space', 'host', 'agent_type', 'api_key', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesLocation_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'location_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesLocalfilesystem', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'localfilesystem'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', [u'id', 'space'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesSwift', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'swift'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['username', 'container', 'space', 'region', 'auth_version', 'auth_url', 'password', u'id', 'tenant'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesPipelinelocalfs', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'pipelinelocalfs'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['remote_user', 'space', 'assume_rsync_daemon', 'remote_name', u'id', 'rsync_password'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('CoordinativeFilterOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('conjunction', OrderedDict([('type', 'string'), ('enum', ['and', 'or'])])), ('complement', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FilterOverSpaces'})]))]))])), ('NegativeFilterOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('negation', OrderedDict([('type', 'string'), ('enum', ['not'])])), ('complement', {'$ref': '#/components/schemas/FilterOverSpaces'})]))])), ('ArrayFilterOverSpaces', OrderedDict([('type', 'array'), ('items', {'oneOf': [{'type': 'string'}, {'type': 'integer'}]})])), ('ObjectFilterOverSpaces', {'oneOf': [{'$ref': '#/components/schemas/CoordinativeFilterOverSpaces'}, {'$ref': '#/components/schemas/NegativeFilterOverSpaces'}, {'$ref': '#/components/schemas/SimpleFilterOverSpaces'}, {'$ref': '#/components/schemas/FilterOverSpacesDuracloud'}, {'$ref': '#/components/schemas/FilterOverSpacesLockssomatic'}, {'$ref': '#/components/schemas/FilterOverSpacesFedora'}, {'$ref': '#/components/schemas/FilterOverSpacesGpg'}, {'$ref': '#/components/schemas/FilterOverSpacesDspace'}, {'$ref': '#/components/schemas/FilterOverSpacesNfs'}, {'$ref': '#/components/schemas/FilterOverSpacesArkivum'}, {'$ref': '#/components/schemas/FilterOverSpacesDataverse'}, {'$ref': '#/components/schemas/FilterOverSpacesLocation_set'}, {'$ref': '#/components/schemas/FilterOverSpacesLocalfilesystem'}, {'$ref': '#/components/schemas/FilterOverSpacesSwift'}, {'$ref': '#/components/schemas/FilterOverSpacesPipelinelocalfs'}]}), ('FilterOverSpaces', {'oneOf': [{'$ref': '#/components/schemas/ObjectFilterOverSpaces'}, {'$ref': '#/components/schemas/ArrayFilterOverSpaces'}]}), ('SearchQueryOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('filter', {'$ref': '#/components/schemas/FilterOverSpaces'}), ('order_by', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))]))]))])), ('required', ['filter'])])), ('SearchOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('query', {'$ref': '#/components/schemas/SearchQueryOverSpaces'}), ('paginator', {'$ref': '#/components/schemas/PaginatorSchema'})])), ('required', ['query'])])), ('DataForNewSearchOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('search_parameters', OrderedDict([('type', 'string')]))])), ('required', ['search_parameters'])]))]))])), ('paths', {'/packages/new_search/': {'get': OrderedDict([('summary', 'Get the data needed to search over all packages.'), ('description', 'Get the data needed to search over all packages.'), ('operationId', 'new_search.package'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request to get the data needed to search across all packages succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/DataForNewSearchOverPackages')]))]))]))]))])), ('tags', ['packages'])])}, '/locations/new/': {'get': OrderedDict([('summary', 'Get the data needed to create a new location.'), ('description', 'Get the data needed to create a new location.'), ('operationId', 'data_for_new.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to create a new location resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/NewLocation')]))]))]))]))])), ('tags', ['locations'])])}, '/pipelines/{pk}/': {'put': OrderedDict([('summary', 'Update an existing pipeline.'), ('description', 'Update an existing pipeline.'), ('operationId', 'update.pipeline'), ('requestBody', OrderedDict([('description', 'JSON object required to update an existing pipeline'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/PipelineUpdate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Updating of an existing pipeline resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditAPipeline')]))]))]))])), ('404', OrderedDict([('description', 'Updating of an existing pipeline resource failed because there is no pipeline with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Updating of an existing pipeline resource failed because the user is forbidden from updating this pipeline resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('400', OrderedDict([('description', 'Updating of an existing pipeline resource failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])]), 'get': OrderedDict([('summary', 'View an existing pipeline.'), ('description', 'View an existing pipeline.'), ('operationId', 'get.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a single pipeline succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PipelineView')]))]))]))])), ('404', OrderedDict([('description', 'Request for a single pipeline failed because there is no pipeline resource with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for a single pipeline failed because the user is forbidden from viewing this pipeline resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])]), 'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the pipeline.')])], 'delete': OrderedDict([('summary', 'Delete an existing pipeline.'), ('description', 'Delete an existing pipeline.'), ('operationId', 'delete.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Deletion of the pipeline resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PipelineView')]))]))]))])), ('404', OrderedDict([('description', 'Deletion of the pipeline resource failed because there is no pipeline with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Deletion of the pipeline resource failed because user is forbidden from performing this action'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])])}, '/spaces/new/': {'get': OrderedDict([('summary', 'Get the data needed to create a new space.'), ('description', 'Get the data needed to create a new space.'), ('operationId', 'data_for_new.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to create a new space resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/NewSpace')]))]))]))]))])), ('tags', ['spaces'])])}, '/spaces/': {'post': OrderedDict([('summary', 'Create a new space.'), ('description', 'Create a new space.'), ('operationId', 'create.space'), ('requestBody', OrderedDict([('description', 'JSON object required to create a new space'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/SpaceCreate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Creation of a new space succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/SpaceView')]))]))]))])), ('400', OrderedDict([('description', 'Creation of a new space failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])]), 'search': OrderedDict([('summary', 'Search over all spaces.'), ('description', 'Search over all spaces.'), ('operationId', 'search.space'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all spaces'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverSpaces'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all spaces succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfSpaces')]))]))]))])), ('400', OrderedDict([('description', 'Search across all spaces failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])]), 'get': OrderedDict([('summary', 'View all spaces.'), ('description', 'View all spaces.'), ('operationId', 'get_many.space'), ('parameters', [{'$ref': '#/components/parameters/items_per_page'}, {'$ref': '#/components/parameters/page'}, {'$ref': '#/components/parameters/order_by_attribute'}, {'$ref': '#/components/parameters/order_by_subattribute'}, {'$ref': '#/components/parameters/order_by_direction'}]), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a collection of spaces succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfSpaces')]))]))]))])), ('400', OrderedDict([('description', 'Request for a collection of spaces failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])])}, '/pipelines/search/': {'post': OrderedDict([('summary', 'Search over all pipelines.'), ('description', 'Search over all pipelines.'), ('operationId', 'search.pipeline'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all pipelines'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverPipelines'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all pipelines succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPipelines')]))]))]))])), ('400', OrderedDict([('description', 'Search across all pipelines failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])])}, '/locations/{pk}/edit/': {'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the location.')])], 'get': OrderedDict([('summary', 'Get the data needed to update an existing location.'), ('description', 'Get the data needed to update an existing location.'), ('operationId', 'data_for_edit.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to edit a(n) location resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditALocation')]))]))]))])), ('404', OrderedDict([('description', 'Request for the data needed to edit a(n) location failed because there is no location resource with the specified pk'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for the data needed to edit a(n) location failed because the user is forbidden from editing this location resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])])}, '/spaces/{pk}/edit/': {'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the space.')])], 'get': OrderedDict([('summary', 'Get the data needed to update an existing space.'), ('description', 'Get the data needed to update an existing space.'), ('operationId', 'data_for_edit.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to edit a(n) space resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditASpace')]))]))]))])), ('404', OrderedDict([('description', 'Request for the data needed to edit a(n) space failed because there is no space resource with the specified pk'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for the data needed to edit a(n) space failed because the user is forbidden from editing this space resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])])}, '/pipelines/{pk}/edit/': {'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the pipeline.')])], 'get': OrderedDict([('summary', 'Get the data needed to update an existing pipeline.'), ('description', 'Get the data needed to update an existing pipeline.'), ('operationId', 'data_for_edit.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to edit a(n) pipeline resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditAPipeline')]))]))]))])), ('404', OrderedDict([('description', 'Request for the data needed to edit a(n) pipeline failed because there is no pipeline resource with the specified pk'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for the data needed to edit a(n) pipeline failed because the user is forbidden from editing this pipeline resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])])}, '/spaces/{pk}/': {'put': OrderedDict([('summary', 'Update an existing space.'), ('description', 'Update an existing space.'), ('operationId', 'update.space'), ('requestBody', OrderedDict([('description', 'JSON object required to update an existing space'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/SpaceUpdate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Updating of an existing space resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditASpace')]))]))]))])), ('404', OrderedDict([('description', 'Updating of an existing space resource failed because there is no space with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Updating of an existing space resource failed because the user is forbidden from updating this space resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('400', OrderedDict([('description', 'Updating of an existing space resource failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])]), 'get': OrderedDict([('summary', 'View an existing space.'), ('description', 'View an existing space.'), ('operationId', 'get.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a single space succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/SpaceView')]))]))]))])), ('404', OrderedDict([('description', 'Request for a single space failed because there is no space resource with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for a single space failed because the user is forbidden from viewing this space resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])]), 'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the space.')])], 'delete': OrderedDict([('summary', 'Delete an existing space.'), ('description', 'Delete an existing space.'), ('operationId', 'delete.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Deletion of the space resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/SpaceView')]))]))]))])), ('404', OrderedDict([('description', 'Deletion of the space resource failed because there is no space with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Deletion of the space resource failed because user is forbidden from performing this action'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])])}, '/locations/': {'post': OrderedDict([('summary', 'Create a new location.'), ('description', 'Create a new location.'), ('operationId', 'create.location'), ('requestBody', OrderedDict([('description', 'JSON object required to create a new location'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/LocationCreate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Creation of a new location succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/LocationView')]))]))]))])), ('400', OrderedDict([('description', 'Creation of a new location failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])]), 'search': OrderedDict([('summary', 'Search over all locations.'), ('description', 'Search over all locations.'), ('operationId', 'search.location'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all locations'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverLocations'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all locations succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfLocations')]))]))]))])), ('400', OrderedDict([('description', 'Search across all locations failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])]), 'get': OrderedDict([('summary', 'View all locations.'), ('description', 'View all locations.'), ('operationId', 'get_many.location'), ('parameters', [{'$ref': '#/components/parameters/items_per_page'}, {'$ref': '#/components/parameters/page'}, {'$ref': '#/components/parameters/order_by_attribute'}, {'$ref': '#/components/parameters/order_by_subattribute'}, {'$ref': '#/components/parameters/order_by_direction'}]), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a collection of locations succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfLocations')]))]))]))])), ('400', OrderedDict([('description', 'Request for a collection of locations failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])])}, '/locations/search/': {'post': OrderedDict([('summary', 'Search over all locations.'), ('description', 'Search over all locations.'), ('operationId', 'search.location'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all locations'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverLocations'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all locations succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfLocations')]))]))]))])), ('400', OrderedDict([('description', 'Search across all locations failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])])}, '/pipelines/new_search/': {'get': OrderedDict([('summary', 'Get the data needed to search over all pipelines.'), ('description', 'Get the data needed to search over all pipelines.'), ('operationId', 'new_search.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request to get the data needed to search across all pipelines succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/DataForNewSearchOverPipelines')]))]))]))]))])), ('tags', ['pipelines'])])}, '/spaces/new_search/': {'get': OrderedDict([('summary', 'Get the data needed to search over all spaces.'), ('description', 'Get the data needed to search over all spaces.'), ('operationId', 'new_search.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request to get the data needed to search across all spaces succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/DataForNewSearchOverSpaces')]))]))]))]))])), ('tags', ['spaces'])])}, '/spaces/search/': {'post': OrderedDict([('summary', 'Search over all spaces.'), ('description', 'Search over all spaces.'), ('operationId', 'search.space'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all spaces'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverSpaces'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all spaces succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfSpaces')]))]))]))])), ('400', OrderedDict([('description', 'Search across all spaces failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])])}, '/packages/search/': {'post': OrderedDict([('summary', 'Search over all packages.'), ('description', 'Search over all packages.'), ('operationId', 'search.package'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all packages'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverPackages'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all packages succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPackages')]))]))]))])), ('400', OrderedDict([('description', 'Search across all packages failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['packages'])])}, '/pipelines/new/': {'get': OrderedDict([('summary', 'Get the data needed to create a new pipeline.'), ('description', 'Get the data needed to create a new pipeline.'), ('operationId', 'data_for_new.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to create a new pipeline resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/NewPipeline')]))]))]))]))])), ('tags', ['pipelines'])])}, '/locations/new_search/': {'get': OrderedDict([('summary', 'Get the data needed to search over all locations.'), ('description', 'Get the data needed to search over all locations.'), ('operationId', 'new_search.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request to get the data needed to search across all locations succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/DataForNewSearchOverLocations')]))]))]))]))])), ('tags', ['locations'])])}, '/pipelines/': {'post': OrderedDict([('summary', 'Create a new pipeline.'), ('description', 'Create a new pipeline.'), ('operationId', 'create.pipeline'), ('requestBody', OrderedDict([('description', 'JSON object required to create a new pipeline'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/PipelineCreate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Creation of a new pipeline succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PipelineView')]))]))]))])), ('400', OrderedDict([('description', 'Creation of a new pipeline failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])]), 'search': OrderedDict([('summary', 'Search over all pipelines.'), ('description', 'Search over all pipelines.'), ('operationId', 'search.pipeline'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all pipelines'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverPipelines'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all pipelines succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPipelines')]))]))]))])), ('400', OrderedDict([('description', 'Search across all pipelines failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])]), 'get': OrderedDict([('summary', 'View all pipelines.'), ('description', 'View all pipelines.'), ('operationId', 'get_many.pipeline'), ('parameters', [{'$ref': '#/components/parameters/items_per_page'}, {'$ref': '#/components/parameters/page'}, {'$ref': '#/components/parameters/order_by_attribute'}, {'$ref': '#/components/parameters/order_by_subattribute'}, {'$ref': '#/components/parameters/order_by_direction'}]), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a collection of pipelines succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPipelines')]))]))]))])), ('400', OrderedDict([('description', 'Request for a collection of pipelines failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])])}, '/packages/{pk}/': {'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the package.')])], 'get': OrderedDict([('summary', 'View an existing package.'), ('description', 'View an existing package.'), ('operationId', 'get.package'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a single package succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PackageView')]))]))]))])), ('404', OrderedDict([('description', 'Request for a single package failed because there is no package resource with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for a single package failed because the user is forbidden from viewing this package resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['packages'])])}, '/packages/': {'search': OrderedDict([('summary', 'Search over all packages.'), ('description', 'Search over all packages.'), ('operationId', 'search.package'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all packages'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverPackages'}), ('example', {'ObjectSearchOverPackagesExample': {'paginator': {'items_per_page': 10, 'page': 1}, 'query': {'filter': {'complement': [{'attribute': 'description', 'relation': 'like', 'value': '%a%'}, {'complement': {'attribute': 'description', 'relation': 'like', 'value': 'T%'}, 'negation': 'not'}, {'complement': [{'attribute': 'size', 'relation': '<', 'value': 1000}, {'attribute': 'size', 'relation': '>', 'value': 512}], 'conjunction': 'or'}], 'conjunction': 'and'}}}, 'ArraySearchOverPackagesExample': {'paginator': {'items_per_page': 10, 'page': 1}, 'query': {'filter': ['and', [['description', 'like', '%a%'], ['not', ['description', 'like', 'T%']], ['or', [['size', '<', 1000], ['size', '>', 512]]]]]}}})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all packages succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPackages')]))]))]))])), ('400', OrderedDict([('description', 'Search across all packages failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['packages'])]), 'get': OrderedDict([('summary', 'View all packages.'), ('description', 'View all packages.'), ('operationId', 'get_many.package'), ('parameters', [{'$ref': '#/components/parameters/items_per_page'}, {'$ref': '#/components/parameters/page'}, {'$ref': '#/components/parameters/order_by_attribute'}, {'$ref': '#/components/parameters/order_by_subattribute'}, {'$ref': '#/components/parameters/order_by_direction'}]), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a collection of packages succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPackages')]))]))]))])), ('400', OrderedDict([('description', 'Request for a collection of packages failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['packages'])])}, '/locations/{pk}/': {'put': OrderedDict([('summary', 'Update an existing location.'), ('description', 'Update an existing location.'), ('operationId', 'update.location'), ('requestBody', OrderedDict([('description', 'JSON object required to update an existing location'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/LocationUpdate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Updating of an existing location resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditALocation')]))]))]))])), ('404', OrderedDict([('description', 'Updating of an existing location resource failed because there is no location with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Updating of an existing location resource failed because the user is forbidden from updating this location resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('400', OrderedDict([('description', 'Updating of an existing location resource failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])]), 'get': OrderedDict([('summary', 'View an existing location.'), ('description', 'View an existing location.'), ('operationId', 'get.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a single location succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/LocationView')]))]))]))])), ('404', OrderedDict([('description', 'Request for a single location failed because there is no location resource with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for a single location failed because the user is forbidden from viewing this location resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])]), 'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the location.')])], 'delete': OrderedDict([('summary', 'Delete an existing location.'), ('description', 'Delete an existing location.'), ('operationId', 'delete.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Deletion of the location resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/LocationView')]))]))]))])), ('404', OrderedDict([('description', 'Deletion of the location resource failed because there is no location with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Deletion of the location resource failed because user is forbidden from performing this action'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])])}}), ('tags', [OrderedDict([('name', 'locations'), ('description', 'Access to the Location resource')]), OrderedDict([('name', 'packages'), ('description', 'Access to the Package resource')]), OrderedDict([('name', 'pipelines'), ('description', 'Access to the Pipeline resource')]), OrderedDict([('name', 'spaces'), ('description', 'Access to the Space resource')])])]) + OrderedDict([('openapi', '3.0.0'), ('info', OrderedDict([('version', '3.0.0'), ('title', 'Archivematica Storage Service API'), ('description', 'An API for the Archivematica Storage Service.')])), ('servers', [OrderedDict([('url', '/api/v3'), ('description', 'The default server for the Archivematica Storage Service.')])]), ('security', [OrderedDict([('ApiKeyAuth', [])])]), ('components', OrderedDict([('securitySchemes', OrderedDict([('ApiKeyAuth', OrderedDict([('type', 'apiKey'), ('in', 'header'), ('name', 'Authorization')]))])), ('parameters', OrderedDict([('items_per_page', OrderedDict([('in', 'query'), ('name', 'items_per_page'), ('required', False), ('schema', OrderedDict([('type', 'integer'), ('minimum', 1), ('default', 10)])), ('description', 'The maximum number of items to return.')])), ('page', OrderedDict([('in', 'query'), ('name', 'page'), ('required', False), ('schema', OrderedDict([('type', 'integer'), ('minimum', 1), ('default', 1)])), ('description', 'The page number to return.')])), ('order_by_direction', OrderedDict([('in', 'query'), ('name', 'order_by_direction'), ('schema', OrderedDict([('type', 'string'), ('enum', ['-', 'ascending', 'asc', 'descending', 'desc'])])), ('required', False), ('description', 'The direction of the ordering; omitting this parameter means ascending direction.')])), ('order_by_attribute', OrderedDict([('in', 'query'), ('name', 'order_by_attribute'), ('schema', {'type': 'string'}), ('description', 'Attribute of the resource that view results should be ordered by.'), ('required', False)])), ('order_by_subattribute', OrderedDict([('in', 'query'), ('name', 'order_by_subattribute'), ('schema', {'type': 'string'}), ('required', False), ('description', 'Attribute of the related attribute order_by_attribute of the resource that view results should be ordered by.')]))])), ('schemas', OrderedDict([('ErrorSchema', OrderedDict([('type', 'object'), ('properties', OrderedDict([('error', OrderedDict([('type', 'string')]))])), ('required', ['error'])])), ('PaginatorSchema', OrderedDict([('type', 'object'), ('properties', OrderedDict([('count', {'type': 'integer'}), ('page', {'default': 1, 'minimum': 1, 'type': 'integer'}), ('items_per_page', {'default': 10, 'minimum': 1, 'type': 'integer'})])), ('required', ['page', 'items_per_page'])])), ('FileView', {'required': ['package', 'name', 'ingestion_time', 'source_id', 'checksum'], 'type': 'object', 'properties': {'ingestion_time': OrderedDict([('type', 'string'), ('format', 'date-time'), ('nullable', True)]), 'accessionid': OrderedDict([('type', 'string'), ('description', 'Accession ID of originating transfer')]), 'source_package': OrderedDict([('type', 'string'), ('description', 'Unique identifier of originating unit')]), 'name': OrderedDict([('type', 'string')]), 'package': OrderedDict([('type', 'string'), ('format', 'uri'), ('nullable', True)]), 'checksum': OrderedDict([('type', 'string')]), 'format_name': OrderedDict([('type', 'string')]), 'origin': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Unique identifier of originating Archivematica dashboard')]), 'stored': OrderedDict([('type', 'boolean'), ('default', False)]), 'normalized': OrderedDict([('type', 'boolean'), ('default', False), ('description', 'Whether or not file has been normalized')]), 'source_id': OrderedDict([('type', 'string')]), 'size': OrderedDict([('type', 'integer'), ('default', 0), ('description', 'Size in bytes of the file')]), u'id': OrderedDict([('type', 'integer')]), 'pronom_id': OrderedDict([('type', 'string')]), 'uuid': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Unique identifier')])}}), ('PaginatedSubsetOfFiles', OrderedDict([('type', 'object'), ('properties', OrderedDict([('paginator', {'$ref': '#/components/schemas/PaginatorSchema'}), ('items', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FileView'})]))])), ('required', ['paginator', 'items'])])), ('SimpleFilterOverFiles', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['ingestion_time', 'accessionid', 'source_package', 'name', 'checksum', 'valid', 'format_name', 'origin', 'stored', 'normalized', 'source_id', 'size', u'id', 'pronom_id', 'uuid'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverFilesPackage', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['package'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('CoordinativeFilterOverFiles', OrderedDict([('type', 'object'), ('properties', OrderedDict([('conjunction', OrderedDict([('type', 'string'), ('enum', ['and', 'or'])])), ('complement', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FilterOverFiles'})]))]))])), ('NegativeFilterOverFiles', OrderedDict([('type', 'object'), ('properties', OrderedDict([('negation', OrderedDict([('type', 'string'), ('enum', ['not'])])), ('complement', {'$ref': '#/components/schemas/FilterOverFiles'})]))])), ('ArrayFilterOverFiles', OrderedDict([('type', 'array'), ('items', {'oneOf': [{'type': 'string'}, {'type': 'integer'}]})])), ('ObjectFilterOverFiles', {'oneOf': [{'$ref': '#/components/schemas/CoordinativeFilterOverFiles'}, {'$ref': '#/components/schemas/NegativeFilterOverFiles'}, {'$ref': '#/components/schemas/SimpleFilterOverFiles'}, {'$ref': '#/components/schemas/FilterOverFilesPackage'}]}), ('FilterOverFiles', {'oneOf': [{'$ref': '#/components/schemas/ObjectFilterOverFiles'}, {'$ref': '#/components/schemas/ArrayFilterOverFiles'}]}), ('SearchQueryOverFiles', OrderedDict([('type', 'object'), ('properties', OrderedDict([('filter', {'$ref': '#/components/schemas/FilterOverFiles'}), ('order_by', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))]))]))])), ('required', ['filter'])])), ('SearchOverFiles', OrderedDict([('type', 'object'), ('properties', OrderedDict([('query', {'$ref': '#/components/schemas/SearchQueryOverFiles'}), ('paginator', {'$ref': '#/components/schemas/PaginatorSchema'})])), ('required', ['query'])])), ('DataForNewSearchOverFiles', OrderedDict([('type', 'object'), ('properties', OrderedDict([('search_parameters', OrderedDict([('type', 'string')]))])), ('required', ['search_parameters'])])), ('LocationView', {'required': ['space', 'purpose', 'relative_path'], 'type': 'object', 'properties': {u'masters': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'used': OrderedDict([('type', 'integer'), ('default', 0), ('description', 'Amount used, in bytes.')]), 'uuid': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Unique identifier')]), 'space': OrderedDict([('type', 'string'), ('format', 'uri')]), u'locationpipeline_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'True if space can be accessed.')]), 'quota': OrderedDict([('type', 'integer'), ('nullable', True), ('default', None), ('description', 'Size, in bytes (optional)')]), 'relative_path': OrderedDict([('type', 'string'), ('description', "Path to location, relative to the storage space's path.")]), u'package_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'purpose': OrderedDict([('type', 'string'), ('enum', ['AR', 'AS', 'CP', 'DS', 'SD', 'SS', 'BL', 'TS', 'RP']), ('description', 'Purpose of the space. Eg. AIP storage, Transfer source')]), 'replicators': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')])), ('description', 'Other locations that will be used to create replicas of the packages stored in this location')]), 'pipeline': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')])), ('description', 'The Archivematica instance using this location.')]), u'id': OrderedDict([('type', 'integer')]), 'description': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Human-readable description.')])}}), ('PaginatedSubsetOfLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('paginator', {'$ref': '#/components/schemas/PaginatorSchema'}), ('items', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/LocationView'})]))])), ('required', ['paginator', 'items'])])), ('LocationCreate', {'required': ['space', 'relative_path', 'purpose'], 'type': 'object', 'properties': {'pipeline': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'URI of a pipeline resource')])), ('description', 'The Archivematica instance using this location.')]), 'description': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Human-readable description.')]), 'space': OrderedDict([('type', 'string'), ('format', 'URI of a space resource')]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'True if space can be accessed.')]), 'quota': OrderedDict([('type', 'integer'), ('default', None), ('description', 'Size, in bytes (optional)')]), 'relative_path': OrderedDict([('type', 'string'), ('description', "Path to location, relative to the storage space's path.")]), 'purpose': OrderedDict([('type', 'string'), ('enum', ['AR', 'AS', 'CP', 'DS', 'SD', 'SS', 'BL', 'TS', 'RP']), ('description', 'Purpose of the space. Eg. AIP storage, Transfer source')]), 'replicators': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'URI of a location resource')])), ('description', 'Other locations that will be used to create replicas of the packages stored in this location')])}}), ('LocationUpdate', {'required': ['space', 'relative_path', 'purpose'], 'type': 'object', 'properties': {'pipeline': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'URI of a pipeline resource')])), ('description', 'The Archivematica instance using this location.')]), 'description': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Human-readable description.')]), 'space': OrderedDict([('type', 'string'), ('format', 'URI of a space resource')]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'True if space can be accessed.')]), 'quota': OrderedDict([('type', 'integer'), ('default', None), ('description', 'Size, in bytes (optional)')]), 'relative_path': OrderedDict([('type', 'string'), ('description', "Path to location, relative to the storage space's path.")]), 'purpose': OrderedDict([('type', 'string'), ('enum', ['AR', 'AS', 'CP', 'DS', 'SD', 'SS', 'BL', 'TS', 'RP']), ('description', 'Purpose of the space. Eg. AIP storage, Transfer source')]), 'replicators': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'URI of a location resource')])), ('description', 'Other locations that will be used to create replicas of the packages stored in this location')])}}), ('NewLocation', OrderedDict([('type', 'object'), ('properties', OrderedDict([('spaces', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'URI of a(n) spaces resource')]))])), ('pipelines', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'URI of a(n) pipelines resource')]))])), ('locations', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'URI of a(n) locations resource')]))]))])), ('required', ['spaces', 'pipelines', 'locations'])])), ('EditALocation', OrderedDict([('type', 'object'), ('properties', OrderedDict([('data', {'$ref': '#/components/schemas/NewLocation'}), ('resource', {'$ref': '#/components/schemas/LocationView'})])), ('required', ['data', 'resource'])])), ('SimpleFilterOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsMasters', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'masters'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsSpace', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['space'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['last_verified', 'used', 'verified', 'uuid', 'access_protocol', 'staging_path', 'size', 'path', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsLocationpipeline_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'locationpipeline_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', [u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsPackage_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'package_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsReplicators', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['replicators'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverLocationsPipeline', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['pipeline'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['api_key', 'uuid', 'enabled', 'api_username', 'remote_name', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('CoordinativeFilterOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('conjunction', OrderedDict([('type', 'string'), ('enum', ['and', 'or'])])), ('complement', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FilterOverLocations'})]))]))])), ('NegativeFilterOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('negation', OrderedDict([('type', 'string'), ('enum', ['not'])])), ('complement', {'$ref': '#/components/schemas/FilterOverLocations'})]))])), ('ArrayFilterOverLocations', OrderedDict([('type', 'array'), ('items', {'oneOf': [{'type': 'string'}, {'type': 'integer'}]})])), ('ObjectFilterOverLocations', {'oneOf': [{'$ref': '#/components/schemas/CoordinativeFilterOverLocations'}, {'$ref': '#/components/schemas/NegativeFilterOverLocations'}, {'$ref': '#/components/schemas/SimpleFilterOverLocations'}, {'$ref': '#/components/schemas/FilterOverLocationsMasters'}, {'$ref': '#/components/schemas/FilterOverLocationsSpace'}, {'$ref': '#/components/schemas/FilterOverLocationsLocationpipeline_set'}, {'$ref': '#/components/schemas/FilterOverLocationsPackage_set'}, {'$ref': '#/components/schemas/FilterOverLocationsReplicators'}, {'$ref': '#/components/schemas/FilterOverLocationsPipeline'}]}), ('FilterOverLocations', {'oneOf': [{'$ref': '#/components/schemas/ObjectFilterOverLocations'}, {'$ref': '#/components/schemas/ArrayFilterOverLocations'}]}), ('SearchQueryOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('filter', {'$ref': '#/components/schemas/FilterOverLocations'}), ('order_by', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))]))]))])), ('required', ['filter'])])), ('SearchOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('query', {'$ref': '#/components/schemas/SearchQueryOverLocations'}), ('paginator', {'$ref': '#/components/schemas/PaginatorSchema'})])), ('required', ['query'])])), ('DataForNewSearchOverLocations', OrderedDict([('type', 'object'), ('properties', OrderedDict([('search_parameters', OrderedDict([('type', 'string')]))])), ('required', ['search_parameters'])])), ('PackageView', {'required': ['current_location', 'current_path', 'package_type', 'related_packages'], 'type': 'object', 'properties': {'size': OrderedDict([('type', 'integer'), ('default', 0), ('description', 'Size in bytes of the package')]), 'status': OrderedDict([('type', 'string'), ('enum', ['PENDING', 'STAGING', 'UPLOADED', 'VERIFIED', 'FAIL', 'DEL_REQ', 'DELETED', 'FINALIZE']), ('default', 'FAIL'), ('description', 'Status of the package in the storage service.')]), 'package_type': OrderedDict([('type', 'string'), ('enum', ['AIP', 'AIC', 'SIP', 'DIP', 'transfer', 'file', 'deposit'])]), u'fixitylog_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'origin_pipeline': OrderedDict([('type', 'string'), ('format', 'uri'), ('nullable', True)]), 'uuid': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Unique identifier')]), u'replicas': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), u'event_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), u'file_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'replicated_package': OrderedDict([('type', 'string'), ('format', 'uri'), ('nullable', True)]), 'misc_attributes': OrderedDict([('type', 'object'), ('nullable', True), ('default', {}), ('description', 'For storing flexible, often Space-specific, attributes')]), 'pointer_file_location': OrderedDict([('type', 'string'), ('format', 'uri'), ('nullable', True)]), 'encryption_key_fingerprint': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'The fingerprint of the GPG key used to encrypt the package, if applicable')]), u'packagedownloadtask_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'current_location': OrderedDict([('type', 'string'), ('format', 'uri')]), 'pointer_file_path': OrderedDict([('type', 'string'), ('nullable', True)]), 'related_packages': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'current_path': OrderedDict([('type', 'string')]), u'id': OrderedDict([('type', 'integer')]), 'description': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Human-readable description.')])}}), ('PaginatedSubsetOfPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('paginator', {'$ref': '#/components/schemas/PaginatorSchema'}), ('items', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/PackageView'})]))])), ('required', ['paginator', 'items'])])), ('SimpleFilterOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesFixitylog_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'fixitylog_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['datetime_reported', 'error_details', u'id', 'success'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesOrigin_pipeline', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['origin_pipeline'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['api_key', 'uuid', 'enabled', 'api_username', 'remote_name', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesReplicas', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'replicas'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesEvent_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'event_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['status', 'user_id', 'event_type', 'store_data', 'status_time', 'status_reason', u'id', 'user_email', 'event_reason'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesFile_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'file_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['ingestion_time', 'accessionid', 'source_package', 'name', 'checksum', 'valid', 'format_name', 'origin', 'stored', 'normalized', 'source_id', 'size', u'id', 'pronom_id', 'uuid'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesReplicated_package', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['replicated_package'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesPointer_file_location', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['pointer_file_location'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesPackagedownloadtask_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'packagedownloadtask_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['uuid', 'download_completion_time', 'downloads_completed', u'id', 'downloads_attempted'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesCurrent_location', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['current_location'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPackagesRelated_packages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['related_packages'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('CoordinativeFilterOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('conjunction', OrderedDict([('type', 'string'), ('enum', ['and', 'or'])])), ('complement', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FilterOverPackages'})]))]))])), ('NegativeFilterOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('negation', OrderedDict([('type', 'string'), ('enum', ['not'])])), ('complement', {'$ref': '#/components/schemas/FilterOverPackages'})]))])), ('ArrayFilterOverPackages', OrderedDict([('type', 'array'), ('items', {'oneOf': [{'type': 'string'}, {'type': 'integer'}]})])), ('ObjectFilterOverPackages', {'oneOf': [{'$ref': '#/components/schemas/CoordinativeFilterOverPackages'}, {'$ref': '#/components/schemas/NegativeFilterOverPackages'}, {'$ref': '#/components/schemas/SimpleFilterOverPackages'}, {'$ref': '#/components/schemas/FilterOverPackagesFixitylog_set'}, {'$ref': '#/components/schemas/FilterOverPackagesOrigin_pipeline'}, {'$ref': '#/components/schemas/FilterOverPackagesReplicas'}, {'$ref': '#/components/schemas/FilterOverPackagesEvent_set'}, {'$ref': '#/components/schemas/FilterOverPackagesFile_set'}, {'$ref': '#/components/schemas/FilterOverPackagesReplicated_package'}, {'$ref': '#/components/schemas/FilterOverPackagesPointer_file_location'}, {'$ref': '#/components/schemas/FilterOverPackagesPackagedownloadtask_set'}, {'$ref': '#/components/schemas/FilterOverPackagesCurrent_location'}, {'$ref': '#/components/schemas/FilterOverPackagesRelated_packages'}]}), ('FilterOverPackages', {'oneOf': [{'$ref': '#/components/schemas/ObjectFilterOverPackages'}, {'$ref': '#/components/schemas/ArrayFilterOverPackages'}]}), ('SearchQueryOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('filter', {'$ref': '#/components/schemas/FilterOverPackages'}), ('order_by', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))]))]))])), ('required', ['filter'])])), ('SearchOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('query', {'$ref': '#/components/schemas/SearchQueryOverPackages'}), ('paginator', {'$ref': '#/components/schemas/PaginatorSchema'})])), ('required', ['query'])])), ('DataForNewSearchOverPackages', OrderedDict([('type', 'object'), ('properties', OrderedDict([('search_parameters', OrderedDict([('type', 'string')]))])), ('required', ['search_parameters'])])), ('PipelineView', {'required': ['uuid'], 'type': 'object', 'properties': {'api_key': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'API key to use when making API calls to the pipeline.')]), 'uuid': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Identifier for the Archivematica pipeline')]), u'event_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), u'locationpipeline_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'Enabled if this pipeline is able to access the storage service.')]), u'package_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'location': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), 'api_username': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Username to use when making API calls to the pipeline.')]), 'remote_name': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Host or IP address of the pipeline server for making API calls.')]), u'id': OrderedDict([('type', 'integer')]), 'description': OrderedDict([('type', 'string'), ('nullable', True), ('default', None), ('description', 'Human readable description of the Archivematica instance.')])}}), ('PaginatedSubsetOfPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('paginator', {'$ref': '#/components/schemas/PaginatorSchema'}), ('items', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/PipelineView'})]))])), ('required', ['paginator', 'items'])])), ('PipelineCreate', {'type': 'object', 'properties': {'api_key': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'API key to use when making API calls to the pipeline.')]), 'remote_name': OrderedDict([('anyOf', [OrderedDict([('type', 'string'), ('format', 'ipv4')]), OrderedDict([('type', 'string'), ('format', 'uri')])]), ('default', None), ('description', 'Host or IP address of the pipeline server for making API calls.')]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'Enabled if this pipeline is able to access the storage service.')]), 'description': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Human readable description of the Archivematica instance.')]), 'api_username': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Username to use when making API calls to the pipeline.')])}}), ('PipelineUpdate', {'type': 'object', 'properties': {'api_key': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'API key to use when making API calls to the pipeline.')]), 'remote_name': OrderedDict([('anyOf', [OrderedDict([('type', 'string'), ('format', 'ipv4')]), OrderedDict([('type', 'string'), ('format', 'uri')])]), ('default', None), ('description', 'Host or IP address of the pipeline server for making API calls.')]), 'enabled': OrderedDict([('type', 'boolean'), ('default', True), ('description', 'Enabled if this pipeline is able to access the storage service.')]), 'description': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Human readable description of the Archivematica instance.')]), 'api_username': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', None), ('description', 'Username to use when making API calls to the pipeline.')])}}), ('NewPipeline', OrderedDict([('type', 'object'), ('properties', OrderedDict()), ('required', [])])), ('EditAPipeline', OrderedDict([('type', 'object'), ('properties', OrderedDict([('data', {'$ref': '#/components/schemas/NewPipeline'}), ('resource', {'$ref': '#/components/schemas/PipelineView'})])), ('required', ['data', 'resource'])])), ('SimpleFilterOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['api_key', 'uuid', 'enabled', 'api_username', 'remote_name', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPipelinesEvent_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'event_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['status', 'user_id', 'event_type', 'store_data', 'status_time', 'status_reason', u'id', 'user_email', 'event_reason'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPipelinesLocationpipeline_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'locationpipeline_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', [u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPipelinesPackage_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'package_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['size', 'status', 'package_type', 'uuid', 'misc_attributes', 'encryption_key_fingerprint', 'pointer_file_path', 'current_path', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverPipelinesLocation', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['location'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('CoordinativeFilterOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('conjunction', OrderedDict([('type', 'string'), ('enum', ['and', 'or'])])), ('complement', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FilterOverPipelines'})]))]))])), ('NegativeFilterOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('negation', OrderedDict([('type', 'string'), ('enum', ['not'])])), ('complement', {'$ref': '#/components/schemas/FilterOverPipelines'})]))])), ('ArrayFilterOverPipelines', OrderedDict([('type', 'array'), ('items', {'oneOf': [{'type': 'string'}, {'type': 'integer'}]})])), ('ObjectFilterOverPipelines', {'oneOf': [{'$ref': '#/components/schemas/CoordinativeFilterOverPipelines'}, {'$ref': '#/components/schemas/NegativeFilterOverPipelines'}, {'$ref': '#/components/schemas/SimpleFilterOverPipelines'}, {'$ref': '#/components/schemas/FilterOverPipelinesEvent_set'}, {'$ref': '#/components/schemas/FilterOverPipelinesLocationpipeline_set'}, {'$ref': '#/components/schemas/FilterOverPipelinesPackage_set'}, {'$ref': '#/components/schemas/FilterOverPipelinesLocation'}]}), ('FilterOverPipelines', {'oneOf': [{'$ref': '#/components/schemas/ObjectFilterOverPipelines'}, {'$ref': '#/components/schemas/ArrayFilterOverPipelines'}]}), ('SearchQueryOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('filter', {'$ref': '#/components/schemas/FilterOverPipelines'}), ('order_by', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))]))]))])), ('required', ['filter'])])), ('SearchOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('query', {'$ref': '#/components/schemas/SearchQueryOverPipelines'}), ('paginator', {'$ref': '#/components/schemas/PaginatorSchema'})])), ('required', ['query'])])), ('DataForNewSearchOverPipelines', OrderedDict([('type', 'object'), ('properties', OrderedDict([('search_parameters', OrderedDict([('type', 'string')]))])), ('required', ['search_parameters'])])), ('SpaceView', {'required': ['access_protocol', 'staging_path'], 'type': 'object', 'properties': {u'duracloud': OrderedDict([('type', 'string'), ('format', 'uri')]), u'lockssomatic': OrderedDict([('type', 'string'), ('format', 'uri')]), 'last_verified': OrderedDict([('type', 'string'), ('format', 'date-time'), ('nullable', True), ('default', None), ('description', 'Time this location was last verified to be accessible.')]), 'used': OrderedDict([('type', 'integer'), ('default', 0), ('description', 'Amount used in bytes')]), 'verified': OrderedDict([('type', 'boolean'), ('default', False), ('description', 'Whether or not the space has been verified to be accessible.')]), u'fedora': OrderedDict([('type', 'string'), ('format', 'uri')]), u'gpg': OrderedDict([('type', 'string'), ('format', 'uri')]), 'uuid': OrderedDict([('type', 'string'), ('format', 'uuid'), ('description', 'Unique identifier')]), 'access_protocol': OrderedDict([('type', 'string'), ('enum', ['ARKIVUM', 'DV', 'DC', 'DSPACE', 'FEDORA', 'GPG', 'FS', 'LOM', 'NFS', 'PIPE_FS', 'SWIFT']), ('description', 'How the space can be accessed.')]), 'staging_path': OrderedDict([('type', 'string'), ('description', 'Absolute path to a staging area. Must be UNIX filesystem compatible, preferably on the same filesystem as the path.')]), u'dspace': OrderedDict([('type', 'string'), ('format', 'uri')]), u'nfs': OrderedDict([('type', 'string'), ('format', 'uri')]), u'arkivum': OrderedDict([('type', 'string'), ('format', 'uri')]), 'size': OrderedDict([('type', 'integer'), ('nullable', True), ('default', None), ('description', 'Size in bytes (optional)')]), u'dataverse': OrderedDict([('type', 'string'), ('format', 'uri')]), 'path': OrderedDict([('type', 'string'), ('default', ''), ('description', 'Absolute path to the space on the storage service machine.')]), u'location_set': OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string'), ('format', 'uri')]))]), u'localfilesystem': OrderedDict([('type', 'string'), ('format', 'uri')]), u'swift': OrderedDict([('type', 'string'), ('format', 'uri')]), u'id': OrderedDict([('type', 'integer')]), u'pipelinelocalfs': OrderedDict([('type', 'string'), ('format', 'uri')])}}), ('PaginatedSubsetOfSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('paginator', {'$ref': '#/components/schemas/PaginatorSchema'}), ('items', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/SpaceView'})]))])), ('required', ['paginator', 'items'])])), ('SpaceCreate', {'required': ['staging_path', 'access_protocol'], 'type': 'object', 'properties': {'path': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', ''), ('description', 'Absolute path to the space on the storage service machine.')]), 'size': OrderedDict([('type', 'integer'), ('default', None), ('description', 'Size in bytes (optional)')]), 'access_protocol': OrderedDict([('type', 'string'), ('enum', ['ARKIVUM', 'DV', 'DC', 'DSPACE', 'FEDORA', 'GPG', 'FS', 'LOM', 'NFS', 'PIPE_FS', 'SWIFT']), ('description', 'How the space can be accessed.')]), 'staging_path': OrderedDict([('type', 'string'), ('maxLength', 256), ('description', 'Absolute path to a staging area. Must be UNIX filesystem compatible, preferably on the same filesystem as the path.')])}}), ('SpaceUpdate', {'required': ['staging_path'], 'type': 'object', 'properties': {'path': OrderedDict([('type', 'string'), ('maxLength', 256), ('default', ''), ('description', 'Absolute path to the space on the storage service machine.')]), 'staging_path': OrderedDict([('type', 'string'), ('maxLength', 256), ('description', 'Absolute path to a staging area. Must be UNIX filesystem compatible, preferably on the same filesystem as the path.')]), 'size': OrderedDict([('type', 'integer'), ('default', None), ('description', 'Size in bytes (optional)')])}}), ('NewSpace', OrderedDict([('type', 'object'), ('properties', OrderedDict()), ('required', [])])), ('EditASpace', OrderedDict([('type', 'object'), ('properties', OrderedDict([('data', {'$ref': '#/components/schemas/NewSpace'}), ('resource', {'$ref': '#/components/schemas/SpaceView'})])), ('required', ['data', 'resource'])])), ('SimpleFilterOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', ['last_verified', 'used', 'verified', 'uuid', 'access_protocol', 'staging_path', 'size', 'path', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesDuracloud', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'duracloud'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['duraspace', 'space', 'host', 'user', 'password', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesLockssomatic', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'lockssomatic'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['collection_iri', 'external_domain', 'space', 'content_provider_id', 'sd_iri', u'id', 'checksum_type', 'au_size', 'keep_local'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesFedora', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'fedora'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['fedora_name', 'fedora_password', 'fedora_user', u'id', 'space'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesGpg', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'gpg'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', [u'id', 'key', 'space'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesDspace', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'dspace'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['space', 'sd_iri', 'metadata_policy', 'user', 'archive_format', 'password', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesNfs', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'nfs'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['manually_mounted', 'space', 'remote_path', 'version', 'remote_name', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesArkivum', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'arkivum'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['host', 'remote_user', 'remote_name', u'id', 'space'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesDataverse', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'dataverse'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['agent_name', 'agent_identifier', 'space', 'host', 'agent_type', 'api_key', u'id'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesLocation_set', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'location_set'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['used', 'uuid', 'enabled', 'quota', 'relative_path', 'purpose', u'id', 'description'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesLocalfilesystem', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'localfilesystem'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', [u'id', 'space'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesSwift', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'swift'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['username', 'container', 'space', 'region', 'auth_version', 'auth_url', 'password', u'id', 'tenant'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('FilterOverSpacesPipelinelocalfs', OrderedDict([('type', 'object'), ('properties', OrderedDict([('attribute', OrderedDict([('type', 'string'), ('enum', [u'pipelinelocalfs'])])), ('subattribute', OrderedDict([('type', 'string'), ('enum', ['remote_user', 'space', 'assume_rsync_daemon', 'remote_name', u'id', 'rsync_password'])])), ('relation', OrderedDict([('type', 'string'), ('enum', ['regex', 'gt', 'like', '!=', '=', 'contains', 'ne', '<=', 'lt', '>=', 'lte', 'in', 'regexp', 'exact', '<', 'gte', '>'])])), ('value', {'anyOf': [{'type': 'string'}, {'type': 'number'}, {'type': 'boolean'}]})]))])), ('CoordinativeFilterOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('conjunction', OrderedDict([('type', 'string'), ('enum', ['and', 'or'])])), ('complement', OrderedDict([('type', 'array'), ('items', {'$ref': '#/components/schemas/FilterOverSpaces'})]))]))])), ('NegativeFilterOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('negation', OrderedDict([('type', 'string'), ('enum', ['not'])])), ('complement', {'$ref': '#/components/schemas/FilterOverSpaces'})]))])), ('ArrayFilterOverSpaces', OrderedDict([('type', 'array'), ('items', {'oneOf': [{'type': 'string'}, {'type': 'integer'}]})])), ('ObjectFilterOverSpaces', {'oneOf': [{'$ref': '#/components/schemas/CoordinativeFilterOverSpaces'}, {'$ref': '#/components/schemas/NegativeFilterOverSpaces'}, {'$ref': '#/components/schemas/SimpleFilterOverSpaces'}, {'$ref': '#/components/schemas/FilterOverSpacesDuracloud'}, {'$ref': '#/components/schemas/FilterOverSpacesLockssomatic'}, {'$ref': '#/components/schemas/FilterOverSpacesFedora'}, {'$ref': '#/components/schemas/FilterOverSpacesGpg'}, {'$ref': '#/components/schemas/FilterOverSpacesDspace'}, {'$ref': '#/components/schemas/FilterOverSpacesNfs'}, {'$ref': '#/components/schemas/FilterOverSpacesArkivum'}, {'$ref': '#/components/schemas/FilterOverSpacesDataverse'}, {'$ref': '#/components/schemas/FilterOverSpacesLocation_set'}, {'$ref': '#/components/schemas/FilterOverSpacesLocalfilesystem'}, {'$ref': '#/components/schemas/FilterOverSpacesSwift'}, {'$ref': '#/components/schemas/FilterOverSpacesPipelinelocalfs'}]}), ('FilterOverSpaces', {'oneOf': [{'$ref': '#/components/schemas/ObjectFilterOverSpaces'}, {'$ref': '#/components/schemas/ArrayFilterOverSpaces'}]}), ('SearchQueryOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('filter', {'$ref': '#/components/schemas/FilterOverSpaces'}), ('order_by', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'array'), ('items', OrderedDict([('type', 'string')]))]))]))])), ('required', ['filter'])])), ('SearchOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('query', {'$ref': '#/components/schemas/SearchQueryOverSpaces'}), ('paginator', {'$ref': '#/components/schemas/PaginatorSchema'})])), ('required', ['query'])])), ('DataForNewSearchOverSpaces', OrderedDict([('type', 'object'), ('properties', OrderedDict([('search_parameters', OrderedDict([('type', 'string')]))])), ('required', ['search_parameters'])]))]))])), ('paths', {'/files/': {'search': OrderedDict([('summary', 'Search over all files.'), ('description', 'Search over all files.'), ('operationId', 'search.file'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all files'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverFiles'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all files succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfFiles')]))]))]))])), ('400', OrderedDict([('description', 'Search across all files failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['files'])]), 'get': OrderedDict([('summary', 'View all files.'), ('description', 'View all files.'), ('operationId', 'get_many.file'), ('parameters', [{'$ref': '#/components/parameters/items_per_page'}, {'$ref': '#/components/parameters/page'}, {'$ref': '#/components/parameters/order_by_attribute'}, {'$ref': '#/components/parameters/order_by_subattribute'}, {'$ref': '#/components/parameters/order_by_direction'}]), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a collection of files succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfFiles')]))]))]))])), ('400', OrderedDict([('description', 'Request for a collection of files failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['files'])])}, '/packages/new_search/': {'get': OrderedDict([('summary', 'Get the data needed to search over all packages.'), ('description', 'Get the data needed to search over all packages.'), ('operationId', 'new_search.package'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request to get the data needed to search across all packages succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/DataForNewSearchOverPackages')]))]))]))]))])), ('tags', ['packages'])])}, '/locations/{pk}/edit/': {'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the location.')])], 'get': OrderedDict([('summary', 'Get the data needed to update an existing location.'), ('description', 'Get the data needed to update an existing location.'), ('operationId', 'data_for_edit.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to edit a(n) location resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditALocation')]))]))]))])), ('404', OrderedDict([('description', 'Request for the data needed to edit a(n) location failed because there is no location resource with the specified pk'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for the data needed to edit a(n) location failed because the user is forbidden from editing this location resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])])}, '/pipelines/{pk}/': {'put': OrderedDict([('summary', 'Update an existing pipeline.'), ('description', 'Update an existing pipeline.'), ('operationId', 'update.pipeline'), ('requestBody', OrderedDict([('description', 'JSON object required to update an existing pipeline'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/PipelineUpdate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Updating of an existing pipeline resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditAPipeline')]))]))]))])), ('404', OrderedDict([('description', 'Updating of an existing pipeline resource failed because there is no pipeline with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Updating of an existing pipeline resource failed because the user is forbidden from updating this pipeline resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('400', OrderedDict([('description', 'Updating of an existing pipeline resource failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])]), 'get': OrderedDict([('summary', 'View an existing pipeline.'), ('description', 'View an existing pipeline.'), ('operationId', 'get.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a single pipeline succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PipelineView')]))]))]))])), ('404', OrderedDict([('description', 'Request for a single pipeline failed because there is no pipeline resource with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for a single pipeline failed because the user is forbidden from viewing this pipeline resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])]), 'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the pipeline.')])], 'delete': OrderedDict([('summary', 'Delete an existing pipeline.'), ('description', 'Delete an existing pipeline.'), ('operationId', 'delete.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Deletion of the pipeline resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PipelineView')]))]))]))])), ('404', OrderedDict([('description', 'Deletion of the pipeline resource failed because there is no pipeline with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Deletion of the pipeline resource failed because user is forbidden from performing this action'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])])}, '/spaces/new/': {'get': OrderedDict([('summary', 'Get the data needed to create a new space.'), ('description', 'Get the data needed to create a new space.'), ('operationId', 'data_for_new.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to create a new space resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/NewSpace')]))]))]))]))])), ('tags', ['spaces'])])}, '/spaces/': {'post': OrderedDict([('summary', 'Create a new space.'), ('description', 'Create a new space.'), ('operationId', 'create.space'), ('requestBody', OrderedDict([('description', 'JSON object required to create a new space'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/SpaceCreate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Creation of a new space succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/SpaceView')]))]))]))])), ('400', OrderedDict([('description', 'Creation of a new space failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])]), 'search': OrderedDict([('summary', 'Search over all spaces.'), ('description', 'Search over all spaces.'), ('operationId', 'search.space'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all spaces'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverSpaces'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all spaces succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfSpaces')]))]))]))])), ('400', OrderedDict([('description', 'Search across all spaces failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])]), 'get': OrderedDict([('summary', 'View all spaces.'), ('description', 'View all spaces.'), ('operationId', 'get_many.space'), ('parameters', [{'$ref': '#/components/parameters/items_per_page'}, {'$ref': '#/components/parameters/page'}, {'$ref': '#/components/parameters/order_by_attribute'}, {'$ref': '#/components/parameters/order_by_subattribute'}, {'$ref': '#/components/parameters/order_by_direction'}]), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a collection of spaces succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfSpaces')]))]))]))])), ('400', OrderedDict([('description', 'Request for a collection of spaces failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])])}, '/pipelines/search/': {'post': OrderedDict([('summary', 'Search over all pipelines.'), ('description', 'Search over all pipelines.'), ('operationId', 'search.pipeline'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all pipelines'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverPipelines'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all pipelines succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPipelines')]))]))]))])), ('400', OrderedDict([('description', 'Search across all pipelines failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])])}, '/locations/new/': {'get': OrderedDict([('summary', 'Get the data needed to create a new location.'), ('description', 'Get the data needed to create a new location.'), ('operationId', 'data_for_new.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to create a new location resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/NewLocation')]))]))]))]))])), ('tags', ['locations'])])}, '/files/new_search/': {'get': OrderedDict([('summary', 'Get the data needed to search over all files.'), ('description', 'Get the data needed to search over all files.'), ('operationId', 'new_search.file'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request to get the data needed to search across all files succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/DataForNewSearchOverFiles')]))]))]))]))])), ('tags', ['files'])])}, '/spaces/{pk}/edit/': {'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the space.')])], 'get': OrderedDict([('summary', 'Get the data needed to update an existing space.'), ('description', 'Get the data needed to update an existing space.'), ('operationId', 'data_for_edit.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to edit a(n) space resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditASpace')]))]))]))])), ('404', OrderedDict([('description', 'Request for the data needed to edit a(n) space failed because there is no space resource with the specified pk'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for the data needed to edit a(n) space failed because the user is forbidden from editing this space resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])])}, '/files/search/': {'post': OrderedDict([('summary', 'Search over all files.'), ('description', 'Search over all files.'), ('operationId', 'search.file'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all files'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverFiles'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all files succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfFiles')]))]))]))])), ('400', OrderedDict([('description', 'Search across all files failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['files'])])}, '/pipelines/{pk}/edit/': {'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the pipeline.')])], 'get': OrderedDict([('summary', 'Get the data needed to update an existing pipeline.'), ('description', 'Get the data needed to update an existing pipeline.'), ('operationId', 'data_for_edit.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to edit a(n) pipeline resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditAPipeline')]))]))]))])), ('404', OrderedDict([('description', 'Request for the data needed to edit a(n) pipeline failed because there is no pipeline resource with the specified pk'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for the data needed to edit a(n) pipeline failed because the user is forbidden from editing this pipeline resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])])}, '/spaces/{pk}/': {'put': OrderedDict([('summary', 'Update an existing space.'), ('description', 'Update an existing space.'), ('operationId', 'update.space'), ('requestBody', OrderedDict([('description', 'JSON object required to update an existing space'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/SpaceUpdate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Updating of an existing space resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditASpace')]))]))]))])), ('404', OrderedDict([('description', 'Updating of an existing space resource failed because there is no space with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Updating of an existing space resource failed because the user is forbidden from updating this space resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('400', OrderedDict([('description', 'Updating of an existing space resource failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])]), 'get': OrderedDict([('summary', 'View an existing space.'), ('description', 'View an existing space.'), ('operationId', 'get.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a single space succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/SpaceView')]))]))]))])), ('404', OrderedDict([('description', 'Request for a single space failed because there is no space resource with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for a single space failed because the user is forbidden from viewing this space resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])]), 'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the space.')])], 'delete': OrderedDict([('summary', 'Delete an existing space.'), ('description', 'Delete an existing space.'), ('operationId', 'delete.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Deletion of the space resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/SpaceView')]))]))]))])), ('404', OrderedDict([('description', 'Deletion of the space resource failed because there is no space with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Deletion of the space resource failed because user is forbidden from performing this action'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])])}, '/locations/': {'post': OrderedDict([('summary', 'Create a new location.'), ('description', 'Create a new location.'), ('operationId', 'create.location'), ('requestBody', OrderedDict([('description', 'JSON object required to create a new location'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/LocationCreate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Creation of a new location succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/LocationView')]))]))]))])), ('400', OrderedDict([('description', 'Creation of a new location failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])]), 'search': OrderedDict([('summary', 'Search over all locations.'), ('description', 'Search over all locations.'), ('operationId', 'search.location'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all locations'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverLocations'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all locations succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfLocations')]))]))]))])), ('400', OrderedDict([('description', 'Search across all locations failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])]), 'get': OrderedDict([('summary', 'View all locations.'), ('description', 'View all locations.'), ('operationId', 'get_many.location'), ('parameters', [{'$ref': '#/components/parameters/items_per_page'}, {'$ref': '#/components/parameters/page'}, {'$ref': '#/components/parameters/order_by_attribute'}, {'$ref': '#/components/parameters/order_by_subattribute'}, {'$ref': '#/components/parameters/order_by_direction'}]), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a collection of locations succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfLocations')]))]))]))])), ('400', OrderedDict([('description', 'Request for a collection of locations failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])])}, '/files/{pk}/': {'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the file.')])], 'get': OrderedDict([('summary', 'View an existing file.'), ('description', 'View an existing file.'), ('operationId', 'get.file'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a single file succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/FileView')]))]))]))])), ('404', OrderedDict([('description', 'Request for a single file failed because there is no file resource with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for a single file failed because the user is forbidden from viewing this file resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['files'])])}, '/locations/search/': {'post': OrderedDict([('summary', 'Search over all locations.'), ('description', 'Search over all locations.'), ('operationId', 'search.location'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all locations'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverLocations'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all locations succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfLocations')]))]))]))])), ('400', OrderedDict([('description', 'Search across all locations failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])])}, '/pipelines/new_search/': {'get': OrderedDict([('summary', 'Get the data needed to search over all pipelines.'), ('description', 'Get the data needed to search over all pipelines.'), ('operationId', 'new_search.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request to get the data needed to search across all pipelines succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/DataForNewSearchOverPipelines')]))]))]))]))])), ('tags', ['pipelines'])])}, '/spaces/new_search/': {'get': OrderedDict([('summary', 'Get the data needed to search over all spaces.'), ('description', 'Get the data needed to search over all spaces.'), ('operationId', 'new_search.space'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request to get the data needed to search across all spaces succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/DataForNewSearchOverSpaces')]))]))]))]))])), ('tags', ['spaces'])])}, '/spaces/search/': {'post': OrderedDict([('summary', 'Search over all spaces.'), ('description', 'Search over all spaces.'), ('operationId', 'search.space'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all spaces'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverSpaces'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all spaces succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfSpaces')]))]))]))])), ('400', OrderedDict([('description', 'Search across all spaces failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['spaces'])])}, '/packages/search/': {'post': OrderedDict([('summary', 'Search over all packages.'), ('description', 'Search over all packages.'), ('operationId', 'search.package'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all packages'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverPackages'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all packages succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPackages')]))]))]))])), ('400', OrderedDict([('description', 'Search across all packages failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['packages'])])}, '/pipelines/new/': {'get': OrderedDict([('summary', 'Get the data needed to create a new pipeline.'), ('description', 'Get the data needed to create a new pipeline.'), ('operationId', 'data_for_new.pipeline'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for the data needed to create a new pipeline resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/NewPipeline')]))]))]))]))])), ('tags', ['pipelines'])])}, '/locations/new_search/': {'get': OrderedDict([('summary', 'Get the data needed to search over all locations.'), ('description', 'Get the data needed to search over all locations.'), ('operationId', 'new_search.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request to get the data needed to search across all locations succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/DataForNewSearchOverLocations')]))]))]))]))])), ('tags', ['locations'])])}, '/pipelines/': {'post': OrderedDict([('summary', 'Create a new pipeline.'), ('description', 'Create a new pipeline.'), ('operationId', 'create.pipeline'), ('requestBody', OrderedDict([('description', 'JSON object required to create a new pipeline'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/PipelineCreate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Creation of a new pipeline succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PipelineView')]))]))]))])), ('400', OrderedDict([('description', 'Creation of a new pipeline failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])]), 'search': OrderedDict([('summary', 'Search over all pipelines.'), ('description', 'Search over all pipelines.'), ('operationId', 'search.pipeline'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all pipelines'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverPipelines'})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all pipelines succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPipelines')]))]))]))])), ('400', OrderedDict([('description', 'Search across all pipelines failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])]), 'get': OrderedDict([('summary', 'View all pipelines.'), ('description', 'View all pipelines.'), ('operationId', 'get_many.pipeline'), ('parameters', [{'$ref': '#/components/parameters/items_per_page'}, {'$ref': '#/components/parameters/page'}, {'$ref': '#/components/parameters/order_by_attribute'}, {'$ref': '#/components/parameters/order_by_subattribute'}, {'$ref': '#/components/parameters/order_by_direction'}]), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a collection of pipelines succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPipelines')]))]))]))])), ('400', OrderedDict([('description', 'Request for a collection of pipelines failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['pipelines'])])}, '/packages/{pk}/': {'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the package.')])], 'get': OrderedDict([('summary', 'View an existing package.'), ('description', 'View an existing package.'), ('operationId', 'get.package'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a single package succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PackageView')]))]))]))])), ('404', OrderedDict([('description', 'Request for a single package failed because there is no package resource with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for a single package failed because the user is forbidden from viewing this package resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['packages'])])}, '/packages/': {'search': OrderedDict([('summary', 'Search over all packages.'), ('description', 'Search over all packages.'), ('operationId', 'search.package'), ('requestBody', OrderedDict([('description', 'JSON object required to search over all packages'), ('required', True), ('content', {'application/json': OrderedDict([('schema', {'$ref': '#/components/schemas/SearchOverPackages'}), ('example', {'ObjectSearchOverPackagesExample': {'paginator': {'items_per_page': 10, 'page': 1}, 'query': {'filter': {'complement': [{'attribute': 'description', 'relation': 'like', 'value': '%a%'}, {'complement': {'attribute': 'description', 'relation': 'like', 'value': 'T%'}, 'negation': 'not'}, {'complement': [{'attribute': 'size', 'relation': '<', 'value': 1000}, {'attribute': 'size', 'relation': '>', 'value': 512}], 'conjunction': 'or'}], 'conjunction': 'and'}}}, 'ArraySearchOverPackagesExample': {'paginator': {'items_per_page': 10, 'page': 1}, 'query': {'filter': ['and', [['description', 'like', '%a%'], ['not', ['description', 'like', 'T%']], ['or', [['size', '<', 1000], ['size', '>', 512]]]]]}}})])})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Search across all packages succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPackages')]))]))]))])), ('400', OrderedDict([('description', 'Search across all packages failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['packages'])]), 'get': OrderedDict([('summary', 'View all packages.'), ('description', 'View all packages.'), ('operationId', 'get_many.package'), ('parameters', [{'$ref': '#/components/parameters/items_per_page'}, {'$ref': '#/components/parameters/page'}, {'$ref': '#/components/parameters/order_by_attribute'}, {'$ref': '#/components/parameters/order_by_subattribute'}, {'$ref': '#/components/parameters/order_by_direction'}]), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a collection of packages succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/PaginatedSubsetOfPackages')]))]))]))])), ('400', OrderedDict([('description', 'Request for a collection of packages failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['packages'])])}, '/locations/{pk}/': {'put': OrderedDict([('summary', 'Update an existing location.'), ('description', 'Update an existing location.'), ('operationId', 'update.location'), ('requestBody', OrderedDict([('description', 'JSON object required to update an existing location'), ('required', True), ('content', {'application/json': {'schema': {'$ref': '#/components/schemas/LocationUpdate'}}})])), ('responses', OrderedDict([('200', OrderedDict([('description', 'Updating of an existing location resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/EditALocation')]))]))]))])), ('404', OrderedDict([('description', 'Updating of an existing location resource failed because there is no location with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Updating of an existing location resource failed because the user is forbidden from updating this location resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('400', OrderedDict([('description', 'Updating of an existing location resource failed.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])]), 'get': OrderedDict([('summary', 'View an existing location.'), ('description', 'View an existing location.'), ('operationId', 'get.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Request for a single location succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/LocationView')]))]))]))])), ('404', OrderedDict([('description', 'Request for a single location failed because there is no location resource with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Request for a single location failed because the user is forbidden from viewing this location resource.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])]), 'parameters': [OrderedDict([('in', 'path'), ('name', 'pk'), ('required', True), ('schema', OrderedDict([('type', 'string'), ('format', 'uuid')])), ('description', 'The primary key of the location.')])], 'delete': OrderedDict([('summary', 'Delete an existing location.'), ('description', 'Delete an existing location.'), ('operationId', 'delete.location'), ('responses', OrderedDict([('200', OrderedDict([('description', 'Deletion of the location resource succeeded.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/LocationView')]))]))]))])), ('404', OrderedDict([('description', 'Deletion of the location resource failed because there is no location with the specified pk.'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))])), ('403', OrderedDict([('description', 'Deletion of the location resource failed because user is forbidden from performing this action'), ('content', OrderedDict([('application/json', OrderedDict([('schema', OrderedDict([('$ref', '#/components/schemas/ErrorSchema')]))]))]))]))])), ('tags', ['locations'])])}}), ('tags', [OrderedDict([('name', 'files'), ('description', 'Access to the File resource')]), OrderedDict([('name', 'locations'), ('description', 'Access to the Location resource')]), OrderedDict([('name', 'packages'), ('description', 'Access to the Package resource')]), OrderedDict([('name', 'pipelines'), ('description', 'Access to the Pipeline resource')]), OrderedDict([('name', 'spaces'), ('description', 'Access to the Space resource')])])]) ) HTTP_METHODS = ('get', 'delete', 'post', 'put') @@ -300,6 +300,10 @@ def get_param_docstring_line(arg, arg_cfg): if arg_type: _, arg_type = openapitype2pythontype.get(arg_type, (None, arg_type)) arg_format = arg_cfg.get('format', arg_cfg.get('schema', {}).get('format')) + if (not arg_format) and arg_type == 'list': + arg_format = arg_cfg.get('items', {}).get('format') + if arg_format: + arg_format = 'each element is a {}'.format(arg_format) if arg_format: arg_line.append(' ({}; {}):'.format(arg_type, arg_format)) else: diff --git a/storage_service/static/openapi/openapispecs/storage-service-0.11.0-openapi-3.0.0.yml b/storage_service/static/openapi/openapispecs/storage-service-0.11.0-openapi-3.0.0.yml index c051311fd..16e9c9895 100644 --- a/storage_service/static/openapi/openapispecs/storage-service-0.11.0-openapi-3.0.0.yml +++ b/storage_service/static/openapi/openapispecs/storage-service-0.11.0-openapi-3.0.0.yml @@ -86,6 +86,229 @@ components: required: - page - items_per_page + FileView: + properties: + accessionid: + type: string + description: Accession ID of originating transfer + checksum: + type: string + format_name: + type: string + id: + type: integer + ingestion_time: + type: string + format: date-time + nullable: true + name: + type: string + normalized: + type: boolean + default: false + description: Whether or not file has been normalized + origin: + type: string + format: uuid + description: Unique identifier of originating Archivematica dashboard + package: + type: string + format: uri + nullable: true + pronom_id: + type: string + size: + type: integer + default: 0 + description: Size in bytes of the file + source_id: + type: string + source_package: + type: string + description: Unique identifier of originating unit + stored: + type: boolean + default: false + uuid: + type: string + format: uuid + description: Unique identifier + required: + - package + - name + - ingestion_time + - source_id + - checksum + type: object + PaginatedSubsetOfFiles: + type: object + properties: + paginator: + $ref: '#/components/schemas/PaginatorSchema' + items: + type: array + items: + $ref: '#/components/schemas/FileView' + required: + - paginator + - items + SimpleFilterOverFiles: + type: object + properties: + attribute: + type: string + enum: + - ingestion_time + - accessionid + - source_package + - name + - checksum + - valid + - format_name + - origin + - stored + - normalized + - source_id + - size + - id + - pronom_id + - uuid + relation: + type: string + enum: + - regex + - gt + - like + - '!=' + - '=' + - contains + - ne + - <= + - lt + - '>=' + - lte + - in + - regexp + - exact + - < + - gte + - '>' + value: + anyOf: + - type: string + - type: number + - type: boolean + FilterOverFilesPackage: + type: object + properties: + attribute: + type: string + enum: + - package + subattribute: + type: string + enum: + - size + - status + - package_type + - uuid + - misc_attributes + - encryption_key_fingerprint + - pointer_file_path + - current_path + - id + - description + relation: + type: string + enum: + - regex + - gt + - like + - '!=' + - '=' + - contains + - ne + - <= + - lt + - '>=' + - lte + - in + - regexp + - exact + - < + - gte + - '>' + value: + anyOf: + - type: string + - type: number + - type: boolean + CoordinativeFilterOverFiles: + type: object + properties: + conjunction: + type: string + enum: + - and + - or + complement: + type: array + items: + $ref: '#/components/schemas/FilterOverFiles' + NegativeFilterOverFiles: + type: object + properties: + negation: + type: string + enum: + - not + complement: + $ref: '#/components/schemas/FilterOverFiles' + ArrayFilterOverFiles: + type: array + items: + oneOf: + - type: string + - type: integer + ObjectFilterOverFiles: + oneOf: + - $ref: '#/components/schemas/CoordinativeFilterOverFiles' + - $ref: '#/components/schemas/NegativeFilterOverFiles' + - $ref: '#/components/schemas/SimpleFilterOverFiles' + - $ref: '#/components/schemas/FilterOverFilesPackage' + FilterOverFiles: + oneOf: + - $ref: '#/components/schemas/ObjectFilterOverFiles' + - $ref: '#/components/schemas/ArrayFilterOverFiles' + SearchQueryOverFiles: + type: object + properties: + filter: + $ref: '#/components/schemas/FilterOverFiles' + order_by: + type: array + items: + type: array + items: + type: string + required: + - filter + SearchOverFiles: + type: object + properties: + query: + $ref: '#/components/schemas/SearchQueryOverFiles' + paginator: + $ref: '#/components/schemas/PaginatorSchema' + required: + - query + DataForNewSearchOverFiles: + type: object + properties: + search_parameters: + type: string + required: + - search_parameters LocationView: properties: description: @@ -119,7 +342,7 @@ components: items: type: string format: uri - description: UUID of the Archivematica instance using this location. + description: The Archivematica instance using this location. purpose: type: string enum: @@ -191,8 +414,8 @@ components: type: array items: type: string - format: uuid of a pipeline resource - description: UUID of the Archivematica instance using this location. + format: URI of a pipeline resource + description: The Archivematica instance using this location. purpose: type: string enum: @@ -217,12 +440,12 @@ components: type: array items: type: string - format: uuid of a location resource + format: URI of a location resource description: Other locations that will be used to create replicas of the packages stored in this location space: type: string - format: uuid of a space resource + format: URI of a space resource required: - space - relative_path @@ -243,8 +466,8 @@ components: type: array items: type: string - format: uuid of a pipeline resource - description: UUID of the Archivematica instance using this location. + format: URI of a pipeline resource + description: The Archivematica instance using this location. purpose: type: string enum: @@ -269,12 +492,12 @@ components: type: array items: type: string - format: uuid of a location resource + format: URI of a location resource description: Other locations that will be used to create replicas of the packages stored in this location space: type: string - format: uuid of a space resource + format: URI of a space resource required: - space - relative_path @@ -287,17 +510,17 @@ components: type: array items: type: string - format: uuid of an instance of the spaces resource + format: URI of a(n) spaces resource pipelines: type: array items: type: string - format: uuid of an instance of the pipelines resource + format: URI of a(n) pipelines resource locations: type: array items: type: string - format: uuid of an instance of the locations resource + format: URI of a(n) locations resource required: - spaces - pipelines @@ -1015,14 +1238,20 @@ components: subattribute: type: string enum: + - ingestion_time - accessionid - - origin - source_package - name - checksum + - valid + - format_name + - origin - stored + - normalized - source_id + - size - id + - pronom_id - uuid relation: type: string @@ -2539,6 +2768,135 @@ components: required: - search_parameters paths: + /files/: + get: + summary: View all files. + description: View all files. + operationId: get_many.file + parameters: + - $ref: '#/components/parameters/items_per_page' + - $ref: '#/components/parameters/page' + - $ref: '#/components/parameters/order_by_attribute' + - $ref: '#/components/parameters/order_by_subattribute' + - $ref: '#/components/parameters/order_by_direction' + responses: + '200': + description: Request for a collection of files succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedSubsetOfFiles' + '400': + description: Request for a collection of files failed. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorSchema' + tags: + - files + search: + summary: Search over all files. + description: Search over all files. + operationId: search.file + requestBody: + description: JSON object required to search over all files + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SearchOverFiles' + responses: + '200': + description: Search across all files succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedSubsetOfFiles' + '400': + description: Search across all files failed. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorSchema' + tags: + - files + /files/new_search/: + get: + summary: Get the data needed to search over all files. + description: Get the data needed to search over all files. + operationId: new_search.file + responses: + '200': + description: Request to get the data needed to search across all files succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/DataForNewSearchOverFiles' + tags: + - files + /files/search/: + post: + summary: Search over all files. + description: Search over all files. + operationId: search.file + requestBody: + description: JSON object required to search over all files + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SearchOverFiles' + responses: + '200': + description: Search across all files succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedSubsetOfFiles' + '400': + description: Search across all files failed. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorSchema' + tags: + - files + /files/{pk}/: + get: + summary: View an existing file. + description: View an existing file. + operationId: get.file + responses: + '200': + description: Request for a single file succeeded. + content: + application/json: + schema: + $ref: '#/components/schemas/FileView' + '404': + description: Request for a single file failed because there is no file resource + with the specified pk. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorSchema' + '403': + description: Request for a single file failed because the user is forbidden + from viewing this file resource. + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorSchema' + tags: + - files + parameters: + - in: path + name: pk + required: true + schema: + type: string + format: uuid + description: The primary key of the file. /locations/: get: summary: View all locations. @@ -3540,6 +3898,8 @@ paths: format: uuid description: The primary key of the space. tags: +- name: files + description: Access to the File resource - name: locations description: Access to the Location resource - name: packages diff --git a/tox.ini b/tox.ini index 9b5b2b0c2..fb5ec79d4 100644 --- a/tox.ini +++ b/tox.ini @@ -15,12 +15,13 @@ setenv = DJANGO_SETTINGS_MODULE = storage_service.settings.test DJANGO_SECRET_KEY = 1234 +# py.test -v storage_service/locations/tests/test_api_v3.py::TestV3FileAPI [testenv:py27] basepython = python2 skip_install = true deps = -rrequirements/test.txt commands = - py.test + py.test -v setenv = PYTHONPATH = ./storage_service DJANGO_SETTINGS_MODULE = storage_service.settings.test