Wednesday, April 28, 2010
Leave management System - An Open Source Contribution from Mahiti Infotech Bangalore
Hi All
We have developed an application using Repoze.BFG and KARL as basis. The application, is named as LMS( Leave management System ). We want to contribute this project for Open Source Community. We wish , LMS can act as a reference , for any one who is interested in learning KARL based repoze applications.
Link to download, source code is : https://sourceforge.net/projects/mahiti-lms
Please feel free to tell us how it is and our lackings if any.
Srikanth.T
Senior Programmer
Sowmya.MK
Team Lead
Sreekanth S Rameshaiah
CEO
Mahiti Infotech Pvt. Ltd.
# 33-34, 2nd Floor,
Hennur Cross, Hennur Road,
Bangalore, India - 560043
Phone: +91 80 4115 0580/1
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.
In workflow.py permissions were imported from policy file. Below is the policy file of security_policies of project.
Add workflow.zcml and declare the states and transitions as follows.
Now register the workflow , by declaring it in configure.zcml file.
This way, we were able to create a workflow for our project.
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])
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
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.
Thursday, January 28, 2010
Cataloging objects in BFG
Cataloging objects in BFG
One way to catalog the objects in a BFG application is to use subscribers .
The procedure followed to catalog is :
Let us see how we can catalog objects.
One way to catalog the objects in a BFG application is to use subscribers .
The procedure followed to catalog is :
- Add a catalog file in the root that has a method to catalog the objects.
- In models.py import the catalog method you have written and call it in the appmaker() .
- Implement zope events interfaces that you require in events.py (you can use any name)
- Then write the functions which you want to execute on firing of above mentioned/decalred events.
- Now use subscriber tag in configure.zcml and register the subscriber function to the events declared.
Let us see how we can catalog objects.
- catalog.py
Create a python file called catalog.py in the root. Add a method populate_catalog and place the indexes that are required.
- import datetime
- import time
- from zope.interface import providedBy
- from zope.component import queryAdapter
- from zope.interface.declarations import Declaration
- from repoze.bfg.traversal import model_path
- from repoze.bfg.traversal import find_interface
- from repoze.catalog.catalog import Catalog
- from repoze.catalog.indexes.field import CatalogFieldIndex
- from repoze.catalog.indexes.keyword import CatalogKeywordIndex
- from repoze.catalog.indexes.text import CatalogTextIndex
- from repoze.catalog.indexes.path import CatalogPathIndex
- from repoze.catalog.indexes.path2 import CatalogPathIndex2
- from repoze.catalog.document import DocumentMap
- from repoze.bfg.security import principals_allowed_by_permission
- from leavemnt.interfaces import IRoot
- from leavemnt.interfaces import ISearchText
- from leavemnt.interfaces import IVirtualData
- from leavemnt.interfaces import ILeave
- from leavemnt.interfaces import IProfile
- from leavemnt.utils import coarse_datetime_repr
- from leavemnt.utils import find_users
- def get_search_text(object, default):
- adapter = queryAdapter(object, ISearchText)
- if adapter is None:
- return default
- return adapter()
- def get_creator(object, default):
- return getattr(object, 'creator', default)
- def _get_date(object, default, name):
- date = getattr(object, 'modified', None)
- if date is None:
- return default
- # we can't store datetimes directly in the catalog because they
- # can't be compared with anything
- timetime = time.mktime(date.timetuple())
- # creation "minute" actually to prevent too-granular storage
- date = int(str(int(timetime))[:-2])
- return date
- def get_modified_date(object, default):
- return _get_date(object, default, 'modified')
- def get_created_date(object, default):
- print _get_date(object, default, 'created')
- return _get_date(object, default, 'created')
- def get_interfaces(object, default):
- # we unwind all derived and immediate interfaces using spec.flattened()
- # (providedBy would just give us the immediate interfaces)
- provided_by = list(providedBy(object))
- spec = Declaration(provided_by)
- ifaces = list(spec.flattened())
- return ifaces
- def get_security_state(obj, default):
- return getattr(obj, 'security_state', default)
- def populate_catalog(site):
- catalog = site.catalog = Catalog()
- catalog['text'] = CatalogTextIndex(get_search_text)
- catalog['interfaces'] = CatalogKeywordIndex(get_interfaces)
- catalog['creator'] = CatalogFieldIndex(get_creator)
- catalog['modified'] = CatalogFieldIndex(get_modified_date)
- catalog['created'] = CatalogFieldIndex(get_created_date)
- catalog['security_state']= CatalogFieldIndex(get_security_state)
- catalog.document_map = DocumentMap()
- def find_catalog(context):
- return find_interface(context, IRoot).catalog
- In models.py
Then in the appmaker function , make a site instance , and pass it as a parameter to the populate_catalog method.
- def appmaker(root):
- if not root.has_key(SITE_ID):
- #site = root['site'] = Site()
- site = Site()
- root[SITE_ID] = site
- ## TODO: cleanup catalog creation.
- populate_catalog(site)
- leavefolder = LeaveFolder()
- site['leavefolder'] = leavefolder
- data = DefaultInitialData()
- transaction.commit()
- return root[SITE_ID]
Then the site will contain the catalog mechanism. For every subsequent creation, modification and deletion there should be a mechanism to update the catalog.
- subscribers.py
- import datetime
- from zope.component import queryAdapter
- from repoze.bfg.traversal import model_path
- from repoze.folder.interfaces import IFolder
- from leavemnt.catalog import find_catalog
- from leavemnt.interfaces import IMetadata
- def postorder(startnode):
- def visit(node):
- if IFolder.providedBy(node):
- for child in node.values():
- for result in visit(child):
- yield result
- yield node
- return visit(startnode)
- def index_content(object, event):
- """ Index content (an IObjectAddedEvent subscriber) """
- catalog = find_catalog(object)
- if catalog is not None:
- for node in postorder(object):
- path = model_path(node)
- docid = catalog.document_map.add(path)
- catalog.index_doc(docid, node)
- adapter = queryAdapter(node, IMetadata)
- if adapter is not None:
- metadata = adapter()
- catalog.document_map.add_metadata(docid, metadata)
- def unindex_content(object, event):
- """ Unindex content (an IObjectWillBeRemovedEvent subscriber) """
- catalog = find_catalog(object)
- if catalog is not None:
- path = model_path(object)
- num, docids = catalog.search(path=path)
- for docid in docids:
- catalog.unindex_doc(docid)
- catalog.document_map.remove_docid(docid)
- def reindex_content(object, event):
- """ Reindex a single piece of content (non-recursive); an
- IObjectModifed event subscriber """
- catalog = find_catalog(object)
- if catalog is not None:
- path = model_path(object)
- docid = catalog.document_map.docid_for_address(path)
- catalog.reindex_doc(docid, object)
- #catalog.document_map.remove_metadata(docid)
- adapter = queryAdapter(object, IMetadata)
- if adapter is not None:
- metadata = adapter()
- catalog.document_map.add_metadata(docid, metadata)
-
- def set_modified(object, event):
- """ Set the modified date on a single piece of content
- unconditionally (non-recursive); an IObjectModified event
- subscriber"""
- now = datetime.datetime.now()
- object.modified = now
- def set_created(object, event):
- """ Add modified and created attributes to nodes which do not yet
- have them (recursively); an IObjectWillBeAddedEvent subscriber"""
- now = datetime.datetime.now()
- for node in postorder(object):
- if not getattr(node, 'modified', None):
- node.modified = now
- if not getattr(node, 'created', None):
- node.created = now
When ever the event subscribed in configure.zcml is fired, approriate methods (in subscribers.py) is called.
- configure.zcml
-
-
-
-
-
-
- name="static"
- path="templates/static"
- />
-
-
- for="leavemnt.interfaces.ILeave
- repoze.folder.interfaces.IObjectWillBeRemovedEvent"
- handler=".subscribers.unindex_content" />
-
-
- for="leavemnt.interfaces.ILeave
- repoze.folder.interfaces.IObjectAddedEvent"
- handler=".subscribers.index_content" />
-
- for="leavemnt.interfaces.ILeave
- .interfaces.IObjectModifiedEvent"
- handler=".subscribers.reindex_content" />
-
- for="*
- repoze.folder.interfaces.IObjectWillBeAddedEvent"
- handler=".subscribers.set_created" />
-
- for="leavemnt.interfaces.IProfile
- repoze.folder.interfaces.IObjectWillBeRemovedEvent"
- handler=".subscribers.unindex_content" />
-
-
- for="leavemnt.interfaces.IProfile
- repoze.folder.interfaces.IObjectAddedEvent"
- handler=".subscribers.index_content" />
-
- for="leavemnt.interfaces.IProfile
- .interfaces.IObjectModifiedEvent"
- handler=".subscribers.reindex_content" />
-
- for="*
- .interfaces.IObjectModifiedEvent"
- handler=".subscribers.set_modified" />
-
- events.py
- from leavemnt.interfaces import IObjectModifiedEvent
- from leavemnt.interfaces import IObjectWillBeModifiedEvent
- from zope.interface import implements
- class ObjectModifiedEvent(object):
- implements(IObjectModifiedEvent)
- def __init__(self, object):
- print object
- self.object = object
- class ObjectWillBeModifiedEvent(object):
- implements(IObjectWillBeModifiedEvent)
- def __init__(self, object):
- self.object = object
Subscribe to:
Posts (Atom)