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:
parent
7ec9bbdc15
commit
f9418c1df6
12 changed files with 302 additions and 16 deletions
|
@ -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)))
|
||||
|
|
10
tracking/comment/README.txt
Normal file
10
tracking/comment/README.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
=============
|
||||
Notifications
|
||||
=============
|
||||
|
||||
($Id$)
|
||||
|
||||
>>> from cybertools.tracking.btree import TrackingStorage
|
||||
>>> from cybertools.tracking.notify.base import Notification
|
||||
|
||||
>>> comments = TrackingStorage(trackFactory=Notification)
|
4
tracking/comment/__init__.py
Normal file
4
tracking/comment/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
"""
|
||||
$Id$
|
||||
"""
|
||||
|
33
tracking/comment/base.py
Normal file
33
tracking/comment/base.py
Normal 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)
|
73
tracking/comment/interfaces.py
Normal file
73
tracking/comment/interfaces.py
Normal 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
22
tracking/comment/tests.py
Executable 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')
|
|
@ -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):
|
||||
|
|
10
tracking/notify/README.txt
Normal file
10
tracking/notify/README.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
========
|
||||
Comments
|
||||
========
|
||||
|
||||
($Id$)
|
||||
|
||||
>>> from cybertools.tracking.btree import TrackingStorage
|
||||
>>> from cybertools.tracking.comment.base import Comment
|
||||
|
||||
>>> comments = TrackingStorage(trackFactory=Comment)
|
4
tracking/notify/__init__.py
Normal file
4
tracking/notify/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
"""
|
||||
$Id$
|
||||
"""
|
||||
|
33
tracking/notify/base.py
Normal file
33
tracking/notify/base.py
Normal 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)
|
70
tracking/notify/interfaces.py
Normal file
70
tracking/notify/interfaces.py
Normal 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
22
tracking/notify/tests.py
Executable 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')
|
Loading…
Add table
Reference in a new issue