Back to index

plone3  3.1.7
Topic.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Topic: Canned catalog queries
00014 
00015 $Id: Topic.py 76996 2007-06-24 00:18:49Z hannosch $
00016 """
00017 
00018 from AccessControl import ClassSecurityInfo
00019 from Acquisition import aq_parent, aq_inner
00020 from Globals import InitializeClass
00021 
00022 from zope.component import getUtility
00023 from zope.component.factory import Factory
00024 from zope.interface import implements
00025 
00026 from Products.CMFDefault.SkinnedFolder import SkinnedFolder
00027 from Products.CMFCore.interfaces import ISyndicationTool
00028 from Products.CMFCore.utils import getToolByName
00029 
00030 from interfaces import IMutableTopic
00031 from interfaces import ITopic
00032 from permissions import View
00033 from permissions import AddTopics
00034 from permissions import ChangeTopics
00035 
00036 
00037 def addTopic(self, id, title='', REQUEST=None):
00038     """ Create an empty topic.
00039     """
00040     topic = Topic( id )
00041     topic.id = id
00042     topic.title = title
00043     self._setObject( id, topic )
00044 
00045     if REQUEST is not None:
00046         REQUEST['RESPONSE'].redirect( 'manage_main' )
00047 
00048 
00049 class Topic(SkinnedFolder):
00050 
00051     """ Topics are 'canned queries'.
00052 
00053     o Each topic holds a set of zero or more Criteria objects specifying
00054       the query.
00055     """
00056 
00057     implements(IMutableTopic, ITopic)
00058 
00059     security = ClassSecurityInfo()
00060     security.declareObjectProtected(View)
00061 
00062     acquireCriteria = True
00063     _criteriaTypes = []
00064 
00065     security.declareProtected(ChangeTopics, 'listCriteria')
00066     def listCriteria(self):
00067         """ Return a list of our criteria objects.
00068         """
00069         return self.objectValues( self._criteria_metatype_ids() )
00070 
00071     security.declareProtected(ChangeTopics, 'listCriteriaTypes')
00072     def listCriteriaTypes(self):
00073         """ List the available criteria types.
00074         """
00075         out = []
00076 
00077         for ct in self._criteriaTypes:
00078             out.append( { 'name': ct.meta_type } )
00079 
00080         return out
00081 
00082     security.declareProtected(ChangeTopics, 'listAvailableFields')
00083     def listAvailableFields(self):
00084         """ Return a list of available fields for new criteria.
00085         """
00086         portal_catalog = getToolByName( self, 'portal_catalog' )
00087         currentfields = map( lambda x: x.Field(), self.listCriteria() )
00088         availfields = filter(
00089             lambda field, cf=currentfields: field not in cf,
00090             portal_catalog.indexes()
00091             )
00092         return availfields
00093 
00094     security.declareProtected(ChangeTopics, 'listSubtopics')
00095     def listSubtopics(self):
00096         """ Return a list of our subtopics.
00097         """
00098         return self.objectValues( self.meta_type )
00099 
00100     security.declareProtected(ChangeTopics, 'edit')
00101     def edit(self, acquireCriteria, title=None, description=None):
00102         """ Set the flag which indicates whether to acquire criteria.
00103 
00104         o If set, reuse creiteria from parent topics;
00105 
00106         o Also update metadata about the Topic.
00107         """
00108         self.acquireCriteria = bool(acquireCriteria)
00109         if title is not None:
00110             self.title = title
00111         self.description = description
00112 
00113         self.reindexObject()
00114 
00115     security.declareProtected(View, 'buildQuery')
00116     def buildQuery(self):
00117         """ Construct a catalog query using our criterion objects.
00118         """
00119         result = {}
00120 
00121         if self.acquireCriteria:
00122 
00123             try:
00124                 # Tracker 290 asks to allow combinations, like this:
00125                 # parent = aq_parent( self )
00126                 parent = aq_parent( aq_inner( self ) )
00127                 result.update( parent.buildQuery() )
00128 
00129             except: # oh well, can't find parent, or it isn't a Topic.
00130                 pass
00131 
00132         for criterion in self.listCriteria():
00133 
00134             for key, value in criterion.getCriteriaItems():
00135                 result[ key ] = value
00136 
00137         return result
00138 
00139     security.declareProtected(View, 'queryCatalog')
00140     def queryCatalog(self, REQUEST=None, **kw):
00141         """ Invoke the catalog using our criteria.
00142 
00143         o Built-in criteria update any criteria passed in 'kw'.
00144         """
00145         kw.update( self.buildQuery() )
00146         portal_catalog = getToolByName( self, 'portal_catalog' )
00147         return portal_catalog.searchResults(REQUEST, **kw)
00148 
00149     security.declareProtected(View, 'synContentValues')
00150     def synContentValues(self):
00151         """ Return a limited subset of the brains for our query.
00152 
00153         o Return no more brain objects than the limit set by the
00154           syndication tool.
00155         """
00156         syn_tool = getUtility(ISyndicationTool)
00157         limit = syn_tool.getMaxItems( self )
00158         brains = self.queryCatalog( sort_limit=limit )[ :limit ]
00159         return [ brain.getObject() for brain in brains ]
00160 
00161     ### Criteria adding/editing/deleting
00162     security.declareProtected(ChangeTopics, 'addCriterion')
00163     def addCriterion(self, field, criterion_type):
00164         """ Add a new search criterion.
00165         """
00166         crit = None
00167         newid = 'crit__%s' % field
00168 
00169         for ct in self._criteriaTypes:
00170 
00171             if criterion_type == ct.meta_type:
00172                 crit = ct( newid, field )
00173 
00174         if crit is None:
00175             # No criteria type matched passed in value
00176             raise NameError, 'Unknown Criterion Type: %s' % criterion_type
00177 
00178         self._setObject( newid, crit )
00179 
00180     security.declareProtected(ChangeTopics, 'deleteCriterion')
00181     def deleteCriterion(self, criterion_id):
00182         """ Delete selected criterion.
00183         """
00184         if type( criterion_id ) is type( '' ):
00185             self._delObject( criterion_id )
00186         elif type( criterion_id ) in ( type( () ), type( [] ) ):
00187             for cid in criterion_id:
00188                 self._delObject( cid )
00189 
00190     security.declareProtected(View, 'getCriterion')
00191     def getCriterion(self, criterion_id):
00192         """ Get the criterion object.
00193         """
00194         try:
00195             return self._getOb( 'crit__%s' % criterion_id )
00196         except AttributeError:
00197             return self._getOb( criterion_id )
00198 
00199     security.declareProtected(AddTopics, 'addSubtopic')
00200     def addSubtopic(self, id):
00201         """ Add a new subtopic.
00202         """
00203         ti = self.getTypeInfo()
00204         ti.constructInstance(self, id)
00205         return self._getOb( id )
00206 
00207     #
00208     #   Helper methods
00209     #
00210     security.declarePrivate('_criteria_metatype_ids')
00211     def _criteria_metatype_ids(self):
00212 
00213         result = []
00214 
00215         for mt in self._criteriaTypes:
00216             result.append( mt.meta_type )
00217 
00218         return tuple( result )
00219 
00220 InitializeClass(Topic)
00221 
00222 TopicFactory = Factory(Topic)