<commit_before>Assets and Images
=================

Introduction
------------

FIXME All of this still needs to be implemented. This document will be
revised and turned into a doctest along with the implementation.

*Assets* are files of arbitrary type that can be uploaded to and downloaded
from the backend. From the viewpoint of the backend, they are just "blobs"
-- binary objects without any specific semantic.

*Images* are a subtype of assets; they an be resized and cropped to
different target formats.

To manage assets, the backend has the `adhocracy_core.resources.asset.IAsset`
resource type, which is a special kind of *Pool.* (FIXME Or possibly it's a
*Simple*? In any case, it's not versionable.)

Assets can be uploaded to an *asset pool.* Resources that provide an asset
pool implement the `adhocracy_core.sheets.asset.IHasAssetPool` sheet, which
has a single field:

:asset_pool: path to the asset pool where assets can be posted

The `adhocracy_core.resources.asset.IAsset` resource type provides three
sheets:

* `adhocracy_core.sheets.metadata.IMetadata`: provided by all resources,
  automatically created and updated by the backend
* `adhocracy_core.sheets.asset.IAssetMetadata` with the fields:

  :mime_type: the MIME type of the asset; must be specified by the frontend,
      but the backend will sanity-check the posted data and reject the asset
      in case of an detectable mismatch (e.g. if the frontend posts a Word file
      but gives "image/jpeg" as MIME type). Not all mismatches will be
      detectable, e.g. different "text/" subtypes can be hard to distinguish.
  :size: the size of the asset (in bytes)
  :filename: the name of the file uploaded by the frontend (in the backend,
      the asset will have a different, auto-generated path)
  :attached_to: a list of backreferences pointing to resources that refer
      to the asset; this attribute is read-only and managed by the backend

* `adhocracy_core.sheets.asset.IAssetData` with a single field:

  :data: the binary data of the asset ("blob")

  This sheet is POST/PUT-only, see below on how to download/view the binary
  data.

Asset Subtypes and MIME Type Validators
---------------------------------------

Note: this section is mostly backend-specific.

The generic `adhocracy_core.sheets.asset.IAssetMetadata` sheet doesn't limit
the MIME type of assets. Since this is rarely desirable, it is considered
abstract and cannot be instantiated -- only subclasses that provide a *MIME
Type Validator* can. To do so, create a subclass of the sheet (empty marker
interface) and register a `adhocracy_core.interfaces.IMimeTypeValidator`
implementation for that subclass (same as with `IRateValidator` for rates).

E.g. to create a spreadsheet asset type that only accepts OpenDocument and
Excel spreadsheets::

    class ISpreadsheetAsset(IAssetMetadata):
        """Empty marker interface for spreadsheet assets."""

    @implementer(IMimeTypeValidator)<commit_msg>Start turning assets_and_images.rst into doctest (WIP)<commit_after>Assets and Images
=================

Introduction
------------

*Assets* are files of arbitrary type that can be uploaded to and downloaded
from the backend. From the viewpoint of the backend, they are just "blobs"
-- binary objects without any specific semantic.

*Images* are a subtype of assets; they an be resized and cropped to
different target formats.

To manage assets, the backend has the `adhocracy_core.resources.asset.IAsset`
resource type, which is a special kind of *Simple.* (FIXME Or possibly it's a
*Pool*? In any case, it's not versionable.)

Assets can be uploaded to an *asset pool.* Resources that provide an asset
pool implement the `adhocracy_core.sheets.asset.IHasAssetPool` sheet, which
has a single field:

:asset_pool: path to the asset pool where assets can be posted

The `adhocracy_core.resources.asset.IAsset` resource type provides three
sheets:

* `adhocracy_core.sheets.metadata.IMetadata`: provided by all resources,
  automatically created and updated by the backend
* `adhocracy_core.sheets.asset.IAssetMetadata` with the fields:

  :mime_type: the MIME type of the asset; must be specified by the frontend,
      but the backend will sanity-check the posted data and reject the asset
      in case of an detectable mismatch (e.g. if the frontend posts a Word file
      but gives "image/jpeg" as MIME type). Not all mismatches will be
      detectable, e.g. different "text/" subtypes can be hard to distinguish.
  :size: the size of the asset (in bytes)
  :filename: the name of the file uploaded by the frontend (in the backend,
      the asset will have a different, auto-generated path)
  :attached_to: a list of backreferences pointing to resources that refer
      to the asset; this attribute is read-only and managed by the backend

* `adhocracy_core.sheets.asset.IAssetData` with a single field:

  :data: the binary data of the asset ("blob")

  This sheet is POST/PUT-only, see below on how to download/view the binary
  data.

For testing, we import the needed stuff and start the Adhocracy testapp::

    >>> from pprint import pprint
    >>> from adhocracy_core.testing import god_header
    >>> from webtest import TestApp
    >>> app = getfixture('app')
    >>> testapp = TestApp(app)
    >>> rest_url = 'http://localhost'

We need a pool with an asset pool::

    >>> data = {'content_type': 'adhocracy_core.resources.asset.IPoolWithAssets',
    ...        'data': {'adhocracy_core.sheets.name.IName': {
    ...                     'name':  'ProposalPool'}}}
    >>> resp_data = testapp.post_json(rest_url + '/adhocracy', data,
    ...                               headers=god_header).json
    >>> proposal_pool_path = resp_data['path']
    >>> proposal_pool_path
    ['http://localhost/adhocracy/ProposalPool']

We can ask the pool for the location of the asset pool:

    >>> resp_data = testapp.get(proposal_pool_path).json
    >>> resp_data['data']['adhocracy_core.sheets.asset.IHasAssetPool']['name']
    ['http://localhost/adhocracy/ProposalPool/assets']

Asset Subtypes and MIME Type Validators
---------------------------------------

Note: this section is mostly backend-specific.

The generic `adhocracy_core.sheets.asset.IAssetMetadata` sheet doesn't limit
the MIME type of assets. Since this is rarely desirable, it is considered
abstract and cannot be instantiated -- only subclasses that provide a *MIME
Type Validator* can. To do so, create a subclass of the sheet (empty marker
interface) and register a `adhocracy_core.interfaces.IMimeTypeValidator`
implementation for that subclass (same as with `IRateValidator` for rates).

TODO Make testable:

E.g. to create a spreadsheet asset type that only accepts OpenDocument and
Excel spreadsheets::

    class ISpreadsheetAsset(IAssetMetadata):
        """Empty marker interface for spreadsheet assets."""

    @implementer(IMimeTypeValidator)
{'fraction_non_alphanumeric': 0.09082994776552525, 'fraction_numerical': 0.0, 'mean_word_length': 3.800139275766017, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4033726', 'n_tokens_mistral': 1949, 'n_tokens_neox': 1841, 'n_words': 840}