From acf00c9de91b8a1d078408089c1f417e5ce150f9 Mon Sep 17 00:00:00 2001 From: Lennart Regebro Date: Sun, 17 May 2009 18:38:45 +0000 Subject: [PATCH] Moved the indexing to be a catalog wrapper. svn path=/plone.app.discussion/trunk/; revision=27005 --- plone/app/discussion/conversation.py | 7 +- .../profiles/default/componentregistry.xml | 2 +- .../discussion/profiles/default/toolset.xml | 5 + plone/app/discussion/tests/test_api.py | 5 +- plone/app/discussion/tests/test_tool.py | 9 +- plone/app/discussion/tool.py | 93 ++++++++++--------- 6 files changed, 73 insertions(+), 48 deletions(-) create mode 100644 plone/app/discussion/profiles/default/toolset.xml diff --git a/plone/app/discussion/conversation.py b/plone/app/discussion/conversation.py index 6bc4437..19705a9 100644 --- a/plone/app/discussion/conversation.py +++ b/plone/app/discussion/conversation.py @@ -115,7 +115,9 @@ class Conversation(Persistent, Explicit): if not reply_to in self._children: self._children[reply_to] = LLSet() self._children[reply_to].insert(id) - notify(ObjectAddedEvent(comment, self, id)) + # Notify that the object is added. The object must here be + # acquisition wrapped or the indexing will fail. + notify(ObjectAddedEvent(comment.__of__(self), self, id)) notify(ContainerModifiedEvent(self)) # Dict API @@ -137,6 +139,9 @@ class Conversation(Persistent, Explicit): def keys(self): return self._comments.keys() + def getPhysicalPath(self): + return self.aq_parent.getPhysicalPath() + (self.id,) + # TODO: Update internal data structures when items added or removed @implementer(IConversation) diff --git a/plone/app/discussion/profiles/default/componentregistry.xml b/plone/app/discussion/profiles/default/componentregistry.xml index 9764a7f..35f1a08 100644 --- a/plone/app/discussion/profiles/default/componentregistry.xml +++ b/plone/app/discussion/profiles/default/componentregistry.xml @@ -3,7 +3,7 @@ diff --git a/plone/app/discussion/profiles/default/toolset.xml b/plone/app/discussion/profiles/default/toolset.xml new file mode 100644 index 0000000..0823a74 --- /dev/null +++ b/plone/app/discussion/profiles/default/toolset.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/plone/app/discussion/tests/test_api.py b/plone/app/discussion/tests/test_api.py index 96d552b..dc2642c 100644 --- a/plone/app/discussion/tests/test_api.py +++ b/plone/app/discussion/tests/test_api.py @@ -29,7 +29,10 @@ class ConversationTest(TestCase): # Create a conversation. In this case we doesn't assign it to an # object, as we just want to check the Conversation object API. conversation = IConversation(self.portal.doc1) - + # Pretend that we have traversed to the comment by aq wrapping it. + # XXX implement traversal to commenting and change this: + conversation = conversation.__of__(self.portal.doc1) + # Add a comment. reply_to=0 means it's not a reply comment = Comment(conversation=conversation, reply_to=0) comment.title = 'Comment 1' diff --git a/plone/app/discussion/tests/test_tool.py b/plone/app/discussion/tests/test_tool.py index 730e143..7c7126f 100644 --- a/plone/app/discussion/tests/test_tool.py +++ b/plone/app/discussion/tests/test_tool.py @@ -29,6 +29,9 @@ class ToolTest(TestCase): # Create a conversation. In this case we doesn't assign it to an # object, as we just want to check the Conversation object API. conversation = IConversation(self.portal.doc1) + # Pretend that we have traversed to the comment by aq wrapping it. + # XXX implement traversal to commenting and change this: + conversation = conversation.__of__(self.portal.doc1) # Add a comment. reply_to=0 means it's not a reply comment = Comment(conversation=conversation, reply_to=0) @@ -39,8 +42,10 @@ class ToolTest(TestCase): # Check that the comment got indexed in the tool: tool = getUtility(ICommentingTool) - comment = list(tool.search())[0] - self.assertEquals(comment['text'], 'Comment text') + comment = list(tool.searchResults()) + self.assert_(len(comment) == 1, "There is only one comment, but we got" + " %s results in the search" % len(comment)) + self.assertEquals(comment[0].Title, 'Comment 1') def test_suite(): diff --git a/plone/app/discussion/tool.py b/plone/app/discussion/tool.py index 1c90d1b..c37a011 100644 --- a/plone/app/discussion/tool.py +++ b/plone/app/discussion/tool.py @@ -2,58 +2,65 @@ import time from zope import interface from zope.component import getUtility -from BTrees.OOBTree import OOBTree, OOSet, intersection - -from interfaces import ICommentingTool +from interfaces import ICommentingTool, IComment # The commenting tool, which is a local utility -class CommentingTool(object): +from Products.CMFCore.utils import UniqueObject, getToolByName +from OFS.SimpleItem import SimpleItem + +class CommentingTool(UniqueObject, SimpleItem): + interface.implements(ICommentingTool) - def __init__(self): - self._id2uid = OOBTree() # The comment ID to object UID - self._id2text = OOBTree() # The text for a comment - self._wfstate2id = OOBTree() # To search on wf states - self._creator2id = OOBTree() # To search/order on creator ids - - def index(self, comment): - # Store the object in the store: - id = comment.comment_id - self._id2uid[id] = comment.__parent__._parent_uid - self._id2text[id] = comment.text + meta_type = 'plone.app.discussion tool' + id = 'portal_discussion' + + def reindexObject(self, object): + """Remove from catalog. + """ + catalog = getToolByName(self, 'portal_catalog') + return catalog.reindexObject(object) + + indexObject = reindexObject - # TODO - ## Index on workflow state - #wfstate = comment.getWorkflowState() - #if not wfstate in self._wfstate2id: - #self._wfstate2id[wfstate] = OOSet() - #self._wfstate2id[wfstate].insert(id) + def unindexObject(self, object): + """Remove from catalog. + """ + catalog = getToolByName(self, 'portal_catalog') + return catalog.unindexObject(object) + + def uniqueValuesFor(self, name): + """ return unique values for FieldIndex name """ + catalog = getToolByName(self, 'portal_catalog') + return catalog.uniqueValuesFor(name) - # Index on creator - creator = comment.creator - if not creator in self._creator2id: - self._creator2id[creator] = OOSet() - self._creator2id[creator].insert(id) - - def search(self, creator=None): - if creator is not None: - # Get all replies for a certain object - ids = self._creator2ids.get(creator, None) - if ids is None: - raise StopIteration - else: - ids = self._id2uid.keys() - - for id in ids: - yield {'id': id, - 'text': self._id2text[id] - # TODO: More data + maybe brains or something? - } + def searchResults(self, REQUEST=None, **kw): + """ + Calls ZCatalog.searchResults with extra arguments that + limit the results to what the user is allowed to see. + """ + catalog = getToolByName(self, 'portal_catalog') + object_provides = [IComment.__identifier__] + if 'object_provides' in kw: + kw_provides = kw['object_provides'] + if isinstance(str, kw_provides): + object_provides.append(kw_provides) + else: + object_provides.extend(kw_provides) + if REQUEST is not None and 'object_provides' in REQUEST.form: + rq_provides = REQUEST.form['object_provides'] + del REQUEST.form['object_provides'] + if isinstance(str, rq_provides): + object_provides.append(rq_provides) + else: + object_provides.extend(rq_provides) + kw['object_provides'] = object_provides + return catalog.searchResults(REQUEST, **kw) def object_added_handler(obj, event): tool = getUtility(ICommentingTool) - tool.index(obj) + tool.indexObject(obj) def object_removed_handler(obj, event): tool = getUtility(ICommentingTool) - tool.unindex(obj) + tool.unindexObject(obj)