#204: Manage content rules using GenericSetup
It should be possible to create and assign content rules using GenericSetup
- Proposed by
- Martin Aspeli
- Proposal type
- Assigned to release
- Repository branch
There is currently no easy, declarative way to install new content rules without resorting to the content rules Python API.
Content rules consist of two parts:
- A rule, which has some high level properties and then contains a list of conditions and actions
- An assignment of a rule to a context, including settings such as "does the apply to events occurring in subfolders" and "is the rule currently active"
It should be possible to manage both of these using GenericSetup.
This PLIP is now implemented, and consists of two changes:
Firstly, the <plone:ruleCondition /> and <plone:ruleAction /> directives which are used to register new types of conditions and actions, respectively, now have two extra, optional attributes: factory, which specifies a callable (e.g. a class) used to create an instance of the given condition or action; and schema, which specifies the schema interface (with zope.schema fields) that determines how a condition or action is configured. Any content rule condition or action that wants to be importable and exportable with GenericSetup must specify these two attributes. The standard conditions and actions have been updated to do so. For example, here's the portal type condition:
<plone:ruleCondition name="plone.conditions.PortalType" title="Content type" description="Apply only when the current content object is of a particular type" for="*" event="zope.component.interfaces.IObjectEvent" addview="plone.conditions.PortalType" editview="edit" schema=".portaltype.IPortalTypeCondition" factory=".portaltype.PortalTypeCondition" />
With these in place, the GenericSetup syntax is as follows. The export and import handlers (plone.app.contentrules.exportimport.rules.exportRulesplone.app.contentrules.exportimport.rules.importRules) must be registed as import steps in the usual way (if and when this PLIP is accepted, this will be done in Plone's base profile, and so third party products registering extension profiles should not need to worry). The handlers will operate on a file called contentrules.xml in the profile directory. Here is an example from the plone.app.contentrules tests:
<?xml version="1.0"?> <contentrules> <rule name="test1" title="Test rule 1" description="A test rule" event="zope.lifecycleevent.interfaces.IObjectModifiedEvent" enabled="True" stop-after="False"> <conditions> <condition type="plone.conditions.PortalType"> <property name="check_types"> <element>Document</element> <element>News Item</element> </property> </condition> <condition type="plone.conditions.Role"> <property name="role_names"> <element>Manager</element> </property> </condition> </conditions> <actions> <action type="plone.actions.Notify"> <property name="message">A message</property> <property name="message_type">info</property> </action> </actions> </rule> <rule name="test2" title="Test rule 2" description="Another test rule" event="zope.lifecycleevent.interfaces.IObjectModifiedEvent" enabled="False" stop-after="True"> <conditions> <condition type="plone.conditions.PortalType"> <property name="check_types"> <element>Event</element> </property> </condition> </conditions> <actions> <action type="plone.actions.Workflow"> <property name="transition">publish</property> </action> </actions> </rule> <rule name="test3" title="Test rule 3" description="Third test rule" event="zope.app.container.interfaces.IObjectMovedEvent" /> <assignment location="/news" name="test1" enabled="True" bubbles="False" /> <assignment location="/news" name="test2" enabled="False" bubbles="True" insert-before="test1" /> <assignment location="/news" name="test3" insert-before="*" /> </contentrules>
The <rule /> element creates a new rule. It takes the following attributes:
- name (optional)
- A unique name for the rule. If it's not given, a unique name will be picked for you. If it is given and a rule of this name already exists, the existing rule will be updated/overridden. It is generally a good idea to give a rule name, at least if you intend to use the <assignment /> element to assign rules later.
- title (required)
- A title for the rule, shown in the rule management user interface.
- description (optional)
- A longer, plain-text description of the rule.
- event (required)
- A dotted name to an event type (interface) that this rule should react to. This must be one of the events registered in the event-type vocabulary (see configure.zcml in plone.app.contentrules).
- enabled (optional)
- Whether or not the rule is currently active. If not given, this defaults to "True" (on) - specify "False" to turn the rule off.
- stop-after (optional)
- Whether or not to stop processing further rules after this rule completes successfully. This defaults to "False" (off). Specify "True" to change this.
Inside the <rule /> element, there are two elements: <conditions /> and <actions />. These specify the lists of conditions and actions, respectively. Each condition is declared with a <condition /> element, and each action with an <action /> element. These are otherwise equivalent, and take the following parameters:
- type (required)
- The type of condition or action to create. This is the name that is specified in the <plone:ruleCondition /> or <plone:ruleAction /> ZCML directive (and also given by the element variable on the rule data object itself).
Each condition and action can be configured with properties, using <property /> elements inside the <condition /> or <action /> element. The property names must correspond to field names in the rule element's schema. For scalar values, the value of the element is placed as a string inside the <property /> element (c.f. the transition property for the plone.actions.Workflow action in the example above). Sequence properties (lists, tuples, sets) are initialised by placing a sequence of <element /> elements inside the <property /> element (c.f. the plone.conditions.PortalType condition in the example above). The contents of an <element /> element must be a string that can be converted to the underlying value type.
Once rules have been created, they can be assigned to contexts. This is done using the <assignment /> directive. Assignments are processed in order. You can affect the final ordering of rules assigned in a given location by using the insert-before attribute. The <assignment /> directive takes the following attributes:
- location (required)
- The location where the assignment is to be made. This must be a possible rule container (usually, a folder; more specifically, this means that the object has been marked with the IRuleAssignable interface, which standard folders in Plone have). This is given as a path relative to the portal root. Hence /news means the news folder in the portal root.
- name (required)
- The name of the rule to assign. By design, a rule can be assigned to a given location at most once.
- enabled (optional)
- Whether or not the rule is currently enabled in this location. This defaults to "False" (disabled). Specify "True" to enable the rule assignment.
- bubbles (optional)
- Whether or not the rule should "bubble" into subfolders. That is, if a rule is assigned to a folder and an even occurs in a subfolder, the rule will only be triggered if bubbling is enabled. The default is "False" (no bubbling). Set this to "True" to turn on bubbling.
- insert-before (optional)
- This can be used to affect the order of rule assignments. If omitted, a new assignment will come last of the rule assignments in a particular folder. If set to "*" (an asterisk), the rule will come first. If set to a rule name, the new assignment will come before the assignment of the given rule. If the specified rule cannot be found, the new assignment will again come last.
- plone.contentrules plip204 branch created
- Implemented support for the factory and schema attributes in the <plone:ruleCondition /> and <plone:ruleAction /> directives.
- Better tests for ZCML processing added to plone.contentrules
- plone.contentrules plip204 branch created
- Implemented GS purge
- Implemented GS export
- Implemented GS import
- Wrote tests for GS import and export