Composing messages
==================

The ``composer`` module provides
``collective.singing.interfaces.IComposer`` implementations for
assembling mails.

  >>> import collective.dancing.composer

Setup
-----

Let's make an ISubscription and an IChannel implementation for use in
this test:

  >>> from zope import interface, component
  >>> import collective.singing.interfaces
  >>> import collective.singing.message
  >>> from collective.dancing.tests import decodeMessageAsString

  >>> class Channel(object):
  ...     def __init__(self, title, url):
  ...         self.title = title
  ...         self.url = url
  ...         self.queue = collective.singing.message.MessageQueues()
  ...     def absolute_url(self):
  ...         return self.url

  >>> class Subscription(object):
  ...     def __init__(self, channel):
  ...         self.channel = channel
  ...         self.composer_data = {}

HTMLComposer
------------

The ``HTMLComposer`` creates messages of type
``email.Message.Message``.  It expects the subscription's
``IComposerData`` to have an 'email' entry:

  >>> HTMLComposer = collective.dancing.composer.HTMLComposer
  >>> HTMLComposer.schema.names()
  ['email']

The HTMLComposer implements both the ``IComposer`` and the
``IComposerBasedSecret`` interfaces:

  >>> from zope.interface import verify
  >>> verify.verifyClass(collective.singing.interfaces.IComposer,
  ...                    HTMLComposer)
  True
  >>> verify.verifyClass(collective.singing.interfaces.IComposerBasedSecret,
  ...                    HTMLComposer)
  True

That is, we can use it to retrieve a subscription's secret:

  >>> channel = Channel('News for nerds', 'http://my.chann.el')
  >>> subscription = Subscription(channel)
  >>> subscription.composer_data['email'] = u'daniel@localhost'
  >>> secret = HTMLComposer.secret(subscription.composer_data)
  >>> isinstance(secret, str)
  True
  >>> subscription.secret = secret

  >>> composer = HTMLComposer()

  Test _from_address
  >>> from Products.CMFCore.interfaces import IPropertiesTool
  >>> properties = component.getUtility(IPropertiesTool)
  >>> old_name = properties.email_from_name
  >>> properties.email_from_name = u'Ko\u010dka'.encode('utf8')
  >>> composer._from_address
  '=?utf-8?b?S2/EjWth?= <>'
  >>> properties.email_from_name = old_name

  Rendering

  >>> items = (
  ...     'My bonnie lies over the ocean',
  ...     'My bonnie lies over the sea',
  ...     'My bonnie lies over the ocean',
  ...     'Oh bring back my bonnie to me')

  >>> msg = composer.render(subscription, items=zip(items, items))
  >>> msg # doctest: +ELLIPSIS
  <collective.singing.message.Message object ...>
  >>> msg.payload # doctest: +ELLIPSIS
  <email.MIMEMultipart.MIMEMultipart instance ...>
  >>> print decodeMessageAsString(msg.payload) # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
  Content-Type: multipart/mixed;...
  Subject: Plone site: News for nerds...
  From: Site Administrator <>...
  To: daniel@localhost...
  ...My bonnie lies over the ocean...My bonnie lies over the sea...

  >>> msg = composer.render_confirmation(subscription) # doctest: +ELLIPSIS
  >>> msg # doctest: +ELLIPSIS
  <collective.singing.message.Message object ...>
  >>> print decodeMessageAsString(msg.payload) # doctest: +ELLIPSIS
  Content-Type: multipart/mixed;...
  Subject: Confirm your subscription with News for nerds...
  From: Site Administrator <>...
  To: daniel@localhost...
  ...To confirm your subscription with News for nerds, please click here...

IMailer
-------

The ``composer`` module defines an ``IMailer`` utility that's used to
send out mails.  Let's make sure that it's registered properly, and
that it has the right settings:

  >>> from zope import component
  >>> from zope.sendmail.interfaces import IMailer
  >>> smtp = component.getUtility(IMailer, 'plone.smtp')
  >>> cfg = smtp._fetch_settings()
  >>> cfg['username'], cfg['password'], cfg['hostname'], cfg['port']
  (None, None, 'localhost', 25)


Formatters
==========

HTML formatters
---------------

  >>> from collective.dancing import composer

The CMFDublinCoreHTMLFormatter renders objects providing the CMF
Dublin Core interface:

  >>> from zope.publisher.browser import TestRequest
  >>> request = TestRequest()
  
  >>> print composer.CMFDublinCoreHTMLFormatter(portal['front-page'], request)() \
  ... # doctest: +NORMALIZE_WHITESPACE
  <div>
    <h2><a href="http://nohost/plone/front-page">Welcome to Plone</a></h2>
    <p>Congratulations! You have successfully installed Plone.</p>
  </div>

The PloneCallHTMLFormatter assumes that the item passed to it is a
Plone object that returns its Plone view when called:

  >>> print composer.PloneCallHTMLFormatter(portal['front-page'], request)() \
  ... # doctest: +ELLIPSIS
  <h1 class="documentFirstHeading">...Welcome to Plone...
  Congratulations! You have successfully installed Plone...
