Manual
CMFNotification manual
1. Installation and configuration
This document explains how to install and configure CMFNotification.
Installation
============
1. Read the `right documentation`_ if you have never installed any
product.
2. Install the product in the file system (as usual).
3. Install the product in your Plone portal, via the Plone control
panel (as usual).
.. _right documentation: http://plone.org/documentation/tutorial/third-party-products/installing
Principles and rules
====================
Before frantically clicking everywhere, blindly hoping that this will
"just work", we would better begin by introducing the principles of
CMFNotification and, particularly, the rules::
This is not 'Nam, there are rules.
-- Walter Sobchak (The Big Lebowski)
This is a required step. Firstly because if you do not configure
CMFNotification, nothing special will happen. You have to configure
it. Secondly, understanding what you are doing is the first step to
understand why it does not work. This will save your time.
CMFNotification lets you define who will receive e-mails, when and
what mail template will be used. Mail templates can be used to have
specific mails for specific events (when an event is published with a
determined keyword, for example).
To determine who, when and what, you have to define rules. There are
two kinds of rules:
- rules that define who we are sending e-mails to. There is one such
rule for each supported type of event (item creation, item
modification, workflow transition, etc.) ;
- rules that define which mail template we will use.
Configuration
=============
To configure CMFNotification, click on the "Configuration of
CMFNotification" configlet in the Plone control panel.
Enabling and disabling features
-------------------------------
Labels should be self-explanatory. However, here is a quick guide to
the configuration form:
*enable extra subscriptions*
if enabled, users will be able to subscribe or unsubscribe to items
via the buttons that appear in the "Mail subscription" portlet
(which is added in the right column, by default). They will
therefore receive an e-mail notification when an event occurs, if
the notification of this event is enabled. See *Rules for list of
users* section in the rules reference for further details. Note that
this feature is restricted by a permission: *CMFNotification:
Subscribe/unsubscribe*. By default, this permission is granted to
``Manager`` and ``Member`` roles. Note that anonymous subscription
is not implemented.
Default: disabled.
*toggle recursive mode for extra subscriptions*
if enabled, an user who has subscribed to a folder will
automatically be subscribed to items of this folder (and sub-folders
and their subitems, etc.)
Default: enabled.
*toggle debug mode*
if enabled, CMFNotification will log the addresses that it sends
e-mails to and the messages themselves. This can be particularly
helpful when debugging your rules.
Default: disable.
*rules (ignore)*
this is a special rule to disallow notification. This can be handy
when you want to temporarily disable notification in one click
withoug messing up with the whole configuration. A simple rule like
this one does the trick::
python: True
You could also want not to send any notification for items in a
specific folder. Using an "ignore rule" is much more handy that
customizing all rules::
python: here.isInFooSection()
Default: the default rule disable notification of temporary items::
python: getattr(context, 'isTemporary', lambda: False)()
Configuration of the rules
--------------------------
If you are really in a hurry, you may want to look at "How to setup
CMFNotification in two minutes" (``how-to-setup-in-2-minutes.txt``).
If you are not, take your time and `read more about rules`_.
.. _read more about rules: http://plone.org/products/cmfnotification/documentation/manuals/manual/rules-reference
Logging
=======
Every error or potential problem (if no user was found for a
notification, if a problem occurs when trying to find or apply the
mail template, etc.) is logged. If you do not receive any e-mail,
check your Zope log file.
For futher details, see our `troubleshooting how-to`_.
.. _troubleshooting how-to: http://plone.org/products/cmfnotification/documentation/how-to/how-to-troubleshoot-your-configuration
2. Rules reference
Extensive documentation on what rules are and how to use them.
General principles
==================
All types of rules follow the same principles:
First, a rule is one line long. It can be as long as we want,
though. However, it is suggested that very long rules components be
put in a script, a tool/content type method or a view.
A rule have two components, separated by two colons: ``::``. Spaces
can be put before or after the colons, for readability's sake (se
examples below)::
<match-expr> :: <rule-expr>
The first component is a conditional expression. If this expression is
evaluated to ``True``, then the rule matches. The type of the second
component and the behaviour of the rule depend of its type (see
below).
These expressions can be:
- Python expressions, e.g.::
python: here.meta_type == 'Document'
- TAL expressions, e.g.::
not: here/keepSecret
- an asterisk (``*``), which basically means "always" or "everyone",
depending on the context. A rule with ``*`` always match.
Python and TAL expressions are provided some bindings (like ``here``,
``author``, etc.). See the `Bindings`_ paragraph below.
Rules
=====
Rules for list of users
-----------------------
These rules are used to decide who should be notified. As all rules,
they look like the following::
<match-expr> :: <get-notified-expr>
The ``<get-notified-expr>`` expression is used to determine who has to
be notified. It must return a list of user names, email addresses or
both. If multiple rules match, then the global subscribers list **is
an union of all subscribers list returned by each rule**. In other
words, if we have the following rules::
here/iAmTrue :: python: [user1']
here/iAmAlsoTrue :: python: ['user2']
Then both users will receive a mail notification.
Note that this list will be **extended by the list of users who have
manually subscribed to the item** (if we have enabled this feature).
Moreover a label can be added after a selection rule ::
<match-expr> :: <get-notified-expr> :: <label>
This label lets us decide which e-mail template to use for users that
match this rule. In other words: on the same event, we can decide to
send a different e-mail for various (groups of) users. More than one
rule may use the same label: in this case, as above, the global list
of matching users is an union of all subscribers list returned by each
rule. Also note that the same user may be retrieved for different
rules with different labels: (s)he will then receive **more than one**
e-mail. See below for an example.
If no label is specified, it is considered to be empty string. Users
who manually suscribe to the item are also registered under this empty
label.
**Important:** Also note that a security check is done in any case: no
user will receive notification of an item which (s)he cannot
view. Therefore, you have to think twice if you want to notify all
users of our portal when there are a lot of users: security checks are
costly. If you are not sure, test
``NotificationTool.removeUnAuthorizedSubscribers()`` on a development
portal with all users. Note that a future version of CMFNotification
might allow certain rules to be trusted; in this case, security checks
would not be done.
Some examples:
- if we want to notify all users who can view the item::
* :: *
- if we want to send an e-mail to only one user when an item is
submitted::
python: transition == 'submit' :: python: ['jsmith']
Rules for e-mail template
-------------------------
There are also rules to determine what e-mail template will be used to
notify users. They look like this::
<match-expr> :: <template-expr>
``<template-expr>`` is a TAL or Python expression which can return
either a page template (ZPT) or the "id" of a page template. This page
template will be "applied to" (or "evaluated in the context of") the
object to generate the email message of the notification. Again,
specific bindings are available (see below).
Contrary to subscribers rules, **only the first rule** to match is
taken in account. In other words, if we have the following rules::
here/iAmTrue :: string:creation_mail_notification
here/iAmAlsoTrue :: string:modification_mail_notification
Then the mail template will be the first one that matches:
``creation_mail_notification``.
If user selection rules had labels, template selection is runned for each
groups corresponding to each label independantly.
Note that CMFNotification ships with simple yet usable mail template:
- ``creation_mail_notification``: for item creation (not for
discussion item, though, see below);
- ``modification_mail_notification``: for item modification;
- ``workflow_mail_notification``: for workflow transitions;
- ``discussion_mail_notification``: for discussion item creation;
- ``registration_mail_notification``: for member registration;
Bindings
========
Bindings are injected into the expression context when rule
expressions and mail templates are evaluated.
Default bindings
----------------
The following bindings are always available:
- ``here``: the current item;
- ``context``: same as ``here``;
- ``current_state``: workflow state of the current item;
- ``author``: the current member;
- ``nothing``: equals to None;
- ``portal``;
- ``request``;
- ``modules``: a ``SecureModuleImporter`` instance.
Special bindings for template selection rules
---------------------------------------------
The following bindings are only available in the template selection
rules (for all events):
- ``label``: one of the matching labels of user selection rules. Using
``label`` in our mail template selection rules lets us select a
different template for users that have matched the corresponding
label. For example, we could define these rules for users::
* :: python: ['manager'] :: simple
* :: python: ['dev1', 'dev2'] :: detailed
And the following rules for template selection::
python: label == 'simple' :: string:simple_mail_template
python: label == 'detailed' :: string:detailed_mail_template
The three users would receive an e-mail:
- ``manager`` would receive a simplified notification;
- ``dev1`` and ``dev2`` would received a detailed notification,
since we asked for another mail template.
Special bindings for item modification
--------------------------------------
The following bindings are available in the context of an item
modification:
- ``current``: the current version of the object;
- ``previous``: the previous version of the object, if available, or
``None`` otherwise (or when the item is created).
Special bindings for workflow transition
----------------------------------------
The following bindings are available in the context of a workflow
transition:
- ``transition``: the transition (as a string) which was triggered;
- ``current_state``: the current workflow state (as a string) of the
item;
- ``previous_state``: the previous workflow state (as a string) of the
item;
- ``comments``: the (possibly empty) comments.
Special bindings for member registration and modification
---------------------------------------------------------
The following bindings are available in the context of a member
registration or modification:
- ``current_user``: the user who has has registered the member (could
be the member him/herself, i.e. an anonymous user, or an existing
portal member), or the user who has modified the member properties
(can be the user him/herself or another user);
- ``member``: the new portal member;
- ``properties``: the new portal member's properties;
- ``event``: either ``registration`` or ``modification``. FIXME: ?
Special bindings for discussion item creation
---------------------------------------------
Since ``here`` and ``context`` are ambiguous, two special bindings are
provided to access the discussed item (``discussed_item``) and the
discussion item itself (``discussion_item``).
3. Developer notes
A few notes for developers.
Events, patches and so-called architecture
------------------------------------------
The product defines a set of event subscribers
(cf. ``events/events.txt``) that calls appropriate handlers in
CMFNotification tool.
The product still patches a some components of CMF, in order to call
handlers when specific events occur. Cf. ``patches.py`` module for
more information. These patches will soon be replaced by appropriate
events.
These handlers are implemented by ``NotificationTool`` (cf. methods
which begin with ``on*``). They are very similar, and therefore call
an unique helper method (``_handlerHelper()``) to do the work. The
rest is in the code...
Implementation of the extra subscriptions list
----------------------------------------------
I wanted the subscriptions to be recursive, i.e. that an user
subscribed to ``folder/`` is also recursively subscribed to
``folder/document`` and ``folder/subfolder``.
The naive answer for that is to keep a mapping whose keys are path of
object, and values are email addresses, like this::
{'/': ('boss1@exemple.com', 'boss2@exemple.com'),
'/marketing/': ('marketing@exemple.com', ) }
But keeping paths is good until the paths change. In the example
above, if ``marketing/`` is renamed as ``advertising/``, the tool
cannot know the previous path of the object. Then, our mapping become
quite useless.
The best way to deal with path changes is to store the UID of the
objects instead of their path. But then, how can we easily get the
entries in the mapping which corresponds to (i.e. which is a parent of
the current object)? We would need to loop through all the UIDs and
get the corresponding object. This would be expensive.
Therefore, I decided to have two mappings:
- ``_uid_to_path``: key is the object UID, value is the object path;
- ``_subscriptions``: key is the object path, value are the
subscribers list;
Since we know when an object is modified, we can keep both mappings
updated.
I am open to comments on that point (as I am on the rest of the
product, too).

