Metadata-Version: 2.1
Name: oarepo-validate
Version: 1.3.2
Summary: OArepo Validate library for record metadata validation
Home-page: https://github.com/oarepo/oarepo-validate
Author: UCT Prague
Author-email: miroslav.simek@vscht.cz
License: MIT
Description: # oarepo-validate
        
        [![image][]][1]
        [![image][2]][3]
        [![image][4]][5]
        [![image][6]][7]
        [![image][8]][9]
        
          [image]: https://img.shields.io/travis/oarepo/oarepo-validate.svg
          [1]: https://travis-ci.org/oarepo/oarepo-validate
          [2]: https://img.shields.io/coveralls/oarepo/oarepo-validate.svg
          [3]: https://coveralls.io/r/oarepo/oarepo-validate
          [4]: https://img.shields.io/github/tag/oarepo/oarepo-validate.svg
          [5]: https://github.com/oarepo/oarepo-validate/releases
          [6]: https://img.shields.io/pypi/dm/oarepo-validate.svg
          [7]: https://pypi.python.org/pypi/oarepo-validate
          [8]: https://img.shields.io/github/license/oarepo/oarepo-validate.svg
          [9]: https://github.com/oarepo/oarepo-validate/blob/master/LICENSE
        
        OArepo Validate library for model-level matedata validation
        
        
        ## Installation
        
        ```bash
            pip install oarepo-validate
        ```
        
        ## Usage
        
        The library provides mixins for enforcing json schema and marshmallow validation.
        
        ### JSON schema validation
        
        If ``$schema`` is present on metadata, invenio performs a json schema validation inside
        the ``validate()`` method. The problem is that ``$schema`` can be set/removed via the REST
        API. This means that an ill-written client can completely bypass the validation.
        
        To mitigate this issue, create your own Record implementation:
        
        ```python
        from oarepo_validate import SchemaKeepingRecordMixin
        from invenio_records import Record
        
        class MyRecord(SchemaKeepingRecordMixin, Record):
            ALLOWED_SCHEMAS = ('records/record-v1.0.0.json', 'records/record-v2.0.0.json')
            PREFERRED_SCHEMA = 'records/record-v2.0.0.json'
        ```
        
        And register the record in REST endpoints in configuration:
        
        ```python
        RECORD_PID = 'pid(recid,record_class="my:MyRecord")'
        
        RECORDS_REST_ENDPOINTS = {
            'records': dict(
                pid_type='recid',
                pid_minter='recid',
                pid_fetcher='recid',
                record_class='my:MyRecord',
                item_route='/records/<{0}:pid_value>'.format(RECORD_PID),
                # ...
            )
        }
        ```
        
        #### Create record
        
        When creating a new record, if ``$schema`` is not set, ``MyRecord.PREFERRED_SCHEMA`` is added
        automatically. If ``$schema`` is set, it is validated against ``MyRecord.ALLOWED_SCHEMAS``
        and an exception is raised if the schema is not present in ``ALLOWED_SCHEMAS``.
        
        #### PUT / PATCH record
        
        Before the result of the operation is committed, ``$schema`` is checked again.
        
        ### Marshmallow validation
        
        In invenio, REST create operation use the following sequence:
        
        ```
        <flask>
        <invenio_records_rest.views.RecordsListResource:post>
           <loader>
              <marshmallow>
           <permission factory>
           <pid minter>
           <record_class.create>
              <record.commit>
                 <record.validate>
        ```
        
        REST PUT operation then uses:
        
        ```
        <flask>
        <invenio_records_rest.views.RecordResource:put>
           <permission factory>
           <loader>
              <marshmallow>
           <record.update>
           <record.commit>
              <record.validate>
        ```
        
        REST PATCH operation:
        
        ```
        <flask>
        <invenio_records_rest.views.RecordResource:put>
           <permission factory>
           <simple json loader>
           <record.patch>
           <record.commit>
              <record.validate>
        ```
        
        As you can see, if you place any validation code in loader's marshmallow, it is not executed.
        An alternative is to have the validation code in ``validate`` and handle all validations there.
        This library does exactly this - it provides a record mixin that calls marshmallow schema's ``load``
        method inside its ``validate`` method.
        
        #### Usage
        
        Create your own record and inherit from the mixin:
        
        ```python
        from oarepo_validate import MarshmallowValidatedRecordMixin
        from invenio_records import Record
        from marshmallow import Schema, fields
        
        class TestSchema(Schema):
            name = fields.Str(required=True)
        
        class MyRecord(MarshmallowValidatedRecordMixin, Record):
            MARSHMALLOW_SCHEMA = TestSchema
        ```
        
        Do not forget to register it as in the previous example.
        
        Now marshmallow schema will be processed before each ``commit`` method.
        
        #### What about marshmallow in loader?
        
        In most cases, marshmallow schema in loader can be removed and a simple json loader used instead.
        However, if you need a custom processing of input data that is independent of validation,
        you can keep the two marshmallows. To remove marshmallow loader and use a simple one,
        set ``oarepo_validate.json_loader`` as the record loader.
        
        ```python
        RECORDS_REST_ENDPOINTS = {
            'recid': dict(
                record_loaders={
                    'application/json': 'oarepo_validate:json_loader',
                },
                # ...
            )
        }
        ```
        
        A special case is when the marshmallow in loader already includes validation marshmallow rules.
        Then you would want to use loader's marshmallow for create / replace and marshmallow in validation
        only for patch operation (so that the same marshmallow rules are not called twice). To accomplish
        this, set:
        
        ```python
        class MyRecord(MarshmallowValidatedRecordMixin, Record):
            MARSHMALLOW_SCHEMA = TestSchema
        
            VALIDATE_MARSHMALLOW = False
            VALIDATE_PATCH = True
        ```
        
        ``VALIDATE_MARSHMALLOW`` will switch off marshmallow validation in ``validate`` method and
        ``VALIDATE_PATCH`` will switch on marshmallow validation in ``patch`` method.
        
        ##### record-files
        
        Be careful with removing the loader when you use ``invenio-record-files``. Just using plain
        json loader makes it possible to set ``_bucket`` and ``_files`` directly which should be
        disabled for security reasons (anyone might gain access to any file if he knows bucket and
        object version of the file and has write access to any record).
        
        To fix this, set:
        
        ```python
        from oarepo_validate import FilesKeepingRecordMixin
        
        RECORDS_REST_ENDPOINTS = {
            'recid': dict(
                record_loaders={
                    'application/json': 'oarepo_validate:json_loader',
                },
                # ...
            )
        }
        
        class MyRecord(FilesKeepingRecordMixin, ...):
            ...
        ```
        
        The loader will strip ``_bucket`` and ``_files`` from the payload and the mixin
        will make sure that the files can not be removed with ``put`` or replaced with ``patch``
        operation.
        
        #### Context
        
        Marshmallow validation is called with a context, that is filled with:
        
          * ``record``
          * ``pid`` if it is known
          * Any ``**kwargs`` passed to ``Record.create`` or ``Record.commit``
        
        #### Signals
        
        The library provides the following signals:
        
        ```python
        before_marshmallow_validate = signal('oarepo_before_marshmallow_validate')
        """
        Signal invoked before record metadata are validated (loaded by marshmallow schema)
        inside Record.validate
        
        :param source:  the record being validated
        :param record:  the record being validated
        :param context: marshmallow context
        :param **kwargs: kwargs passed to Record.create or Record.commit (or Record.validate)
        """
        
        after_marshmallow_validate = signal('oarepo_after_marshmallow_validate')
        """
        Signal invoked after record metadata are validated (loaded by marshmallow schema)
        inside Record.validate
        
        :param source:  the record being validated
        :param record:  the record that was successfully validated
        :param context: marshmallow context
        :param result:  result of load that will be used to update record's metadata.
                        Signal handler can modify it. In case of validation exception the result is None.
        :param error:   Exception raised when validating. None if validation has been successful
        :param **kwargs: kwargs passed to Record.create or Record.commit (or Record.validate)
        """
        ```
        
        #### Serializers
        
        If ``marhsmallow.dump`` is not required for metadata serialization,
        ``oarepo_validate.json_search, oarepo_validate.json_response``
        are faster replacements for marshmallow-based serializers:
        
        ```python
        RECORDS_REST_ENDPOINTS = {
            'recid': dict(
                record_serializers={
                    'application/json': 'oarepo_validate:json_response',
                },
                search_serializers={
                    'application/json': 'oarepo_validate:json_search',
                }
            )
        }
        ```
        
        
        <!--
        Copyright (C) 2020 UCT Prague.
        
        oarepo-validate is free software; you can redistribute it and/or modify it
        under the terms of the MIT License; see LICENSE file for more details.
        -->
        
        # Changes
        
        
        ## Version 1.2.3 (released 2020-08-30)
        
        - Handling pid field in search hit serialization
        
        
        ## Version 1.2.2 (released 2020-08-25)
        
        - Handling pid field in record serialization
        
        
        ## Version 1.2.1 (released 2020-08-25)
        
        - Keeping schema in ``Record.__init__`` (useful mostly for tests)
        
        
        ## Version 1.2.0 (released 2020-08-25)
        
        - Added marshmallow-less loaders and serializers
        
        
        ## Version 1.1.0 (released 2020-08-18)
        
        - Added before and after validation signals.
        
        
        ## Version 1.0.0 (released 2020-08-16)
        
        - Initial public release.
        
Keywords: metadata validation oarepo records
Platform: any
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Development Status :: 4 - Beta
Description-Content-Type: text/markdown
Provides-Extra: tests
Provides-Extra: dev
