Special Content Type Registry Predicates
========================================

We provide some special Content Type Registry (CTR) predicates.

Request Header Predicate
------------------------

This one will match a special crafted request header to a portal type
and create the right portal type.

  >>> from Products.CMFCore.utils import getToolByName
  >>> from Products.ShellExServer.ctr import HeaderPredicate
  >>> from Products.ShellExServer.config import HEADER_NAME

  >>> class record(object): pass
  ...

  >>> ctr = getToolByName(self.portal, 'content_type_registry')
  >>> p_id = 'header_document'
  >>> p_type = HeaderPredicate.PREDICATE_TYPE
  >>> ctr.addPredicate(p_id, p_type)

  >>> type_name = 'Document'
  >>> r = record()
  >>> setattr(r, 'portal_type_name', type_name)
  >>> setattr(r, 'header_name', HEADER_NAME)

  >>> ctr.updatePredicate(p_id, r, type_name)
  >>> ctr.reorderPredicate(p_id, 0)

Note that normalization is now enabled by default:

  >>> from Products.CMFCore.utils import getToolByName
  >>> props = getToolByName(self.portal, 'portal_properties')
  >>> desktop = getToolByName(props, 'plone_desktop_uri')
  >>> desktop.getProperty('filename_normalization', False)
  True

Let's disable it for this test:

  >>> desktop.manage_changeProperties(filename_normalization=False)
  >>> desktop.getProperty('filename_normalization', True)
  False

Now, we will create a file with some random file name, due to the
'catch all' predicate, it will end up being a 'File' object (see
``dav_put.txt`` for more tests on that).

  >>> from Testing.ZopeTestCase import user_name, user_password, folder_name
  >>> from urllib import quote
  >>> self.setRoles(['Manager'])

A file with spaces in the name. Content Type was sent as
'application/octet-stream':

  >>> fname = 'Stupid Named File Without Extension 1'
  >>> print http(r"""
  ... PUT plone/%s HTTP/1.1
  ... Authorization: Basic %s:%s
  ... Content-Type: application/octet-stream
  ... """ % (quote(fname), user_name, user_password),
  ...        handle_errors=False)
  HTTP/1.1 201 Created...

  >>> print self.portal._getOb(fname).getPortalTypeName()
  File

Now if we set the header to the 'Document' portal type, then it should
create a 'Document'.

  >>> fname = 'Stupid Named File Without Extension 2'
  >>> print http(r"""
  ... PUT plone/%s HTTP/1.1
  ... Authorization: Basic %s:%s
  ... %s: Document
  ... Content-Type: application/octet-stream
  ... """ % (quote(fname), user_name, user_password, HEADER_NAME),
  ...        handle_errors=False)
  HTTP/1.1 201 Created...

  >>> print self.portal._getOb(fname).getPortalTypeName()
  Document

If we set the header to `Image` but no CTR predicate is registered for
that, then it won't be triggered, and a `File` will be
created. However since Enfold Desktop 2.3 we create a CTR predicate by
default for each installed type:

  >>> fname = 'Stupid Named File Without Extension 3'
  >>> print http(r"""
  ... PUT plone/%s HTTP/1.1
  ... Authorization: Basic %s:%s
  ... %s: Image
  ... Content-Type: application/octet-stream
  ... """ % (quote(fname), user_name, user_password, HEADER_NAME),
  ...        handle_errors=False)
  HTTP/1.1 201 Created...

  >>> print self.portal._getOb(fname).getPortalTypeName()
  Image

Now we create a predicate mapping `Image` to `File` to see how this
could be controlled:

  >>> p_id = 'header_image'
  >>> p_type = HeaderPredicate.PREDICATE_TYPE
  >>> ctr.addPredicate(p_id, p_type)

  >>> type_name = 'Image'
  >>> r = record()
  >>> setattr(r, 'portal_type_name', type_name)
  >>> setattr(r, 'header_name', HEADER_NAME)

  >>> ctr.updatePredicate(p_id, r, 'File')
  >>> ctr.reorderPredicate(p_id, 0)

  >>> fname = 'Stupid Named File Without Extension 4'
  >>> print http(r"""
  ... PUT plone/%s HTTP/1.1
  ... Authorization: Basic %s:%s
  ... %s: Image
  ... Content-Type: application/octet-stream
  ... """ % (quote(fname), user_name, user_password, HEADER_NAME),
  ...        handle_errors=False)
  HTTP/1.1 201 Created...

  >>> print self.portal._getOb(fname).getPortalTypeName()
  File
