diff --git a/tracking/comment/tests.py b/tracking/comment/tests.py index 6c7ef8b..33448a6 100755 --- a/tracking/comment/tests.py +++ b/tracking/comment/tests.py @@ -5,7 +5,7 @@ from zope.testing.doctestunit import DocFileSuite class Test(unittest.TestCase): - "Basic tests for the cybertools.tracking.notify package." + "Basic tests for the cybertools.tracking.comment package." def testBasics(self): pass diff --git a/tracking/notify/README.txt b/tracking/notify/README.txt index 8fd7fc7..3ecfdbb 100644 --- a/tracking/notify/README.txt +++ b/tracking/notify/README.txt @@ -1,10 +1,31 @@ -======== -Comments -======== +============= +Notifications +============= ($Id$) + >>> from zope import component >>> from cybertools.tracking.btree import TrackingStorage - >>> from cybertools.tracking.comment.base import Comment + >>> from cybertools.tracking.notify.base import Notification, NotificationManager + >>> component.provideAdapter(NotificationManager) - >>> comments = TrackingStorage(trackFactory=Comment) + >>> notifications = TrackingStorage(trackFactory=Notification) + + >>> from cybertools.tracking.notify.interfaces import INotificationManager + >>> manager = INotificationManager(notifications) + + +Storing and Retrieving Notifications +==================================== + + >>> manager.notify('obj01', 'user01', 'object_changed') + + >>> ntf01 = manager.query(userName='user01')[0] + >>> ntf01 + + + >>> print ntf01.state + new + >>> print ntf01.timingType + None diff --git a/tracking/notify/base.py b/tracking/notify/base.py index bbe9155..2f7d57b 100644 --- a/tracking/notify/base.py +++ b/tracking/notify/base.py @@ -22,12 +22,45 @@ Base classes for a notification framework. $Id$ """ +from zope.component import adapts from zope.interface import implements from cybertools.tracking.btree import Track -from cybertools.tracking.notify.interfaces import INotification +from cybertools.tracking.interfaces import ITrackingStorage +from cybertools.tracking.notify.interfaces import INotification, INotificationManager + + +class NotificationManager(object): + + implements(INotificationManager) + adapts(ITrackingStorage) + + def __init__(self, context): + self.context = context + + def notify(self, taskId, userName, ntfType, media=None, priority='info', **kw): + runId = self.context.startRun() + if media is None: + media = ['inbox'] + data = dict(type=ntfType, state='new', media=media) + data.update(kw) + self.context.saveUserTrack(taskId, runId, userName, data) + + def cleanUp(self, age=1, removeIgnored=False): + pass + + def query(self, **kw): + return self.context.query(**kw) class Notification(Track): implements(INotification) + + typeName = 'Notification' + + def __getattr__(self, attr): + if attr in INotification: + return self.data.get(attr) + raise AttributeError(attr) + diff --git a/tracking/notify/interfaces.py b/tracking/notify/interfaces.py index cb98233..9b433ca 100644 --- a/tracking/notify/interfaces.py +++ b/tracking/notify/interfaces.py @@ -28,10 +28,29 @@ from zope import schema from cybertools.tracking.interfaces import ITrack +class INotificationManager(Interface): + """ Provides methods for working with notifications. + + Typically used as an adapter for ITrackingStorage objects. + """ + + def notify(taskId, userName, type, media=None, **kw): + """ Create a notification object according to the information given. + """ + + def cleanUp(age=1, removeIgnored=False): + """ Remove old (finished) runs and (done) tracks; the last change + (timeStamp) being before ``now - age`` days. + + If the ``removeIgnored`` argument is True remove also tracks + in ``ignored`` state. + """ + + class INotification(ITrack): """ A notification carries information necessary to inform a - receiver (typically a user or person, but possibly also an other - entity) about an event. + receiver (typically a user or person, but possibly also another + kind of entity) about an event. The object the notification is related to is referenced via the task id attribute; interdependent notifications (i.e. notifications that are triggered by the identical event or have been created @@ -40,20 +59,22 @@ class INotification(ITrack): """ type = Attribute('A string (token) that specifies the ' - 'type of the notification.') # TODO: vocabulary + 'type of the notification.') state = Attribute('A string (token) specifying the ' - 'current state of the notification.') # TODO: vocabulary + 'current state of the notification.') + priority = Attribute('A string (token) specifying the ' + 'priority/importance of the notification.') parent = Attribute('The id of the parent notification, i.e. the ' 'notification that triggered the creation of this one. ' 'None if there is not parent notification.') eventType = Attribute('A string (token or title) that specifies the ' 'type of the event that triggered this notification.') - media = Attribute('A string (token) specifying the ' - 'media type that will be used for presenting ' - 'the notification.') # TODO: vocabulary + media = Attribute('A collection of strings (tokens) specifying the ' + 'media types that will be used for presenting ' + 'the notification.') timingType = Attribute('A string (token) specifying the ' 'type of timing that will be used for presenting ' - 'the notification.') # TODO: vocabulary + 'the notification.') timing = Attribute('A list of (typically) time/date values specifying ' 'the time range for presentation. The possible values and ' 'their interpretation depend on the timing type.') @@ -67,4 +88,11 @@ class INotification(ITrack): # media + timingType + timing + deliveryInfo could be combined to # a `deliverySpec` attribute. - # TODO: Action class (type + instance); vocabulary of action types +types = ('object_changed', 'object_new', 'invitation', 'assignment') +states = ('new', 'active', 'deferred', 'done', 'ignored') +priorities = ('critical', 'important', 'normal', 'info') +media = ('inbox', 'mail', 'im', 'rss') +timingTypes = ('immediate', 'hourly', 'daily', 'explicit') +actionTypes = ('accept', 'reject', 'ignore', 'note', 'delegate') + + # TODO: Action class (type + instance) diff --git a/tracking/notify/tests.py b/tracking/notify/tests.py index 33448a6..6c7ef8b 100755 --- a/tracking/notify/tests.py +++ b/tracking/notify/tests.py @@ -5,7 +5,7 @@ from zope.testing.doctestunit import DocFileSuite class Test(unittest.TestCase): - "Basic tests for the cybertools.tracking.comment package." + "Basic tests for the cybertools.tracking.notify package." def testBasics(self): pass