started work on comment (discussions) and notify (notifications)

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2389 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2008-02-11 22:29:25 +00:00
parent 7ec9bbdc15
commit f9418c1df6
12 changed files with 302 additions and 16 deletions

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -17,7 +17,7 @@
#
"""
BTree-based implementation of user interaction tracking.
ZODB-/BTree-based implementation of user interaction tracking.
$Id$
"""
@ -84,6 +84,7 @@ class Track(Persistent):
return '<Track %s: %s>' % (`[md[a] for a in self.metadata_attributes]`,
`self.data`)
class TrackingStorage(BTreeContainer):
implements(ITrackingStorage)
@ -93,10 +94,13 @@ class TrackingStorage(BTreeContainer):
trackNum = runId = 0
runs = None
#indexAttributes = ('taskId', 'runId', 'userName', 'timeStamp')
indexAttributes = Track.index_attributes
def __init__(self, *args, **kw):
trackFactory = kw.pop('trackFactory', None)
if trackFactory is not None:
self.trackFactory = trackFactory
self.indexAttributes = trackFactory.index_attributes
super(TrackingStorage, self).__init__(*args, **kw)
self.indexes = OOBTree.OOBTree()
for idx in self.indexAttributes:
@ -117,10 +121,11 @@ class TrackingStorage(BTreeContainer):
def idFromNum(self, num):
return '%07i' % (num)
def startRun(self, taskId):
def startRun(self, taskId=None):
self.runId += 1
runId = self.runId
self.currentRuns[taskId] = runId
if taskId is not None:
self.currentRuns[taskId] = runId
run = self.runs[runId] = Run(runId)
run.start = run.end = getTimeStamp()
return runId
@ -147,6 +152,11 @@ class TrackingStorage(BTreeContainer):
return self.runs.get(runId)
return None
def generateTrackId(self):
self.trackNum += 1
trackId = self.idFromNum(self.trackNum)
return trackId, self.trackNum
def saveUserTrack(self, taskId, runId, userName, data, update=False):
if not runId:
runId = self.currentRuns.get(taskId) or self.startRun(taskId)
@ -154,15 +164,11 @@ class TrackingStorage(BTreeContainer):
if run is None:
raise ValueError('Invalid run: %i.' % runId)
run.end = getTimeStamp()
trackNum = 0
if update:
track = self.getLastUserTrack(taskId, runId, userName)
if track is not None:
return self.updateTrack(track, data)
if not trackNum:
self.trackNum += 1
trackNum = self.trackNum
trackId = self.idFromNum(trackNum)
trackId, trackNum = self.generateTrackId()
track = self.trackFactory(taskId, runId, userName, data)
self[trackId] = track
self.indexTrack(trackNum, track)
@ -211,12 +217,10 @@ class TrackingStorage(BTreeContainer):
if idx in self.indexAttributes:
if type(value) not in (list, tuple):
value = [value]
# TODO: handle a list of values, provide union of results
resultx = None
for v in value:
resultx = self.union(resultx, self.indexes[idx].apply((v, v)))
result = self.intersect(result, resultx)
#result = self.intersect(result, self.indexes[idx].apply((value, value)))
elif idx == 'timeFrom':
result = self.intersect(result,
self.indexes['timeStamp'].apply((value, None)))

View file

@ -0,0 +1,10 @@
=============
Notifications
=============
($Id$)
>>> from cybertools.tracking.btree import TrackingStorage
>>> from cybertools.tracking.notify.base import Notification
>>> comments = TrackingStorage(trackFactory=Notification)

View file

@ -0,0 +1,4 @@
"""
$Id$
"""

33
tracking/comment/base.py Normal file
View file

@ -0,0 +1,33 @@
#
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Basic implementation of comments / discussions.
$Id$
"""
from zope.interface import implements
from cybertools.tracking.btree import Track
from cybertools.tracking.comment.interfaces import IComment
class Comment(Track):
implements(IComment)

View file

@ -0,0 +1,73 @@
#
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Interface definitions for comments - discussions - forums.
$Id$
"""
from zope.interface import Interface, Attribute
from zope import schema
from cybertools.tracking.interfaces import ITrack
class IComment(ITrack):
""" A comment is a piece of text provided by a user and related
to a content object.
The object the comment is related to is referenced via the
task id attribute; interdependent comments (i.e. comments in a
parent/child hierarchy related to the same object share the
run id; the user name references the user/person that created
the comment.
"""
parent = Attribute('The id of the parent comment; None for '
'the top-level comment.')
subject = schema.TextLine(
title=u'Subject',
description=u'A short informative line of text.',
default=u'', # should be taken from the parent
required=True)
text = schema.Text(
title=u'Text',
description=u'The text of the comment.',
default=u'',
required=True)
contentType = schema.BytesLine(
title=u'Content Type',
description=u'Content type (format) of the text field',
# TODO: provide a source/vocabulary
default='text/restructured',
required=True)
def getChildren(sort='default'):
""" Returns the immediate children in the order specified by the sort
argument; the return value is a sequence of track ids.
The default sorting is by timestamp, newest first.
"""
def getChildrenTree(sort='default', depth=0):
""" Returns the children as a tree, in the order specified by
the sort argument. If depth is greater than 0 only that level
of children will be returned.
The return value is a nested sequence of track ids.
"""

22
tracking/comment/tests.py Executable file
View file

@ -0,0 +1,22 @@
# $Id$
import unittest, doctest
from zope.testing.doctestunit import DocFileSuite
class Test(unittest.TestCase):
"Basic tests for the cybertools.tracking.notify package."
def testBasics(self):
pass
def test_suite():
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
return unittest.TestSuite((
unittest.makeSuite(Test),
DocFileSuite('README.txt', optionflags=flags),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -17,7 +17,7 @@
#
"""
loops tracking interface definitions.
Interface definitions for tracking of user interactions.
$Id$
"""
@ -51,8 +51,9 @@ class ITrackingStorage(Interface):
""" A utility for storing user tracks.
"""
def startRun(taskId):
""" Create a new run for the task given and return its id.
def startRun(taskId=None):
""" Create a new run and return its id.
If a taskId is given, record the runId as the tasks current run.
"""
def stopRun(taskId=None, runId=0, finish=True):

View file

@ -0,0 +1,10 @@
========
Comments
========
($Id$)
>>> from cybertools.tracking.btree import TrackingStorage
>>> from cybertools.tracking.comment.base import Comment
>>> comments = TrackingStorage(trackFactory=Comment)

View file

@ -0,0 +1,4 @@
"""
$Id$
"""

33
tracking/notify/base.py Normal file
View file

@ -0,0 +1,33 @@
#
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Base classes for a notification framework.
$Id$
"""
from zope.interface import implements
from cybertools.tracking.btree import Track
from cybertools.tracking.notify.interfaces import INotification
class Notification(Track):
implements(INotification)

View file

@ -0,0 +1,70 @@
#
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Interface definitions for a notification framework.
$Id$
"""
from zope.interface import Interface, Attribute
from zope import schema
from cybertools.tracking.interfaces import ITrack
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.
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
by another notification) share the run id; the user name references
the user/person that will be notified.
"""
type = Attribute('A string (token) that specifies the '
'type of the notification.') # TODO: vocabulary
state = Attribute('A string (token) specifying the '
'current state of the notification.') # TODO: vocabulary
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
timingType = Attribute('A string (token) specifying the '
'type of timing that will be used for presenting '
'the notification.') # TODO: vocabulary
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.')
deliveryInfo = Attribute('Additional information needed for the '
'delivery of the notification, e.g. an email address.')
actionsPossible = Attribute('A collection of possible actions the receiver '
'may take in response to the notification.')
actionsTaken = Attribute('One or more actions that have been carried '
'out in response to the notification.')
# media + timingType + timing + deliveryInfo could be combined to
# a `deliverySpec` attribute.
# TODO: Action class (type + instance); vocabulary of action types

22
tracking/notify/tests.py Executable file
View file

@ -0,0 +1,22 @@
# $Id$
import unittest, doctest
from zope.testing.doctestunit import DocFileSuite
class Test(unittest.TestCase):
"Basic tests for the cybertools.tracking.comment package."
def testBasics(self):
pass
def test_suite():
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
return unittest.TestSuite((
unittest.makeSuite(Test),
DocFileSuite('README.txt', optionflags=flags),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')