[CMF-checkins] CVS: CMF - update_discussion.py:1.1
tseaver@digicool.com
tseaver@digicool.com
Thu, 14 Jun 2001 16:27:47 -0400 (EDT)
Update of /cvs-repository/CMF/CMFDefault/Extensions
In directory korak.digicool.com:/tmp/cvs-serv30518/Extensions
Added Files:
update_discussion.py
Log Message:
- Adds a set of baseline unit tests for the discussions
machinery, including tests for:
o policy checks (whether discussions are allowable)
o nested replies
o cataloguing of replies
o propagation of 'manage_beforeDelete' from the host content
object, and correct un-cataloguing.
- Cleans up a lot of cruft, including fossilized inheritance,
old-style security declarations, etc., in
CMFDefault.DiscussionItem. In particular, DiscussionItem
now implements the DiscussionResponse interface directly,
instead of mixing in the older implementation.
- Replaces the current "path-based" 'in_reply_to' with a simpler,
more robust scheme.
o The old version was a legacy of the much older usage, which
had discussion items in users' "Correspondence" folders, and
assembled them into threads using catalog queries; it was
fragile in the face of moves or renames of the "host"
content object.
o The new scheme stores 'None' in the 'in_reply_to' field to
indicate that the item is a "top-level" reply to the host
content object, or the simple ID of the sibling, for
threaded replies.
- Refactors the skins for discussions a bit, moving the "above
in thread" logic into a separate method, and adding a special
view for DiscussionItems which uses it.
- Adds an 'upgrade_discussion' ExternalMethod to CMFDefault;
this method:
1. Installs (if one isn't already there) a
FactoryTypeInformation object for DiscussionItems. This
FTI is "crippled" for adding objects (no factory/product),
but provides a hook on which to hang the custom view, and
set other type-specific policies.
2. Removes the "(default)" workflow for DiscussionItems, so
as not to present the "Retract", etc. actions; later, we
might add a special workflow, to permit sufficiently
privileged users to delete replies.
3. Updates existing DiscussionItems to conform to the new
scheme.
--- Added File update_discussion.py in package CMF ---
import string
from Products.CMFCore.TypesTool import FactoryTypeInformation
from Products.CMFDefault import DiscussionItem
def update_discussion( self, split=string.split ):
"""
1. Install (if it isn't there already) a type information
object for DiscussionItems, so that they can get actions,
etc. Erase the "(default)" workflow bound to it, to prevent
showing the "Retract" options, etc.
2. Update all DiscussionItems to use the new marking for
'in_reply_to':
- Items which are replies to the containing content object
have None as their 'in_reply_to';
- Items which are replies to sibling items have the sibling's
ID as their 'in_reply_to'.
The representation we are converting from was:
- Items which are replies to the containing content object
have the portal-relative pathstring of the content object
as their 'in_reply_to';
- Items which are replies to sibling items have the absolute
path of the sibling as their 'in_reply_to'.
"""
log = []
a = log.append
types_tool = self.portal_types
if not getattr( types_tool, 'Discussion Item', None ):
fti = apply( FactoryTypeInformation
, ()
, DiscussionItem.factory_type_information[0]
)
types_tool._setObject( 'Discussion Item', fti )
a( 'Added type object for DiscussionItem' )
workflow_tool = self.portal_workflow
workflow_tool.setChainForPortalTypes( ( 'Discussion Item', ), () )
a( 'Erased workflow for DiscussionItem' )
items = self.portal_catalog.searchResults( meta_type='Discussion Item' )
a( 'DiscussionItems updated:' )
for item in items:
object = item.getObject()
talkback = object.aq_parent
path = item.getPath()
in_reply_to = object.in_reply_to
if in_reply_to is None: # we've been here already
continue
irt_elements = split( in_reply_to, '/' )
if len( irt_elements ) == 1:
if talkback._container.get( irt_elements[0] ):
# we've been here already
continue
if irt_elements[0] == '': # absolute, so we are IRT a sibling
sibling_id = irt_elements[ -1 ]
if talkback._container.get( sibling_id, None ):
in_reply_to = sibling_id
else:
in_reply_to = None
else:
in_reply_to = None
object.in_reply_to = in_reply_to
assert object.inReplyTo() # sanity check
object.reindexObject()
a( path )
return string.join( log, '\n' )