Sunday, February 14, 2010

How to create Workflow for a repoze.BFG application

Let us see , how we can create a workflow for a bfg application.

To add a workflow add a file named workflow.py at the root of your site. you can name it as you like.
Add methods related to the states and transitions as per your requirement.

For Example, the following files does the work.

  • workflow.py

from repoze.bfg.security import Allow
from repoze.bfg.security import Deny
from repoze.bfg.security import Everyone
from repoze.bfg.traversal import find_interface
from repoze.bfg.traversal import model_path

from project.security_policies.policy import ADMINISTRATOR_PERMS
from project.security_policies.policy import GUEST_PERMS
from project.security_policies.policy import MODERATOR_PERMS
from project.security_policies.policy import MEMBER_PERMS
from project.security_policies.policy import CREATE
from project.security_policies.policy import NO_INHERIT
from project.security_policies.workflow import postorder
from project.security_policies.workflow import acl_diff
from project.security_policies.workflow import reset_security_workflow


def find_showEvent(context):
return find_interface(context, IshowEvent)

def ts(*args):
return '\t'.join([str(x) for x in args])

#------------------------------------------------------------------------------
# Electors
#------------------------------------------------------------------------------

def not_intranets_containment(context):
return not intranets_containment(context)

def intranets_containment(context):
return False

def private_showEvent_containment(context):
if not_intranets_containment(context):
showEvent = find_showEvent(context)

if showEvent is None:

return False

return getattr(showEvent, 'seproject.security_policies.policycurity_state', None) == 'private'

return False

def public_showEvent_containment(context):
if not_intranets_containment(context):
showEvent = find_showEvent(context)
if showEvent is None:
return False
return getattr(showEvent, 'security_state', None) == 'public'
return False


#------------------------------------------------------------------------------
# Workflow for showEvent
#------------------------------------------------------------------------------

def showEvent_to_private(ob, info):
showEvent = find_showEvent(ob)
acl = []
moderators_group_name = showEvent.moderators_group_name
members_group_name = showEvent.members_group_name
acl.append((Allow, 'group.KarlAdmin', ADMINISTRATOR_PERMS))
acl.append((Allow, moderators_group_name, MODERATOR_PERMS))
acl.append((Allow, members_group_name, MEMBER_PERMS))
acl.append(NO_INHERIT)
msg = None
added, removed = acl_diff(showEvent, acl)
if added or removed:
showEvent.__acl__ = acl
msg = ts('showEvent-private', model_path(showEvent), added, removed)
_reindex(showEvent)
return msg

def showEvent_to_public(ob, info):
showEvent = find_showEvent(ob)
acl = []
moderators_group_name = showEvent.moderators_group_name
members_group_name = showEvent.members_group_name
acl.append((Allow, 'group.KarlAdmin', ADMINISTRATOR_PERMS))
acl.append((Allow, members_group_name, GUEST_PERMS))
acl.append((Allow, 'group.KarlStaff', GUEST_PERMS))
acl.append(NO_INHERIT)
msg = None
added, removed = acl_diff(showEvent, acl)
if added or removed:
showEvent.__acl__ = acl
msg = ts('showEvent-public', model_path(showEvent), added, removed)
_reindex(showEvent)
return msg


def showEvent_to_pending(ob, info):
showEvent = find_showEvent(ob)
acl = []
moderators_group_name = showEvent.moderators_group_name
members_group_name = showEvent.members_group_name
acl.append((Allow, 'group.KarlAdmin', ADMINISTRATOR_PERMS))
acl.append((Allow, members_group_name, GUEST_PERMS)) #When the showEvent is pending user cannot delete,create, edit
acl.append((Allow, 'group.KarlStaff', GUEST_PERMS))
acl.append(NO_INHERIT)
msg = None
added, removed = acl_diff(showEvent, acl)
if added or removed:
showEvent.__acl__ = acl
msg = ts('showEvent-pending', model_path(showEvent), added, removed)
_reindex(showEvent)
return msg

def showEvent_to_rejected(ob,info):
showEvent = find_showEvent(ob)
acl = []
moderators_group_name = showEvent.moderators_group_name
members_group_name = showEvent.members_group_name
acl.append((Allow, 'group.KarlAdmin', ADMINISTRATOR_PERMS))
acl.append((Allow, members_group_name, GUEST_PERMS))
acl.append((Allow, 'group.KarlStaff', GUEST_PERMS))
acl.append(NO_INHERIT) #temp
msg = None
added, removed = acl_diff(showEvent, acl)
if added or removed:
showEvent.__acl__ = acl
msg = ts('showEvent-pending', model_path(showEvent), added, removed)
_reindex(showEvent)
return msg

In workflow.py permissions were imported from policy file. Below is the policy file of security_policies of project.

  • policy.py

from BTrees.IFBTree import multiunion
from BTrees.IFBTree import IFSet

from repoze.bfg.security import Allow
from repoze.bfg.security import Deny
from repoze.bfg.security import Everyone
from repoze.bfg.security import AllPermissionsList


VIEW = 'view'
EDIT = 'edit'
CREATE = 'create'
DELETE = 'delete'
MODERATE = 'moderate'
ADMINISTER = 'administer'
COMMENT#acl.append((Allow, moderators_group_name, MODERATOR_PERMS)) #Creator or member is the part of default member group = 'comment'

GUEST_PERMS = (VIEW, COMMENT)
MEMBER_PERMS = GUEST_PERMS + (EDIT, CREATE, DELETE)
MODERATOR_PERMS = MEMBER_PERMS + (MODERATE,)
ADMINISTRATOR_PERMS = MODERATOR_PERMS + (ADMINISTER,)

ALL = AllPermissionsList()
NO_INHERIT = (Deny, Everyone, ALL)


Add workflow.zcml and declare the states and transitions as follows.

  • workflow.zcml


< configure xmlns="http://namespaces.repoze.org/bfg">
< include package="repoze.workflow" file="meta.zcml">

< workflow type="security"
name="showEvent"
description="WF for showEvent"
elector="project.workflow.not_intranets_containment"
content_types="project.interfaces.IshowEvent"
initial_state="private"
state_attr="security_state"
permission_checker="repoze.bfg.security.has_permission"
>

< state name="public" title="Public"
callback="project.workflow.showEvent_to_public">

< /state>

< state name="private" title="Private"
callback="project.workflow.showEvent_to_private">
< alias name="initial">
< /state>

< state name="pending" title="Pending"ar
callback="project.workflow.showEvent_to_pending">
< /state>

< state name="rejected" title="Rejected"
callback="project.workflow.showEvent_to_rejected">
< alias name="initial">
< /state>

< transition name="submit"
to_state="pending"
from_state="private"/>

< transition name="approve"
to_state="public"
from_state="pending"/>

< transition name="retract"
to_state="private"
from_state="pending"/>

< transition name="reject"
to_state="rejected"
from_state="pending"/>

< transition name="unapprove"
to_state="pending"
from_state="public"/>

</workflow>


Now register the workflow , by declaring it in configure.zcml file.

  • configure.zcml



<configure xmlns="http://namespaces.repoze.org/bfg">

<!-- this must be included for the view declarations to work -->

<include package="repoze.bfg.includes">
<include package="project.security_policies">
<include package="project.views">
<include package="project" file="workflow.zcml">

</configure>

This way, we were able to create a workflow for our project.