class CatalogTool(UniqueObject, ZCatalog, ActionProviderBase): """ This is a ZCatalog that filters catalog queries. """ __implements__ = (ICatalogTool, ActionProviderBase.__implements__) id = 'portal_catalog' meta_type = 'CMF Catalog' _actions = () security = ClassSecurityInfo() manage_options = (ZCatalog.manage_options + ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, )) def __init__(self): ZCatalog.__init__(self, self.getId()) if not hasattr(self, 'Vocabulary'): # As of 2.6, the Catalog no longer adds a vocabulary in itself from Products.PluginIndexes.TextIndex.Vocabulary import Vocabulary vocabulary = Vocabulary('Vocabulary', 'Vocabulary', globbing=1) self._setObject('Vocabulary', vocabulary) self._initIndexes() # # Subclass extension interface # security.declarePublic('enumerateIndexes') # Subclass can call def enumerateIndexes(self): # Return a list of ( index_name, type ) pairs for the initial # index set. # id is depricated and may go away, use getId! return (('Title', 'TextIndex'), ('Subject', 'KeywordIndex'), ('Description', 'TextIndex'), ('Creator', 'FieldIndex'), ('SearchableText', 'TextIndex'), ('Date', 'FieldIndex'), ('Type', 'FieldIndex'), ('created', 'FieldIndex'), ('effective', 'FieldIndex'), ('expires', 'FieldIndex'), ('modified', 'FieldIndex'), ('allowedRolesAndUsers', 'KeywordIndex'), ('review_state', 'FieldIndex'), ('in_reply_to', 'FieldIndex'), ('meta_type', 'FieldIndex'), ('id', 'FieldIndex'), ('getId', 'FieldIndex'), ('path', 'PathIndex'), ('portal_type', 'FieldIndex')) security.declarePublic('enumerateColumns') def enumerateColumns(self): # Return a sequence of schema names to be cached. # id is depricated and may go away, use getId! return ('Subject', 'Title', 'Description', 'Type', 'review_state', 'Creator', 'Date', 'getIcon', 'created', 'effective', 'expires', 'modified', 'CreationDate', 'EffectiveDate', 'ExpiresDate', 'ModificationDate', 'id', 'getId', 'portal_type') def _initIndexes(self): base = aq_base(self) if hasattr(base, 'addIndex'): # Zope 2.4 addIndex = self.addIndex else: # Zope 2.3 and below addIndex = self._catalog.addIndex if hasattr(base, 'addColumn'): # Zope 2.4 addColumn = self.addColumn else: # Zope 2.3 and below addColumn = self._catalog.addColumn # Content indexes self._catalog.indexes.clear() for index_name, index_type in self.enumerateIndexes(): addIndex(index_name, index_type) # Cached metadata self._catalog.names = () self._catalog.schema.clear() for column_name in self.enumerateColumns(): addColumn(column_name) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainCatalogTool', _dtmldir) # # 'portal_catalog' interface methods # def _listAllowedRolesAndUsers(self, user): result = list(user.getRoles()) result.append('Anonymous') result.append('user:%s' % user.getId()) return result # searchResults has inherited security assertions. def searchResults(self, REQUEST=None, **kw): """ Calls ZCatalog.searchResults with extra arguments that limit the results to what the user is allowed to see. """ user = _getAuthenticatedUser(self) kw['allowedRolesAndUsers'] = self._listAllowedRolesAndUsers(user) if not _checkPermission(AccessInactivePortalContent, self): base = aq_base(self) now = DateTime() if hasattr(base, 'addIndex'): # Zope 2.4 and above kw['effective'] = {'query': now, 'range': 'max'} kw['expires'] = {'query': now, 'range': 'min'} else: # Zope 2.3 kw['effective'] = kw['expires'] = now kw['effective_usage'] = 'range:max' kw['expires_usage'] = 'range:min' return apply(ZCatalog.searchResults, (self, REQUEST), kw) __call__ = searchResults def __url(self, ob): return '/'.join(ob.getPhysicalPath()) manage_catalogFind = DTMLFile('catalogFind', _dtmldir) def catalog_object(self, object, uid, idxs=[]): # Wraps the object with workflow and accessibility # information just before cataloging. wf = getattr(self, 'portal_workflow', None) if wf is not None: vars = wf.getCatalogVariablesFor(object) else: vars = {} w = IndexableObjectWrapper(vars, object) ZCatalog.catalog_object(self, w, uid, idxs) security.declarePrivate('indexObject') def indexObject(self, object): '''Add to catalog. ''' url = self.__url(object) self.catalog_object(object, url) security.declarePrivate('unindexObject') def unindexObject(self, object): '''Remove from catalog. ''' url = self.__url(object) self.uncatalog_object(url) security.declarePrivate('reindexObject') def reindexObject(self, object, idxs=[]): '''Update catalog after object data has changed. The optional idxs argument is a list of specific indexes to update (all of them by default). ''' url = self.__url(object) if idxs != []: # Filter out invalid indexes. valid_indexes = self._catalog.indexes.keys() idxs = [i for i in idxs if i in valid_indexes] self.catalog_object(object, url, idxs=idxs)
class ODFFile(File): """ ODFFile class """ meta_type = "OpenDocument File" # icon = 'misc_/ODFFile/presentation' # manage_options = ( # (File.manage_options[5], # File.manage_options[3], # File.manage_options[6],) # ) security = ClassSecurityInfo() def __init__(self, id, title, file, suffix, content_type='', precondition='', conversion='embedded'): """ constructor """ self.xhtml = "<h1>Nothing uploaded</h1>" self.conversion = conversion self.suffix = suffix self._pictures = {} File.__dict__['__init__'](self, id, title, file, content_type, precondition) ########################### # ZMI FORMS # ########################### security.declareProtected(view, 'index_html') def index_html(self, REQUEST=None, RESPONSE=None): """ Show the HTML part """ if REQUEST.has_key('pict'): return self.Pictures(REQUEST['pict'], REQUEST, RESPONSE) rsp = [] if self.conversion == 'embedded': rsp.append(self.standard_html_header(self, REQUEST, RESPONSE)) rsp.append(self.xhtml) if self.conversion == 'embedded': rsp.append(self.standard_html_footer(self, REQUEST, RESPONSE)) return (''.join(rsp)) manage_editForm = DTMLFile('dtml/odfEdit', globals()) manage_editForm._setName('manage_editForm') manage = manage_main = manage_editForm manage_uploadForm = manage_editForm def manage_edit(self, title, content_type, precondition='', filedata=None, conversion='none', REQUEST=None): """ Changes the title and content type attributes of the OpenDocument File. """ ODFFile.inheritedAttribute('manage_edit')(self, title, content_type, precondition, filedata) conversion = str(conversion) if self.conversion != conversion: self.conversion = conversion self.update_xhtml() if REQUEST: message = "Saved changes." return self.manage_main(self, REQUEST, manage_tabs_message=message) security.declareProtected(change_images_and_files, 'uploadFile') def uploadFile(self, file): """ asociates a file to the ODFFile object """ data, size = self._read_data(file) content_type = self._get_content_type(file, data, self.__name__, 'undefined') self.update_data(data, content_type, size) self._p_changed = 1 security.declareProtected(view, 'download') def download(self, REQUEST, RESPONSE): """ set for download asociated file """ self.REQUEST.RESPONSE.setHeader('Content-Type', self.content_type) self.REQUEST.RESPONSE.setHeader('Content-Length', self.size) self.REQUEST.RESPONSE.setHeader( 'Content-Disposition', 'attachment;filename="' + self.id() + self.suffix + '"') return ODFFile.inheritedAttribute('index_html')(self, REQUEST, RESPONSE) security.declareProtected(view, 'download') def picture_list(self, REQUEST, RESPONSE): """ Show list of pictures """ return "\n".join(self._pictures.keys()) security.declareProtected(view, 'download') def Pictures(self, pict, REQUEST, RESPONSE): """ set for download asociated file """ suffices = { 'wmf': 'image/x-wmf', 'png': 'image/png', 'gif': 'image/gif', 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg' } suffix = pict[pict.rfind(".") + 1:] ct = suffices.get(suffix, 'application/octet-stream') self.REQUEST.RESPONSE.setHeader('Content-Type', ct) return self._pictures[pict] def _save_pictures(self, fd): self._pictures = {} z = zipfile.ZipFile(fd) for zinfo in z.infolist(): if zinfo.filename[0:9] == 'Pictures/': pictname = zinfo.filename[9:] self._pictures[pictname] = z.read(zinfo.filename) z.close() # private update_xhtml__roles__ = () def update_xhtml(self): if self.size == 0: return if self.conversion == 'embedded': odhandler = ODF2XHTMLBody(embedable=True) else: odhandler = ODF2XHTMLBody(embedable=False) fd = StringIO(str(self.data)) self._save_pictures(fd) fd.seek(0) self.xhtml = odhandler.odf2xhtml(fd).encode('us-ascii', 'xmlcharrefreplace') self.title = odhandler.title update_data__roles__ = () def update_data(self, data, content_type=None, size=None): File.__dict__['update_data'](self, data, content_type, size) suffix = odmimetypes.get(content_type) if suffix: self.suffix = suffix self.update_xhtml()
class Document(PortalContent, DefaultDublinCoreImpl): """ A Document - Handles both StructuredText and HTML """ __implements__ = (PortalContent.__implements__, DefaultDublinCoreImpl.__implements__) meta_type = 'Document' effective_date = expiration_date = None cooked_text = text = text_format = '' _isDiscussable = 1 _stx_level = 1 # Structured text level _last_safety_belt_editor = '' _last_safety_belt = '' _safety_belt = '' security = ClassSecurityInfo() def __init__(self, id, title='', description='', text_format='', text=''): DefaultDublinCoreImpl.__init__(self) self.id = id self.title = title self.description = description self._edit(text=text, text_format=text_format) self.setFormat(text_format) security.declareProtected(ModifyPortalContent, 'manage_edit') manage_edit = DTMLFile('zmi_editDocument', _dtmldir) security.declareProtected(ModifyPortalContent, 'manage_editDocument') def manage_editDocument(self, text, text_format, file='', REQUEST=None): """ A ZMI (Zope Management Interface) level editing method """ Document.edit(self, text_format=text_format, text=text, file=file) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/manage_edit' + '?manage_tabs_message=Document+updated') def _edit(self, text, text_format='', safety_belt=''): """ Edit the Document and cook the body. """ if not self._safety_belt_update(safety_belt=safety_belt): msg = ("Intervening changes from elsewhere detected." " Please refetch the document and reapply your changes." " (You may be able to recover your version using the" " browser 'back' button, but will have to apply them" " to a freshly fetched copy.)") raise EditingConflict(msg) self.text = text if not text_format: text_format = self.text_format if text_format == 'html': self.cooked_text = text elif text_format == 'plain': self.cooked_text = html_quote(text).replace('\n', '<br />') else: self.cooked_text = HTML(text, level=self._stx_level, header=0) security.declareProtected(ModifyPortalContent, 'edit') def edit(self, text_format, text, file='', safety_belt=''): """ To add webDav support, we need to check if the content is locked, and if so return ResourceLockedError if not, call _edit. Note that this method expects to be called from a web form, and so disables header processing """ self.failIfLocked() if file and (type(file) is not type('')): contents = file.read() if contents: text = contents if html_headcheck(text): text = bodyfinder(text) self.setFormat(text_format) self._edit(text=text, text_format=text_format, safety_belt=safety_belt) self.reindexObject() security.declareProtected(ModifyPortalContent, 'setMetadata') def setMetadata(self, headers): headers['Format'] = self.Format() new_subject = keywordsplitter(headers) headers['Subject'] = new_subject or self.Subject() new_contrib = contributorsplitter(headers) headers['Contributors'] = new_contrib or self.Contributors() haveheader = headers.has_key for key, value in self.getMetadataHeaders(): if not haveheader(key): headers[key] = value self._editMetadata( title=headers['Title'], subject=headers['Subject'], description=headers['Description'], contributors=headers['Contributors'], effective_date=headers['Effective_date'], expiration_date=headers['Expiration_date'], format=headers['Format'], language=headers['Language'], rights=headers['Rights'], ) security.declarePrivate('guessFormat') def guessFormat(self, text): """ Simple stab at guessing the inner format of the text """ if html_headcheck(text): return 'html' else: return 'structured-text' security.declarePrivate('handleText') def handleText(self, text, format=None, stx_level=None): """ Handles the raw text, returning headers, body, format """ headers = {} if not format: format = self.guessFormat(text) if format == 'html': parser = SimpleHTMLParser() parser.feed(text) headers.update(parser.metatags) if parser.title: headers['Title'] = parser.title body = bodyfinder(text) else: headers, body = parseHeadersBody(text, headers) if stx_level: self._stx_level = stx_level return headers, body, format security.declarePublic('getMetadataHeaders') def getMetadataHeaders(self): """Return RFC-822-style header spec.""" hdrlist = DefaultDublinCoreImpl.getMetadataHeaders(self) hdrlist.append(('SafetyBelt', self._safety_belt)) return hdrlist security.declarePublic('SafetyBelt') def SafetyBelt(self): """Return the current safety belt setting. For web form hidden button.""" return self._safety_belt def _safety_belt_update(self, safety_belt=''): """Check validity of safety belt and update tracking if valid. Return 0 if safety belt is invalid, 1 otherwise. Note that the policy is deliberately lax if no safety belt value is present - "you're on your own if you don't use your safety belt". When present, either the safety belt token: - ... is the same as the current one given out, or - ... is the same as the last one given out, and the person doing the edit is the same as the last editor.""" this_belt = safety_belt this_user = getSecurityManager().getUser().getId() if ( # we have a safety belt value: this_belt # and the current object has a safety belt (ie - not freshly made) and (self._safety_belt is not None) # and the safety belt doesn't match the current one: and (this_belt != self._safety_belt) # and safety belt and user don't match last safety belt and user: and not ((this_belt == self._last_safety_belt) and (this_user == self._last_safety_belt_editor))): # Fail. return 0 # We qualified - either: # - the edit was submitted with safety belt stripped, or # - the current safety belt was used, or # - the last one was reused by the last person who did the last edit. # In any case, update the tracking. self._last_safety_belt_editor = this_user self._last_safety_belt = this_belt self._safety_belt = str(self._p_mtime) return 1 ### Content accessor methods security.declareProtected(View, 'SearchableText') def SearchableText(self): """ Used by the catalog for basic full text indexing """ return "%s %s %s" % (self.Title(), self.Description(), self.EditableBody()) security.declareProtected(View, 'CookedBody') def CookedBody(self, stx_level=None, setlevel=0): """\ The prepared basic rendering of an object. For Documents, this means pre-rendered structured text, or what was between the <BODY> tags of HTML. If the format is html, and 'stx_level' is not passed in or is the same as the object's current settings, return the cached cooked text. Otherwise, recook. If we recook and 'setlevel' is true, then set the recooked text and stx_level on the object. """ if (self.text_format == 'html' or self.text_format == 'plain' or (stx_level is None) or (stx_level == self._stx_level)): return self.cooked_text else: cooked = HTML(self.text, level=stx_level, header=0) if setlevel: self._stx_level = stx_level self.cooked_text = cooked return cooked security.declareProtected(View, 'EditableBody') def EditableBody(self): """\ The editable body of text. This is the raw structured text, or in the case of HTML, what was between the <BODY> tags. """ return self.text security.declareProtected(View, 'Format') def Format(self): """ Dublin Core Format element - resource format. """ if self.text_format == 'html': return 'text/html' else: return 'text/plain' security.declareProtected(ModifyPortalContent, 'setFormat') def setFormat(self, format): """ Set text format and Dublin Core resource format. """ value = str(format) if value == 'text/html' or value == 'html': self.text_format = 'html' elif value == 'text/plain': if self.text_format not in ('structured-text', 'plain'): self.text_format = 'structured-text' elif value == 'plain': self.text_format = 'plain' else: self.text_format = 'structured-text' ## FTP handlers security.declareProtected(ModifyPortalContent, 'PUT') def PUT(self, REQUEST, RESPONSE): """ Handle HTTP (and presumably FTP?) PUT requests """ self.dav__init(REQUEST, RESPONSE) self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1) body = REQUEST.get('BODY', '') headers, body, format = self.handleText(text=body) safety_belt = headers.get('SafetyBelt', '') if REQUEST.get_header('Content-Type', '') == 'text/html': text_format = 'html' else: text_format = format try: self.setFormat(text_format) self.setMetadata(headers) self._edit(text=body, safety_belt=safety_belt) except EditingConflict, msg: # XXX Can we get an error msg through? Should we be raising an # exception, to be handled in the FTP mechanism? Inquiring # minds... get_transaction().abort() RESPONSE.setStatus(450) return RESPONSE except ResourceLockedError, msg: get_transaction().abort() RESPONSE.setStatus(423) return RESPONSE
class WorkflowTool(UniqueObject, Folder): ''' This tool accesses and changes the workflow state of content. ''' id = 'portal_workflow' meta_type = 'CMF Workflow Tool' _chains_by_type = None # PersistentMapping _default_chain = ('default_workflow', ) security = ClassSecurityInfo() manage_options = ({ 'label': 'Overview', 'action': 'manage_overview' }, { 'label': 'Workflows', 'action': 'manage_selectWorkflows' }) + Folder.manage_options # # ZMI methods # security.declareProtected(CMFCorePermissions.ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainWorkflowTool', _dtmldir) if AUTO_MIGRATE_WORKFLOW_TOOLS: def __setstate__(self, state): # Adds default_workflow to persistent WorkflowTool instances. # This is temporary! WorkflowTool.inheritedAttribute('__setstate__')(self, state) if not self.__dict__.has_key('default_workflow'): try: from Products.CMFDefault import DefaultWorkflow except ImportError: pass else: self.default_workflow = ( DefaultWorkflow.DefaultWorkflowDefinition( 'default_workflow')) self._objects = self._objects + ( { 'id': 'default_workflow', 'meta_type': self.default_workflow.meta_type }, ) _manage_addWorkflowForm = DTMLFile('addWorkflow', _dtmldir) security.declareProtected(CMFCorePermissions.ManagePortal, 'manage_addWorkflowForm') def manage_addWorkflowForm(self, REQUEST): ''' Form for adding workflows. ''' wft = [] for key in _workflow_factories.keys(): wft.append(key) wft.sort() return self._manage_addWorkflowForm(REQUEST, workflow_types=wft) security.declareProtected(CMFCorePermissions.ManagePortal, 'manage_addWorkflow') def manage_addWorkflow(self, workflow_type, id, RESPONSE=None): ''' Adds a workflow from the registered types. ''' factory = _workflow_factories[workflow_type] ob = factory(id) self._setObject(id, ob) if RESPONSE is not None: RESPONSE.redirect(self.absolute_url() + '/manage_main?management_view=Contents') def all_meta_types(self): return ({ 'name': 'Workflow', 'action': 'manage_addWorkflowForm', 'permission': CMFCorePermissions.ManagePortal }, ) def _listTypeInfo(self): pt = getToolByName(self, 'portal_types', None) if pt is None: return () else: return pt.listTypeInfo() _manage_selectWorkflows = DTMLFile('selectWorkflows', _dtmldir) security.declareProtected(CMFCorePermissions.ManagePortal, 'manage_selectWorkflows') def manage_selectWorkflows(self, REQUEST, manage_tabs_message=None): ''' Shows a management screen for changing type to workflow connections. ''' cbt = self._chains_by_type ti = self._listTypeInfo() types_info = [] for t in ti: id = t.getId() title = t.Type() if title == id: title = None if cbt is not None and cbt.has_key(id): chain = join(cbt[id], ', ') else: chain = '(Default)' types_info.append({'id': id, 'title': title, 'chain': chain}) return self._manage_selectWorkflows( REQUEST, default_chain=join(self._default_chain, ', '), types_info=types_info, management_view='Workflows', manage_tabs_message=manage_tabs_message) security.declareProtected(CMFCorePermissions.ManagePortal, 'manage_changeWorkflows') def manage_changeWorkflows(self, default_chain, props=None, REQUEST=None): ''' Changes which workflows apply to objects of which type. ''' if props is None: props = REQUEST cbt = self._chains_by_type if cbt is None: self._chains_by_type = cbt = PersistentMapping() ti = self._listTypeInfo() # Set up the chains by type. for t in ti: id = t.getId() field_name = 'chain_%s' % id chain = strip(props.get(field_name, '(Default)')) if chain == '(Default)': # Remove from cbt. if cbt.has_key(id): del cbt[id] else: chain = replace(chain, ',', ' ') ids = [] for wf_id in split(chain, ' '): if wf_id: if not self.getWorkflowById(wf_id): raise ValueError, ('"%s" is not a workflow ID.' % wf_id) ids.append(wf_id) cbt[id] = tuple(ids) # Set up the default chain. default_chain = replace(default_chain, ',', ' ') ids = [] for wf_id in split(default_chain, ' '): if wf_id: if not self.getWorkflowById(wf_id): raise ValueError, ('"%s" is not a workflow ID.' % wf_id) ids.append(wf_id) self._default_chain = tuple(ids) if REQUEST is not None: return self.manage_selectWorkflows(REQUEST, manage_tabs_message='Changed.') security.declareProtected(CMFCorePermissions.ManagePortal, 'setDefaultChain') def setDefaultChain(self, default_chain): """ Set the default chain """ default_chain = replace(default_chain, ',', ' ') ids = [] for wf_id in split(default_chain, ' '): if wf_id: if not self.getWorkflowById(wf_id): raise ValueError, ('"%s" is not a workflow ID.' % wf_id) ids.append(wf_id) self._default_chain = tuple(ids) security.declareProtected(CMFCorePermissions.ManagePortal, 'setChainForPortalTypes') def setChainForPortalTypes(self, pt_names, chain): """ Set a chain for a specific portal type """ cbt = self._chains_by_type if cbt is None: self._chains_by_type = cbt = PersistentMapping() if type(chain) is type(''): chain = map(strip, split(chain, ',')) ti = self._listTypeInfo() for t in ti: id = t.getId() if id in pt_names: cbt[id] = tuple(chain) security.declareProtected(CMFCorePermissions.ManagePortal, 'updateRoleMappings') def updateRoleMappings(self, REQUEST=None): ''' ''' wfs = {} for id in self.objectIds(): wf = self.getWorkflowById(id) if hasattr(aq_base(wf), 'updateRoleMappingsFor'): wfs[id] = wf portal = aq_parent(aq_inner(self)) count = self._recursiveUpdateRoleMappings(portal, wfs) if REQUEST is not None: return self.manage_selectWorkflows( REQUEST, manage_tabs_message='%d object(s) updated.' % count) else: return count def _recursiveUpdateRoleMappings(self, ob, wfs): # Returns a count of updated objects. count = 0 wf_ids = self.getChainFor(ob) if wf_ids: changed = 0 for wf_id in wf_ids: wf = wfs.get(wf_id, None) if wf is not None: did = wf.updateRoleMappingsFor(ob) if did: changed = 1 if changed: count = count + 1 if hasattr(aq_base(ob), 'objectItems'): obs = ob.objectItems() if obs: for k, v in obs: changed = getattr(v, '_p_changed', 0) count = count + self._recursiveUpdateRoleMappings(v, wfs) if changed is None: # Re-ghostify. v._p_deactivate() return count security.declarePrivate('getWorkflowById') def getWorkflowById(self, wf_id): wf = getattr(self, wf_id, None) if getattr(wf, '_isAWorkflow', 0): return wf else: return None security.declarePrivate('getDefaultChainFor') def getDefaultChainFor(self, ob): if getattr(ob, '_isPortalContent', 0): # Apply a default workflow to portal content. return self._default_chain security.declarePrivate('getChainFor') def getChainFor(self, ob): ''' Returns the chain that applies to the given object. ''' cbt = self._chains_by_type if hasattr(aq_base(ob), '_getPortalTypeName'): pt = ob._getPortalTypeName() else: pt = ob.meta_type # Use a common Zope idiom. chain = None if cbt is not None: chain = cbt.get(pt, None) # Note that if chain is not in cbt or has a value of # None, we use a default chain. if chain is None: chain = self.getDefaultChainFor(ob) if chain is None: return () return chain security.declarePrivate('getWorkflowIds') def getWorkflowIds(self): ''' Returns the list of workflow ids. ''' wf_ids = [] for obj_name, obj in self.objectItems(): if getattr(obj, '_isAWorkflow', 0): wf_ids.append(obj_name) return tuple(wf_ids) security.declarePrivate('getWorkflowsFor') def getWorkflowsFor(self, ob): ''' Finds the Workflow objects for the type of the given object. ''' res = [] for wf_id in self.getChainFor(ob): wf = self.getWorkflowById(wf_id) if wf is not None: res.append(wf) return res security.declarePrivate('getCatalogVariablesFor') def getCatalogVariablesFor(self, ob): ''' Invoked by portal_catalog. Allows workflows to add variables to the catalog based on workflow status, making it possible to implement queues. Returns a mapping containing the catalog variables that apply to ob. ''' wfs = self.getWorkflowsFor(ob) if wfs is None: return None # Iterate through the workflows backwards so that # earlier workflows can override later workflows. wfs.reverse() vars = {} for wf in wfs: v = wf.getCatalogVariablesFor(ob) if v is not None: vars.update(v) return vars security.declarePrivate('listActions') def listActions(self, info): ''' Invoked by the portal_actions tool. Allows workflows to include actions to be displayed in the actions box. Object actions are supplied by workflows that apply to the object. Global actions are supplied by all workflows. Returns the actions to be displayed to the user. ''' chain = self.getChainFor(info.content) did = {} actions = [] for wf_id in chain: did[wf_id] = 1 wf = self.getWorkflowById(wf_id) if wf is not None: a = wf.listObjectActions(info) if a is not None: actions.extend(a) a = wf.listGlobalActions(info) if a is not None: actions.extend(a) wf_ids = self.getWorkflowIds() for wf_id in wf_ids: if not did.has_key(wf_id): wf = self.getWorkflowById(wf_id) if wf is not None: a = wf.listGlobalActions(info) if a is not None: actions.extend(a) return actions def _invokeWithNotification(self, wfs, ob, action, func, args, kw): ''' Private utility method. ''' reindex = 1 for w in wfs: w.notifyBefore(ob, action) try: res = apply(func, args, kw) except ObjectDeleted, ex: res = ex.getResult() reindex = 0 except ObjectMoved, ex: res = ex.getResult() ob = ex.getNewObject()
class LockNullResource(NullResource, OFS.SimpleItem.Item_w__name__): """ A Lock-Null Resource is created when a LOCK command is succesfully executed on a NullResource, essentially locking the Name. A PUT or MKCOL deletes the LockNull resource from its container and replaces it with the target object. An UNLOCK deletes it. """ __implements__ = (WriteLockInterface, ) __locknull_resource__ = 1 meta_type = 'WebDAV LockNull Resource' security = ClassSecurityInfo() manage_options = ({'label': 'Info', 'action': 'manage_main'}, ) security.declareProtected(View, 'manage') security.declareProtected(View, 'manage_main') manage = manage_main = DTMLFile('dtml/locknullmain', globals()) security.declareProtected(View, 'manage_workspace') manage_workspace = manage manage_main._setName('manage_main') # explicit def __no_valid_write_locks__(self): # A special hook (for better or worse) called when there are no # valid locks left. We have to delete ourselves from our container # now. parent = Acquisition.aq_parent(self) if parent: parent._delObject(self.id) def __init__(self, name): self.id = self.__name__ = name self.title = "LockNull Resource '%s'" % name security.declarePublic('title_or_id') def title_or_id(self): return 'Foo' def PROPFIND(self, REQUEST, RESPONSE): """Retrieve properties defined on the resource.""" return Resource.PROPFIND(self, REQUEST, RESPONSE) security.declareProtected(webdav_lock_items, 'LOCK') def LOCK(self, REQUEST, RESPONSE): """ A Lock command on a LockNull resource should only be a refresh request (one without a body) """ self.dav__init(REQUEST, RESPONSE) body = REQUEST.get('BODY', '') ifhdr = REQUEST.get_header('If', '') if body: # If there's a body, then this is a full lock request # which conflicts with the fact that we're already locked RESPONSE.setStatus(423) else: # There's no body, so this is likely to be a refresh request if not ifhdr: raise PreconditionFailed taglist = IfParser(ifhdr) found = 0 for tag in taglist: for listitem in tag.list: token = tokenFinder(listitem) if token and self.wl_hasLock(token): lock = self.wl_getLock(token) timeout = REQUEST.get_header('Timeout', 'infinite') lock.setTimeout(timeout) # Automatically refreshes found = 1 RESPONSE.setStatus(200) RESPONSE.setHeader('Content-Type', 'text/xml; charset="utf-8"') RESPONSE.setBody(lock.asXML()) if found: break if not found: RESPONSE.setStatus(412) # Precondition failed return RESPONSE security.declareProtected(webdav_unlock_items, 'UNLOCK') def UNLOCK(self, REQUEST, RESPONSE): """ Unlocking a Null Resource removes it from its parent """ self.dav__init(REQUEST, RESPONSE) security = getSecurityManager() user = security.getUser() token = REQUEST.get_header('Lock-Token', '') url = REQUEST['URL'] if token: token = tokenFinder(token) else: raise BadRequest, 'No lock token was submitted in the request' cmd = davcmds.Unlock() result = cmd.apply(self, token, url) parent = Acquisition.aq_parent(self) parent._delObject(self.id) if result: RESPONSE.setStatus(207) RESPONSE.setHeader('Content-Type', 'text/xml; charset="utf-8"') RESPONSE.setBody(result) else: RESPONSE.setStatus(204) return RESPONSE security.declarePublic('PUT') def PUT(self, REQUEST, RESPONSE): """ Create a new non-collection resource, deleting the LockNull object from the container before putting the new object in. """ self.dav__init(REQUEST, RESPONSE) name = self.__name__ parent = self.aq_parent parenturl = parent.absolute_url() ifhdr = REQUEST.get_header('If', '') # Since a Lock null resource is always locked by definition, all # operations done by an owner of the lock that affect the resource # MUST have the If header in the request if not ifhdr: raise PreconditionFailed, 'No If-header' # First we need to see if the parent of the locknull is locked, and # if the user owns that lock (checked by handling the information in # the If header). if (IWriteLock.providedBy(parent) or WriteLockInterface.isImplementedBy(parent)) and \ parent.wl_isLocked(): itrue = parent.dav__simpleifhandler(REQUEST, RESPONSE, 'PUT', col=1, url=parenturl, refresh=1) if not itrue: raise PreconditionFailed, ( 'Condition failed against resources parent') # Now we need to check the If header against our own lock state itrue = self.dav__simpleifhandler(REQUEST, RESPONSE, 'PUT', refresh=1) if not itrue: raise PreconditionFailed, ( 'Condition failed against locknull resource') # All of the If header tests succeeded, now we need to remove ourselves # from our parent. We need to transfer lock state to the new object. locks = self.wl_lockItems() parent._delObject(name) # Now we need to go through the regular operations of PUT body = REQUEST.get('BODY', '') typ = REQUEST.get_header('content-type', None) if typ is None: typ, enc = guess_content_type(name, body) factory = getattr(parent, 'PUT_factory', self._default_PUT_factory) ob = (factory(name, typ, body) or self._default_PUT_factory(name, typ, body)) # Verify that the user can create this type of object try: parent._verifyObjectPaste(ob.__of__(parent), 0) except Unauthorized: raise except: raise Forbidden, sys.exc_info()[1] # Put the locks on the new object if not (IWriteLock.providedBy(ob) or WriteLockInterface.isImplementedBy(ob)): raise MethodNotAllowed, ('The target object type cannot be locked') for token, lock in locks: ob.wl_setLock(token, lock) # Delegate actual PUT handling to the new object. ob.PUT(REQUEST, RESPONSE) parent._setObject(name, ob) RESPONSE.setStatus(201) RESPONSE.setBody('') return RESPONSE security.declareProtected(add_folders, 'MKCOL') def MKCOL(self, REQUEST, RESPONSE): """ Create a new Collection (folder) resource. Since this is being done on a LockNull resource, this also involves removing the LockNull object and transferring its locks to the newly created Folder """ self.dav__init(REQUEST, RESPONSE) if REQUEST.get('BODY', ''): raise UnsupportedMediaType, 'Unknown request body.' name = self.__name__ parent = self.aq_parent parenturl = parent.absolute_url() ifhdr = REQUEST.get_header('If', '') if not ifhdr: raise PreconditionFailed, 'No If-header' # If the parent object is locked, that information should be in the # if-header if the user owns a lock on the parent if (IWriteLock.providedBy(parent) or WriteLockInterface.isImplementedBy(parent)) and \ parent.wl_isLocked(): itrue = parent.dav__simpleifhandler(REQUEST, RESPONSE, 'MKCOL', col=1, url=parenturl, refresh=1) if not itrue: raise PreconditionFailed, ( 'Condition failed against resources parent') # Now we need to check the If header against our own lock state itrue = self.dav__simpleifhandler(REQUEST, RESPONSE, 'MKCOL', refresh=1) if not itrue: raise PreconditionFailed, ( 'Condition failed against locknull resource') # All of the If header tests succeeded, now we need to remove ourselves # from our parent. We need to transfer lock state to the new folder. locks = self.wl_lockItems() parent._delObject(name) parent.manage_addFolder(name) folder = parent._getOb(name) for token, lock in locks: folder.wl_setLock(token, lock) RESPONSE.setStatus(201) RESPONSE.setBody('') return RESPONSE
class VariableDefinition(SimpleItem): """Variable definition""" meta_type = 'Workflow Variable' security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) description = '' for_catalog = 1 for_status = 1 default_value = '' default_expr = None # Overrides default_value if set info_guard = None update_always = 1 manage_options = ( {'label': 'Properties', 'action': 'manage_properties'}, ) def __init__(self, id): self.id = id def getDefaultExprText(self): if not self.default_expr: return '' else: return self.default_expr.text def getInfoGuard(self): if self.info_guard is not None: return self.info_guard else: return Guard().__of__(self) # Create a temporary guard. def getInfoGuardSummary(self): res = None if self.info_guard is not None: res = self.info_guard.getSummary() return res _properties_form = DTMLFile('variable_properties', _dtmldir) def manage_properties(self, REQUEST, manage_tabs_message=None): ''' ''' return self._properties_form(REQUEST, management_view='Properties', manage_tabs_message=manage_tabs_message, ) def setProperties(self, description, default_value='', default_expr='', for_catalog=0, for_status=0, update_always=0, props=None, REQUEST=None): ''' ''' self.description = str(description) self.default_value = str(default_value) if default_expr: self.default_expr = Expression(default_expr) else: self.default_expr = None g = Guard() if g.changeFromProperties(props or REQUEST): self.info_guard = g else: self.info_guard = None self.for_catalog = bool(for_catalog) self.for_status = bool(for_status) self.update_always = bool(update_always) if REQUEST is not None: return self.manage_properties(REQUEST, 'Properties changed.')
class FSPythonScript(FSObject, Script): """FSPythonScripts act like Python Scripts but are not directly modifiable from the management interface.""" meta_type = 'Filesystem Script (Python)' _params = _body = '' _v_f = None _proxy_roles = () _owner = None # Unowned manage_options = ( { 'label': 'Customize', 'action': 'manage_main' }, { 'label': 'Test', 'action': 'ZScriptHTML_tryForm', 'help': ('PythonScripts', 'PythonScript_test.stx') }, ) security = ClassSecurityInfo() security.declareObjectProtected(View) security.declareProtected(ViewManagementScreens, 'manage_main') manage_main = DTMLFile('custpy', _dtmldir) security.declareProtected( View, 'index_html', ) # Prevent the bindings from being edited TTW security.declarePrivate('ZBindings_edit', 'ZBindingsHTML_editForm', 'ZBindingsHTML_editAction') def _createZODBClone(self): """Create a ZODB (editable) equivalent of this object.""" return CustomizedPythonScript(self.getId(), self.read()) def _readFile(self, reparse): """Read the data from the filesystem. """ file = open(self._filepath, 'rU') try: data = file.read() finally: file.close() if reparse: self._write(data, reparse) def _validateProxy(self, roles=None): pass def __render_with_namespace__(self, namespace): '''Calls the script.''' self._updateFromFS() return Script.__render_with_namespace__(self, namespace) def __call__(self, *args, **kw): '''Calls the script.''' self._updateFromFS() return Script.__call__(self, *args, **kw) #### The following is mainly taken from PythonScript.py ### def _exec(self, bound_names, args, kw): """Call a Python Script Calling a Python Script is an actual function invocation. """ # do caching keyset = None if self.ZCacheable_isCachingEnabled(): # Prepare a cache key. keyset = kw.copy() asgns = self.getBindingAssignments() name_context = asgns.getAssignedName('name_context', None) if name_context: keyset[name_context] = self.aq_parent.getPhysicalPath() name_subpath = asgns.getAssignedName('name_subpath', None) if name_subpath: keyset[name_subpath] = self._getTraverseSubpath() # Note: perhaps we should cache based on name_ns also. keyset['*'] = args result = self.ZCacheable_get(keywords=keyset, default=_marker) if result is not _marker: # Got a cached value. return result # Prepare the function. f = self._v_f if f is None: # The script has errors. __traceback_supplement__ = (FSPythonScriptTracebackSupplement, self, 0) raise RuntimeError, '%s has errors.' % self._filepath # Updating func_globals directly is not thread safe here. # In normal PythonScripts, every thread has its own # copy of the function. But in FSPythonScripts # there is only one copy. So here's another way. new_globals = f.func_globals.copy() new_globals['__traceback_supplement__'] = ( FSPythonScriptTracebackSupplement, self) new_globals['__file__'] = self._filepath if bound_names: new_globals.update(bound_names) if f.func_defaults: f = new.function(f.func_code, new_globals, f.func_name, f.func_defaults) else: f = new.function(f.func_code, new_globals, f.func_name) # Execute the function in a new security context. security = getSecurityManager() security.addContext(self) try: result = f(*args, **kw) if keyset is not None: # Store the result in the cache. self.ZCacheable_set(result, keywords=keyset) return result finally: security.removeContext(self) security.declareProtected(ViewManagementScreens, 'getModTime') # getModTime defined in FSObject security.declareProtected(ViewManagementScreens, 'ZScriptHTML_tryForm') # ZScriptHTML_tryForm defined in Shared.DC.Scripts.Script.Script def ZScriptHTML_tryParams(self): """Parameters to test the script with.""" param_names = [] for name in self._params.split(','): name = name.strip() if name and name[0] != '*': param_names.append(name.split('=', 1)[0]) return param_names security.declareProtected(ViewManagementScreens, 'read') def read(self): self._updateFromFS() return self._source security.declareProtected(ViewManagementScreens, 'document_src') def document_src(self, REQUEST=None, RESPONSE=None): """Return unprocessed document source.""" if RESPONSE is not None: RESPONSE.setHeader('Content-Type', 'text/plain') return self._source security.declareProtected(ViewManagementScreens, 'PrincipiaSearchSource') def PrincipiaSearchSource(self): "Support for searching - the document's contents are searched." return "%s\n%s" % (self._params, self._body) security.declareProtected(ViewManagementScreens, 'params') def params(self): return self._params security.declareProtected(ViewManagementScreens, 'manage_haveProxy') manage_haveProxy = PythonScript.manage_haveProxy.im_func security.declareProtected(ViewManagementScreens, 'body') def body(self): return self._body security.declareProtected(ViewManagementScreens, 'get_size') def get_size(self): return len(self.read()) security.declareProtected(FTPAccess, 'manage_FTPget') def manage_FTPget(self): "Get source for FTP download" self.REQUEST.RESPONSE.setHeader('Content-Type', 'text/plain') return self.read() def _write(self, text, compile): ''' Parses the source, storing the body, params, title, bindings, and source in self. If compile is set, compiles the function. ''' ps = PythonScript(self.id) ps.write(text) if compile: ps._makeFunction(1) self._v_f = f = ps._v_f if f is not None: self.func_code = f.func_code self.func_defaults = f.func_defaults else: # There were errors in the compile. # No signature. self.func_code = bad_func_code() self.func_defaults = None self._body = ps._body self._params = ps._params self.title = ps.title self._setupBindings(ps.getBindingAssignments().getAssignedNames()) self._source = ps.read() # Find out what the script sees. def func_defaults(self): # This ensures func_code and func_defaults are # set when the code hasn't been compiled yet, # just in time for mapply(). Truly odd, but so is mapply(). :P self._updateFromFS() return self.__dict__.get('func_defaults', None) func_defaults = ComputedAttribute(func_defaults, 1) def func_code(self): # See func_defaults. self._updateFromFS() return self.__dict__.get('func_code', None) func_code = ComputedAttribute(func_code, 1) def title(self): # See func_defaults. self._updateFromFS() return self.__dict__.get('title', None) title = ComputedAttribute(title, 1) def getBindingAssignments(self): # Override of the version in Bindings.py. # This version ensures that bindings get loaded on demand. if not hasattr(self, '_bind_names'): # Set a default first to avoid recursion self._setupBindings() # Now do it for real self._updateFromFS() return self._bind_names
class DefaultDublinCoreImpl(PropertyManager): """ Mix-in class which provides Dublin Core methods. """ implements(IDublinCore, ICatalogableDublinCore, IMutableDublinCore) __implements__ = (z2IDublinCore, z2ICatalogableDublinCore, z2IMutableDublinCore) security = ClassSecurityInfo() def __init__(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='', rights=''): now = DateTime() self.creation_date = now self.modification_date = now self.creators = () self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights) # # Set-modification-date-related methods. # In DefaultDublinCoreImpl for lack of a better place. # # Class variable default for an upgrade. modification_date = None security.declarePrivate('notifyModified') def notifyModified(self): """ Take appropriate action after the resource has been modified. Update creators and modification_date. """ self.addCreator() self.setModificationDate() security.declareProtected(ModifyPortalContent, 'addCreator') def addCreator(self, creator=None): """ Add creator to Dublin Core creators. """ if creator is None: mtool = queryUtility(IMembershipTool) creator = mtool and mtool.getAuthenticatedMember().getId() # call self.listCreators() to make sure self.creators exists if creator and not creator in self.listCreators(): self.creators = self.creators + (creator, ) security.declareProtected(ModifyPortalContent, 'setModificationDate') def setModificationDate(self, modification_date=None): """ Set the date when the resource was last modified. When called without an argument, sets the date to now. """ if modification_date is None: self.modification_date = DateTime() else: self.modification_date = self._datify(modification_date) # # DublinCore interface query methods # security.declareProtected(View, 'Title') def Title(self): """ Dublin Core Title element - resource name. """ return self.title security.declareProtected(View, 'listCreators') def listCreators(self): """ List Dublin Core Creator elements - resource authors. """ if not hasattr(aq_base(self), 'creators'): # for content created with CMF versions before 1.5 owner_tuple = self.getOwnerTuple() if owner_tuple: self.creators = (owner_tuple[1], ) else: self.creators = () return self.creators security.declareProtected(View, 'Creator') def Creator(self): """ Dublin Core Creator element - resource author. """ creators = self.listCreators() return creators and creators[0] or '' security.declareProtected(View, 'Subject') def Subject(self): """ Dublin Core Subject element - resource keywords. """ return getattr(self, 'subject', ()) # compensate for *old* content security.declareProtected(View, 'Description') def Description(self): """ Dublin Core Description element - resource summary. """ return self.description security.declareProtected(View, 'Publisher') def Publisher(self): """ Dublin Core Publisher element - resource publisher. """ tool = queryUtility(IMetadataTool) if tool is not None: return tool.getPublisher() return 'No publisher' security.declareProtected(View, 'listContributors') def listContributors(self): """ Dublin Core Contributor elements - resource collaborators. """ return self.contributors security.declareProtected(View, 'Contributors') def Contributors(self): """ Deprecated alias of listContributors. """ return self.listContributors() security.declareProtected(View, 'Date') def Date(self, zone=None): """ Dublin Core Date element - default date. """ if zone is None: zone = _zone # Return effective_date if set, modification date otherwise date = getattr(self, 'effective_date', None) if date is None: date = self.modified() return date.toZone(zone).ISO() security.declareProtected(View, 'CreationDate') def CreationDate(self, zone=None): """ Dublin Core Date element - date resource created. """ if zone is None: zone = _zone # return unknown if never set properly if self.creation_date: return self.creation_date.toZone(zone).ISO() else: return 'Unknown' security.declareProtected(View, 'EffectiveDate') def EffectiveDate(self, zone=None): """ Dublin Core Date element - date resource becomes effective. """ if zone is None: zone = _zone ed = getattr(self, 'effective_date', None) return ed and ed.toZone(zone).ISO() or 'None' security.declareProtected(View, 'ExpirationDate') def ExpirationDate(self, zone=None): """ Dublin Core Date element - date resource expires. """ if zone is None: zone = _zone ed = getattr(self, 'expiration_date', None) return ed and ed.toZone(zone).ISO() or 'None' security.declareProtected(View, 'ModificationDate') def ModificationDate(self, zone=None): """ Dublin Core Date element - date resource last modified. """ if zone is None: zone = _zone return self.modified().toZone(zone).ISO() security.declareProtected(View, 'Type') def Type(self): """ Dublin Core Type element - resource type. """ ti = self.getTypeInfo() return ti is not None and ti.Title() or 'Unknown' security.declareProtected(View, 'Format') def Format(self): """ Dublin Core Format element - resource format. """ return self.format security.declareProtected(View, 'Identifier') def Identifier(self): """ Dublin Core Identifier element - resource ID. """ # XXX: fixme using 'portal_metadata' (we need to prepend the # right prefix to self.getPhysicalPath(). return self.absolute_url() security.declareProtected(View, 'Language') def Language(self): """ Dublin Core Language element - resource language. """ return self.language security.declareProtected(View, 'Rights') def Rights(self): """ Dublin Core Rights element - resource copyright. """ return self.rights # # DublinCore utility methods # def content_type(self): """ WebDAV needs this to do the Right Thing (TM). """ return self.Format() __FLOOR_DATE = DateTime(1970, 0) # always effective security.declareProtected(View, 'isEffective') def isEffective(self, date): """ Is the date within the resource's effective range? """ pastEffective = (self.effective_date is None or self.effective_date <= date) beforeExpiration = (self.expiration_date is None or self.expiration_date >= date) return pastEffective and beforeExpiration # # CatalogableDublinCore methods # security.declareProtected(View, 'created') def created(self): """ Dublin Core Date element - date resource created. """ # allow for non-existent creation_date, existed always date = getattr(self, 'creation_date', None) return date is None and self.__FLOOR_DATE or date security.declareProtected(View, 'effective') def effective(self): """ Dublin Core Date element - date resource becomes effective. """ marker = [] date = getattr(self, 'effective_date', marker) if date is marker: date = getattr(self, 'creation_date', None) return date is None and self.__FLOOR_DATE or date __CEILING_DATE = DateTime(2500, 0) # never expires security.declareProtected(View, 'expires') def expires(self): """ Dublin Core Date element - date resource expires. """ date = getattr(self, 'expiration_date', None) return date is None and self.__CEILING_DATE or date security.declareProtected(View, 'modified') def modified(self): """ Dublin Core Date element - date resource last modified. """ date = self.modification_date if date is None: # Upgrade. date = self.bobobase_modification_time() self.modification_date = date return date security.declareProtected(View, 'getMetadataHeaders') def getMetadataHeaders(self): """ Return RFC-822-style headers. """ hdrlist = [] hdrlist.append(('Title', self.Title())) hdrlist.append(('Subject', ', '.join(self.Subject()))) hdrlist.append(('Publisher', self.Publisher())) hdrlist.append(('Description', self.Description())) hdrlist.append(('Contributors', '; '.join(self.Contributors()))) hdrlist.append(('Effective_date', self.EffectiveDate())) hdrlist.append(('Expiration_date', self.ExpirationDate())) hdrlist.append(('Type', self.Type())) hdrlist.append(('Format', self.Format())) hdrlist.append(('Language', self.Language())) hdrlist.append(('Rights', self.Rights())) return hdrlist # # MutableDublinCore methods # security.declarePrivate('_datify') def _datify(self, attrib): if attrib == 'None': attrib = None elif not isinstance(attrib, DateTime): if attrib is not None: attrib = DateTime(attrib) return attrib security.declareProtected(ModifyPortalContent, 'setTitle') def setTitle(self, title): """ Set Dublin Core Title element - resource name. """ self.title = title security.declareProtected(ModifyPortalContent, 'setCreators') def setCreators(self, creators): """ Set Dublin Core Creator elements - resource authors. """ self.creators = tuplize('creators', creators) security.declareProtected(ModifyPortalContent, 'setSubject') def setSubject(self, subject): """ Set Dublin Core Subject element - resource keywords. """ self.subject = tuplize('subject', subject) security.declareProtected(ModifyPortalContent, 'setDescription') def setDescription(self, description): """ Set Dublin Core Description element - resource summary. """ self.description = description security.declareProtected(ModifyPortalContent, 'setContributors') def setContributors(self, contributors): """ Set Dublin Core Contributor elements - resource collaborators. """ # XXX: fixme self.contributors = tuplize('contributors', contributors, semi_split) security.declareProtected(ModifyPortalContent, 'setEffectiveDate') def setEffectiveDate(self, effective_date): """ Set Dublin Core Date element - date resource becomes effective. """ self.effective_date = self._datify(effective_date) security.declareProtected(ModifyPortalContent, 'setExpirationDate') def setExpirationDate(self, expiration_date): """ Set Dublin Core Date element - date resource expires. """ self.expiration_date = self._datify(expiration_date) security.declareProtected(ModifyPortalContent, 'setFormat') def setFormat(self, format): """ Set Dublin Core Format element - resource format. """ self.format = format security.declareProtected(ModifyPortalContent, 'setLanguage') def setLanguage(self, language): """ Set Dublin Core Language element - resource language. """ self.language = language security.declareProtected(ModifyPortalContent, 'setRights') def setRights(self, rights): """ Set Dublin Core Rights element - resource copyright. """ self.rights = rights # # Management tab methods # security.declarePrivate('_editMetadata') def _editMetadata(self, title=_marker, subject=_marker, description=_marker, contributors=_marker, effective_date=_marker, expiration_date=_marker, format=_marker, language=_marker, rights=_marker): """ Update the editable metadata for this resource. """ if title is not _marker: self.setTitle(title) if subject is not _marker: self.setSubject(subject) if description is not _marker: self.setDescription(description) if contributors is not _marker: self.setContributors(contributors) if effective_date is not _marker: self.setEffectiveDate(effective_date) if expiration_date is not _marker: self.setExpirationDate(expiration_date) if format is not _marker: self.setFormat(format) if language is not _marker: self.setLanguage(language) if rights is not _marker: self.setRights(rights) security.declareProtected(ModifyPortalContent, 'manage_metadata') manage_metadata = DTMLFile('zmi_metadata', _dtmldir) security.declareProtected(ModifyPortalContent, 'manage_editMetadata') def manage_editMetadata(self, title, subject, description, contributors, effective_date, expiration_date, format, language, rights, REQUEST): """ Update metadata from the ZMI. """ self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights) REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_metadata' + '?manage_tabs_message=Metadata+updated.') security.declareProtected(ModifyPortalContent, 'editMetadata') def editMetadata(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='en-US', rights=''): """ Need to add check for webDAV locked resource for TTW methods. """ # as per bug #69, we cant assume they use the webdav # locking interface, and fail gracefully if they dont if hasattr(self, 'failIfLocked'): self.failIfLocked() self._editMetadata(title=title, subject=subject, description=description, contributors=contributors, effective_date=effective_date, expiration_date=expiration_date, format=format, language=language, rights=rights) self.reindexObject()
""" Converts Subject string into a List for content filter view. """ for sub in obj.Subject(): if sub in self.filterSubject: return 1 return 0 def __call__(self, content): for predicate in self.predicates: try: if not predicate(content): return 0 except (AttributeError, KeyError, IndexError, ValueError): # predicates are *not* allowed to throw exceptions return 0 return 1 def __str__(self): """ Return a stringified description of the filter. """ return '; '.join(self.description) manage_addPortalFolder = PortalFolder.manage_addPortalFolder.im_func manage_addPortalFolderForm = DTMLFile('folderAdd', globals())
class InterceptedSQLClass(SQL): """ subclass of the SQL (from ZSQLMethods) so that we can enable possible executions and initializations. """ manage_options = DA.manage_options[:3]+\ ({'label':'Permanent Storage', 'action':'manage_permanent_storage'},)+\ DA.manage_options[3:] security = ClassSecurityInfo() security.declareProtected(VMS, 'manage_permanent_storage') manage_permanent_storage = DTMLFile('dtml/permanent_storage', globals()) def __init__(self, id, title, connection_id, arguments, template, relpath): self.id = str(id) self.manage_edit(title, connection_id, arguments, template) self.relpath = relpath def __call__(self, REQUEST=None, __ick__=None, src__=0, test__=0, **kw): """ override __call__ for debugging purposes """ if DEBUGMODE: _debugSQLCall(self, kw) if PROFILE_SQLCALLS: t0 = time.time() result = apply(SQL.__call__, (self, REQUEST, __ick__, src__, test__), kw) t1 = time.time() _profileSQLCall(self, t1 - t0, kw) return result return apply(SQL.__call__, (self, REQUEST, __ick__, src__, test__), kw) def getRelpath(self): """ some doc string """ return self.relpath # manage=manage_main=DTMLFile('dtml/sql_manage_edit', globals()) # manage_main._setName('manage_main') def canCheckIn(self): """ true if in DEBUG mode """ if DEBUGMODE >= 1: return true else: return false def manage_checkIn(self, makebackupcopy=0, REQUEST=None): """ take the object and inspect it and write it back to file """ file_write2 = self.relpath if file_write2.startswith('/'): file_write2 = file_write2[1:] filepath = os.path.join(sqlhome, file_write2) if makebackupcopy: incr = 1 while os.path.isfile(filepath + '.bak%s' % incr): incr += 1 filepath_backup = filepath + '.bak%s' % incr # write the backup fr = open(filepath, 'r') fw = open(filepath_backup, 'w') fw.write(fr.read()) fw.close() fr.close() # write it back now codeblock = self.document_src() fw = open(filepath, 'w') fw.write(codeblock) fw.close() if REQUEST is not None: mtm = "Changes written to back to file" return self.manage_main(self, REQUEST, manage_tabs_message=mtm) else: return "Done"
class CatalogTool(UniqueObject, ZCatalog): '''This is a ZCatalog that filters catalog queries. ''' id = 'portal_catalog' meta_type = 'CMF Catalog' security = ClassSecurityInfo() manage_options = ({ 'label': 'Overview', 'action': 'manage_overview' }, ) + ZCatalog.manage_options def __init__(self): ZCatalog.__init__(self, self.getId()) self._initIndexes() # # Subclass extension interface # security.declarePublic('enumerateIndexes') # Subclass can call def enumerateIndexes(self): # Return a list of ( index_name, type ) pairs for the initial # index set. return (('Title', 'TextIndex'), ('Subject', 'KeywordIndex'), ('Description', 'TextIndex'), ('Creator', 'FieldIndex'), ('SearchableText', 'TextIndex'), ('Date', 'FieldIndex'), ('Type', 'FieldIndex'), ('created', 'FieldIndex'), ('effective', 'FieldIndex'), ('expires', 'FieldIndex'), ('modified', 'FieldIndex'), ('allowedRolesAndUsers', 'KeywordIndex'), ('review_state', 'FieldIndex'), ('in_reply_to', 'FieldIndex')) security.declarePublic('enumerateColumns') def enumerateColumns(self): # Return a sequence of schema names to be cached. return ('Subject', 'Title', 'Description', 'Type', 'review_state', 'Creator', 'Date', 'getIcon', 'created', 'effective', 'expires', 'modified', 'CreationDate', 'EffectiveDate', 'ExpiresDate', 'ModifiedDate') def _initIndexes(self): base = aq_base(self) if hasattr(base, 'addIndex'): # Zope 2.4 addIndex = self.addIndex else: # Zope 2.3 and below addIndex = self._catalog.addIndex if hasattr(base, 'addColumn'): # Zope 2.4 addColumn = self.addColumn else: # Zope 2.3 and below addColumn = self._catalog.addColumn # Content indexes for index_name, index_type in self.enumerateIndexes(): addIndex(index_name, index_type) # Cached metadata for column_name in self.enumerateColumns(): addColumn(column_name) # # ZMI methods # security.declareProtected(CMFCorePermissions.ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainCatalogTool', _dtmldir) # # 'portal_catalog' interface methods # # searchResults has inherited security assertions. def searchResults(self, REQUEST=None, **kw): '''Calls SiteIndex.searchResults() with extra arguments that limit the results to what the user is allowed to see. ''' if REQUEST is None: REQUEST = self.REQUEST user = _getAuthenticatedUser(self) kw['allowedRolesAndUsers'] = list(user.getRoles()) + \ ['Anonymous', 'user:'******'Date') and None: if kw.has_key('Date_usage'): kw['Date'] = min(kw['Date']) kw['Date'] = [kw['Date'], DateTime()] kw['Date_usage'] = 'range:min:max' else: kw['effective'] = kw['expires'] = DateTime() kw['effective_usage'] = 'range:max' kw['expires_usage'] = 'range:min' return apply(ZCatalog.searchResults, (self, REQUEST), kw) __call__ = searchResults def __url(self, ob): return join(ob.getPhysicalPath(), '/') manage_catalogFind = DTMLFile('catalogFind', _dtmldir) def catalog_object(self, object, uid): # Wraps the object with workflow and accessibility # information just before cataloging. wf = getattr(self, 'portal_workflow', None) if wf is not None: vars = wf.getCatalogVariablesFor(object) else: vars = {} w = IndexableObjectWrapper(vars, object) ZCatalog.catalog_object(self, w, uid) security.declarePrivate('indexObject') def indexObject(self, object): '''Add to catalog. ''' url = self.__url(object) self.catalog_object(object, url) security.declarePrivate('unindexObject') def unindexObject(self, object): '''Remove from catalog. ''' url = self.__url(object) self.uncatalog_object(url) security.declarePrivate('reindexObject') def reindexObject(self, object): '''Update catalog after object data has changed. ''' url = self.__url(object) ## Zope 2.3 ZCatalog is supposed to work better if ## you don't uncatalog_object() when reindexing. # self.uncatalog_object(url) self.catalog_object(object, url)
class FileSystem(OSComponent): """ FileSystem object """ portal_type = meta_type = 'FileSystem' manage_editFileSystemForm = DTMLFile('dtml/manageEditFileSystem', globals()) mount = "" storageDevice = "" type = "" blockSize = 0 totalBlocks = 0L totalFiles = 0L capacity = 0 inodeCapacity = 0 maxNameLen = 0 security = ClassSecurityInfo() _properties = OSComponent._properties + ( { 'id': 'mount', 'type': 'string', 'mode': '' }, { 'id': 'storageDevice', 'type': 'string', 'mode': '' }, { 'id': 'type', 'type': 'string', 'mode': '' }, { 'id': 'blockSize', 'type': 'int', 'mode': '' }, { 'id': 'totalBlocks', 'type': 'long', 'mode': '' }, { 'id': 'totalFiles', 'type': 'long', 'mode': '' }, { 'id': 'maxNameLen', 'type': 'int', 'mode': '' }, ) _relations = OSComponent._relations + ( ("os", ToOne(ToManyCont, "Products.ZenModel.OperatingSystem", "filesystems")), ) factory_type_information = ({ 'id': 'FileSystem', 'meta_type': 'FileSystem', 'description': """Arbitrary device grouping class""", 'icon': 'FileSystem_icon.gif', 'product': 'ZenModel', 'factory': 'manage_addFileSystem', 'immediate_view': 'viewFileSystem', 'actions': ( { 'id': 'status', 'name': 'Status', 'action': 'viewFileSystem', 'permissions': (ZEN_VIEW, ) }, { 'id': 'events', 'name': 'Events', 'action': 'viewEvents', 'permissions': (ZEN_VIEW, ) }, { 'id': 'perfConf', 'name': 'Template', 'action': 'objTemplates', 'permissions': ("Change Device", ) }, ) }, ) def getTotalBlocks(self): offset = getattr(self.primaryAq(), 'zFileSystemSizeOffset', 1.0) return int(self.totalBlocks) * offset def totalBytes(self): """ Return the total bytes of a filesytem """ return int(self.blockSize) * self.getTotalBlocks() def totalBytesString(self): """ Return the number of total bytes in human readable from ie 10MB """ return convToUnits(self.totalBytes()) def usedBytes(self): """ Return the number of used bytes on a filesytem. """ blocks = self.usedBlocks() if blocks is not None: return self.blockSize * blocks return None def usedBytesString(self): """ Return the number of used bytes in human readable form ie 10MB """ __pychecker__ = 'no-constCond' ub = self.usedBytes() return ub is None and "unknown" or convToUnits(ub) def availBytes(self): """ Return the number of availible bytes for this filesystem """ blocks = self.availBlocks() if blocks is not None: return self.blockSize * blocks return None def availBytesString(self): """ Return the number of availible bytes in human readable form ie 10MB """ __pychecker__ = 'no-constCond' ab = self.availBytes() return ab is None and "unknown" or convToUnits(ab) def availFiles(self): """ Not implemented returns 0 """ return 0 def capacity(self): """ Return the percentage capacity of a filesystems using its rrd file. Calculate using available blocks instead used blocks to account for reserved blocks. """ __pychecker__ = 'no-returnvalues' totalBlocks = self.getTotalBlocks() availBlocks = self.availBlocks() if totalBlocks and availBlocks is not None: return round(100.0 * (totalBlocks - availBlocks) / totalBlocks) return 'unknown' def inodeCapacity(self): """ Not implemented returns 0 """ return 0 def usedBlocks(self, default=None): """ Return the number of used blocks stored in the filesystem's rrd file """ dskPercent = self.cacheRRDValue("dskPercent", default) if dskPercent is not None and dskPercent != "Unknown" and not isnan( dskPercent): return self.getTotalBlocks() * dskPercent / 100.0 blocks = self.cacheRRDValue('usedBlocks', default) if blocks is not None and not isnan(blocks): return long(blocks) elif self.blockSize: # no usedBlocks datapoint, so this is probably a Windows device # using perfmon for data collection and therefore we'll look for # the freeMegabytes datapoint freeMB = self.cacheRRDValue('FreeMegabytes', default) if freeMB is not None and not isnan(freeMB): usedBytes = self.totalBytes() - long(freeMB) * 1024 * 1024 return usedBytes / self.blockSize return None def availBlocks(self, default=None): """ Return the number of available blocks stored in the filesystem's rrd file """ blocks = self.cacheRRDValue('availBlocks', default) if blocks is not None and not isnan(blocks): return long(blocks) usedBlocks = self.usedBlocks() if usedBlocks is None: return None return self.getTotalBlocks() - usedBlocks def usedBlocksString(self): """ Return the number of used blocks in human readable form ie 10MB """ __pychecker__ = 'no-constCond' ub = self.usedBlocks() return ub is None and "unknown" or convToUnits(ub) def viewName(self): """ Return the mount point name of a filesystem '/boot' """ return self.mount name = viewName security.declareProtected(ZEN_MANAGE_DEVICE, 'manage_editFileSystem') def manage_editFileSystem(self, monitor=False, mount=None, storageDevice=None, type=None, blockSize=None, totalFiles=None, maxNameLen=None, snmpindex=None, REQUEST=None): """ Edit a Service from a web page. """ if mount: self.mount = mount self.storageDevice = storageDevice self.type = type self.blockSize = blockSize self.totalFiles = totalFiles self.maxNameLen = maxNameLen self.snmpindex = snmpindex self.monitor = monitor self.index_object() if REQUEST: messaging.IMessageSender(self).sendToBrowser( 'Filesystem Updated', 'Filesystem %s was edited.' % self.id) return self.callZenScreen(REQUEST)
def manage_addFileSystem(context, newId, userCreated, REQUEST=None): """make a filesystem""" fsid = prepId(newId) fs = FileSystem(fsid) context._setObject(fsid, fs) fs = context._getOb(fsid) fs.mount = newId if userCreated: fs.setUserCreateFlag() if REQUEST is not None: REQUEST['RESPONSE'].redirect(context.absolute_url_path() + '/manage_main') addFileSystem = DTMLFile('dtml/addFileSystem', globals()) class FileSystem(OSComponent): """ FileSystem object """ portal_type = meta_type = 'FileSystem' manage_editFileSystemForm = DTMLFile('dtml/manageEditFileSystem', globals()) mount = "" storageDevice = "" type = ""
class CMFCatalogAware(Base): """Mix-in for notifying portal_catalog and portal_workflow """ security = ClassSecurityInfo() # The following methods can be overriden using inheritence so that # it's possible to specifiy another catalog tool or workflow tool # for a given content type def _getCatalogTool(self): return getToolByName(self, 'portal_catalog', None) def _getWorkflowTool(self): return getToolByName(self, 'portal_workflow', None) # Cataloging methods # ------------------ security.declareProtected(ModifyPortalContent, 'indexObject') def indexObject(self): """ Index the object in the portal catalog. """ catalog = self._getCatalogTool() if catalog is not None: catalog.indexObject(self) security.declareProtected(ModifyPortalContent, 'unindexObject') def unindexObject(self): """ Unindex the object from the portal catalog. """ catalog = self._getCatalogTool() if catalog is not None: catalog.unindexObject(self) security.declareProtected(ModifyPortalContent, 'reindexObject') def reindexObject(self, idxs=[]): """ Reindex the object in the portal catalog. If idxs is present, only those indexes are reindexed. The metadata is always updated. Also update the modification date of the object, unless specific indexes were requested. """ if idxs == []: # Update the modification date. if hasattr(aq_base(self), 'notifyModified'): self.notifyModified() catalog = self._getCatalogTool() if catalog is not None: catalog.reindexObject(self, idxs=idxs) _cmf_security_indexes = ('allowedRolesAndUsers', ) security.declareProtected(ModifyPortalContent, 'reindexObjectSecurity') def reindexObjectSecurity(self, skip_self=False): """Reindex security-related indexes on the object. Recurses in the children to reindex them too. If skip_self is True, only the children will be reindexed. This is a useful optimization if the object itself has just been fully reindexed, as there's no need to reindex its security twice. """ catalog = self._getCatalogTool() if catalog is None: return path = '/'.join(self.getPhysicalPath()) # XXX if _getCatalogTool() is overriden we will have to change # this method for the sub-objects. for brain in catalog.unrestrictedSearchResults(path=path): brain_path = brain.getPath() if brain_path == path and skip_self: continue # Get the object ob = brain._unrestrictedGetObject() if ob is None: # BBB: Ignore old references to deleted objects. # Can happen only when using # catalog-getObject-raises off in Zope 2.8 logger.warning( "reindexObjectSecurity: Cannot get %s from " "catalog", brain_path) continue # Recatalog with the same catalog uid. s = getattr(ob, '_p_changed', 0) catalog.reindexObject(ob, idxs=self._cmf_security_indexes, update_metadata=0, uid=brain_path) if s is None: ob._p_deactivate() # Workflow methods # ---------------- security.declarePrivate('notifyWorkflowCreated') def notifyWorkflowCreated(self): """ Notify the workflow that self was just created. """ wftool = self._getWorkflowTool() if wftool is not None: wftool.notifyCreated(self) # Opaque subitems # --------------- security.declareProtected(AccessContentsInformation, 'opaqueItems') def opaqueItems(self): """ Return opaque items (subelements that are contained using something that is not an ObjectManager). """ items = [] # Call 'talkback' knowing that it is an opaque item. # This will remain here as long as the discussion item does # not implement ICallableOpaqueItem (backwards compatibility). if hasattr(aq_base(self), 'talkback'): talkback = self.talkback if talkback is not None: items.append((talkback.id, talkback)) # Other opaque items than 'talkback' may have callable # manage_after* and manage_before* hooks. # Loop over all attributes and add those to 'items' # implementing 'ICallableOpaqueItem'. self_base = aq_base(self) for name in self_base.__dict__.keys(): obj = getattr(self, name) if ICallableOpaqueItem.providedBy(obj) \ or z2ICallableOpaqueItem.isImplementedBy(obj): items.append((obj.getId(), obj)) return tuple(items) security.declareProtected(AccessContentsInformation, 'opaqueIds') def opaqueIds(self): """ Return opaque ids (subelements that are contained using something that is not an ObjectManager). """ return [t[0] for t in self.opaqueItems()] security.declareProtected(AccessContentsInformation, 'opaqueValues') def opaqueValues(self): """ Return opaque values (subelements that are contained using something that is not an ObjectManager). """ return [t[1] for t in self.opaqueItems()] # Hooks # ----- def _clearLocalRolesAfterClone(self): # Make sure owner local role is set after pasting # The standard Zope mechanisms take care of executable ownership current_user = _getAuthenticatedUser(self) if current_user is not None: local_role_holders = [x[0] for x in self.get_local_roles()] self.manage_delLocalRoles(local_role_holders) self.manage_setLocalRoles(current_user.getId(), ['Owner']) # ZMI # --- manage_options = ({ 'label': 'Workflows', 'action': 'manage_workflowsTab', }, ) _manage_workflowsTab = DTMLFile('zmi_workflows', _dtmldir) security.declareProtected(ManagePortal, 'manage_workflowsTab') def manage_workflowsTab(self, REQUEST, manage_tabs_message=None): """ Tab displaying the current workflows for the content object. """ ob = self wftool = self._getWorkflowTool() # XXX None ? if wftool is not None: wf_ids = wftool.getChainFor(ob) states = {} chain = [] for wf_id in wf_ids: wf = wftool.getWorkflowById(wf_id) if wf is not None: # XXX a standard API would be nice if hasattr(wf, 'getReviewStateOf'): # Default Workflow state = wf.getReviewStateOf(ob) elif hasattr(wf, '_getWorkflowStateOf'): # DCWorkflow state = wf._getWorkflowStateOf(ob, id_only=1) else: state = '(Unknown)' states[wf_id] = state chain.append(wf_id) return self._manage_workflowsTab( REQUEST, chain=chain, states=states, management_view='Workflows', manage_tabs_message=manage_tabs_message)
class CachingPolicyManager(SimpleItem): """ Manage the set of CachingPolicy objects for the site; dispatch to them from skin methods. """ __implements__ = ICachingPolicyManager id = 'caching_policy_manager' meta_type = 'CMF Caching Policy Manager' security = ClassSecurityInfo() def __init__(self): self._policy_ids = () self._policies = PersistentMapping() # # ZMI # manage_options = (({ 'label': 'Policies', 'action': 'manage_cachingPolicies', 'help': ('CMFCore', 'CPMPolicies.stx') }, ) + SimpleItem.manage_options) security.declareProtected(ManagePortal, 'manage_cachingPolicies') manage_cachingPolicies = DTMLFile('cachingPolicies', _dtmldir) security.declarePublic('listPolicies') def listPolicies(self): """ Return a sequence of tuples, '( policy_id, ( policy, typeObjectName ) )' for all policies in the registry """ result = [] for policy_id in self._policy_ids: result.append((policy_id, self._policies[policy_id])) return tuple(result) security.declareProtected(ManagePortal, 'addPolicy') def addPolicy( self, policy_id, predicate # TALES expr (def. 'python:1') , mtime_func # TALES expr (def. 'object/modified') , max_age_secs # integer, seconds (def. 0) , no_cache # boolean (def. 0) , no_store # boolean (def. 0) , must_revalidate # boolean (def. 0) , vary # string value , etag_func # TALES expr (def. '') , REQUEST=None): """ Add a caching policy. """ self._addPolicy(policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=' + 'Policy+added.') security.declareProtected(ManagePortal, 'updatePolicy') def updatePolicy( self, policy_id, predicate # TALES expr (def. 'python:1') , mtime_func # TALES expr (def. 'object/modified') , max_age_secs # integer, seconds , no_cache # boolean (def. 0) , no_store # boolean (def. 0) , must_revalidate # boolean (def. 0) , vary # string value , etag_func # TALES expr (def. '') , REQUEST=None): """ Update a caching policy. """ self._updatePolicy(policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=' + 'Policy+updated.') security.declareProtected(ManagePortal, 'movePolicyUp') def movePolicyUp(self, policy_id, REQUEST=None): """ Move a caching policy up in the list. """ policy_ids = list(self._policy_ids) ndx = policy_ids.index(policy_id) if ndx == 0: msg = "Policy+already+first." else: self._reorderPolicy(policy_id, ndx - 1) msg = "Policy+moved." if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=%s' % msg) security.declareProtected(ManagePortal, 'movePolicyDown') def movePolicyDown(self, policy_id, REQUEST=None): """ Move a caching policy down in the list. """ policy_ids = list(self._policy_ids) ndx = policy_ids.index(policy_id) if ndx == len(policy_ids) - 1: msg = "Policy+already+last." else: self._reorderPolicy(policy_id, ndx + 1) msg = "Policy+moved." if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=%s' % msg) security.declareProtected(ManagePortal, 'removePolicy') def removePolicy(self, policy_id, REQUEST=None): """ Remove a caching policy. """ self._removePolicy(policy_id) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/manage_cachingPolicies' + '?manage_tabs_message=Policy+removed.') # # Policy manipulation methods. # security.declarePrivate('_addPolicy') def _addPolicy(self, policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func): """ Add a policy to our registry. """ policy_id = str(policy_id).strip() if not policy_id: raise ValueError, "Policy ID is required!" if policy_id in self._policy_ids: raise KeyError, "Policy %s already exists!" % policy_id self._policies[policy_id] = CachingPolicy(policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func) idlist = list(self._policy_ids) idlist.append(policy_id) self._policy_ids = tuple(idlist) security.declarePrivate('_updatePolicy') def _updatePolicy(self, policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func): """ Update a policy in our registry. """ if policy_id not in self._policy_ids: raise KeyError, "Policy %s does not exist!" % policy_id self._policies[policy_id] = CachingPolicy(policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store, must_revalidate, vary, etag_func) security.declarePrivate('_reorderPolicy') def _reorderPolicy(self, policy_id, newIndex): """ Reorder a policy in our registry. """ if policy_id not in self._policy_ids: raise KeyError, "Policy %s does not exist!" % policy_id idlist = list(self._policy_ids) ndx = idlist.index(policy_id) pred = idlist[ndx] idlist = idlist[:ndx] + idlist[ndx + 1:] idlist.insert(newIndex, pred) self._policy_ids = tuple(idlist) security.declarePrivate('_removePolicy') def _removePolicy(self, policy_id): """ Remove a policy from our registry. """ if policy_id not in self._policy_ids: raise KeyError, "Policy %s does not exist!" % policy_id del self._policies[policy_id] idlist = list(self._policy_ids) ndx = idlist.index(policy_id) idlist = idlist[:ndx] + idlist[ndx + 1:] self._policy_ids = tuple(idlist) # # 'portal_caching' interface methods # security.declareProtected(View, 'getHTTPCachingHeaders') def getHTTPCachingHeaders(self, content, view_method, keywords, time=None): """ Return a list of HTTP caching headers based on 'content', 'view_method', and 'keywords'. """ context = createCPContext(content, view_method, keywords, time=time) for policy_id, policy in self.listPolicies(): headers = policy.getHeaders(context) if headers: return headers return ()
from AccessControl import ClassSecurityInfo from Globals import InitializeClass from DateTime import DateTime from ComputedAttribute import ComputedAttribute from Products.RhaptosModuleStorage.ModuleDBTool import CommitError from LatestReference import addLatestReference from psycopg2 import IntegrityError, Binary from interfaces.IVersionStorage import IVersionStorage logger = logging.getLogger('RhaptosRepository') HISTORY_FIRST_ID = 10000 # dummy add methods to support copy from Globals import DTMLFile manage_addVersionFolderForm=DTMLFile('www/addform', globals()) def manage_addVersionFolder(self, id, title=''): pass class VersionFolderStorage(SimpleItem): __implements__ = (IVersionStorage) def __init__(self, id): self.id = id def generateId(self): """Fetch a unique ID for this object""" return 'col%d' % self.portal_moduledb.sqlGetNextCollectionId()[0].collectionid
class DefaultDublinCoreImpl(PropertyManager): """ Mix-in class which provides Dublin Core methods """ __implements__ = DublinCore, CatalogableDublinCore, MutableDublinCore security = ClassSecurityInfo() def __init__(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='', rights=''): now = DateTime() self.creation_date = now self.modification_date = now self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights) # # Set-modification-date-related methods. # In DefaultDublinCoreImpl for lack of a better place. # # Class variable default for an upgrade. modification_date = None security.declarePrivate('notifyModified') def notifyModified(self): """ Take appropriate action after the resource has been modified. For now, change the modification_date. """ # XXX This could also store the id of the user doing modifications. self.setModificationDate() # XXX Could this be simply protected by ModifyPortalContent ? security.declarePrivate('setModificationDate') def setModificationDate(self, modification_date=None): """ Set the date when the resource was last modified. When called without an argument, sets the date to now. """ if modification_date is None: self.modification_date = DateTime() else: self.modification_date = self._datify(modification_date) # # DublinCore interface query methods # security.declarePublic('Title') def Title(self): "Dublin Core element - resource name" return self.title security.declarePublic('Creator') def Creator(self): # XXX: fixme using 'portal_membership' -- should iterate over # *all* owners "Dublin Core element - resource creator" owner = self.getOwner() if hasattr(owner, 'getId'): return owner.getId() return 'No owner' security.declarePublic('Subject') def Subject(self): "Dublin Core element - resource keywords" return getattr(self, 'subject', ()) # compensate for *old* content security.declarePublic('Publisher') def Publisher(self): "Dublin Core element - resource publisher" # XXX: fixme using 'portal_metadata' return 'No publisher' security.declarePublic('Description') def Description(self): "Dublin Core element - resource summary" return self.description security.declarePublic('Contributors') def Contributors(self): "Dublin Core element - additional contributors to resource" # XXX: fixme return self.contributors security.declarePublic('Date') def Date(self): "Dublin Core element - default date" # Return effective_date if set, modification date otherwise date = getattr(self, 'effective_date', None) if date is None: date = self.modified() return date.ISO() security.declarePublic('CreationDate') def CreationDate(self): """ Dublin Core element - date resource created. """ # return unknown if never set properly return self.creation_date and self.creation_date.ISO() or 'Unknown' security.declarePublic('EffectiveDate') def EffectiveDate(self): """ Dublin Core element - date resource becomes effective. """ ed = getattr(self, 'effective_date', None) return ed and ed.ISO() or 'None' security.declarePublic('ExpirationDate') def ExpirationDate(self): """ Dublin Core element - date resource expires. """ ed = getattr(self, 'expiration_date', None) return ed and ed.ISO() or 'None' security.declarePublic('ModificationDate') def ModificationDate(self): """ Dublin Core element - date resource last modified. """ return self.modified().ISO() security.declarePublic('Type') def Type(self): "Dublin Core element - Object type" if hasattr(aq_base(self), 'getTypeInfo'): ti = self.getTypeInfo() if ti is not None: return ti.Title() return self.meta_type security.declarePublic('Format') def Format(self): """ Dublin Core element - resource format """ return self.format security.declarePublic('Identifier') def Identifier(self): "Dublin Core element - Object ID" # XXX: fixme using 'portal_metadata' (we need to prepend the # right prefix to self.getPhysicalPath(). return self.absolute_url() security.declarePublic('Language') def Language(self): """ Dublin Core element - resource language """ return self.language security.declarePublic('Rights') def Rights(self): """ Dublin Core element - resource copyright """ return self.rights # # DublinCore utility methods # def content_type(self): """ WebDAV needs this to do the Right Thing (TM). """ return self.Format() __FLOOR_DATE = DateTime(1970, 0) # always effective security.declarePublic('isEffective') def isEffective(self, date): """ Is the date within the resource's effective range? """ pastEffective = (self.effective_date is None or self.effective_date <= date) beforeExpiration = (self.expiration_date is None or self.expiration_date >= date) return pastEffective and beforeExpiration # # CatalogableDublinCore methods # security.declarePublic('created') def created(self): """ Dublin Core element - date resource created, returned as DateTime. """ # allow for non-existent creation_date, existed always date = getattr(self, 'creation_date', None) return date is None and self.__FLOOR_DATE or date security.declarePublic('effective') def effective(self): """ Dublin Core element - date resource becomes effective, returned as DateTime. """ marker = [] date = getattr(self, 'effective_date', marker) if date is marker: date = getattr(self, 'creation_date', None) return date is None and self.__FLOOR_DATE or date __CEILING_DATE = DateTime(9999, 0) # never expires security.declarePublic('expires') def expires(self): """ Dublin Core element - date resource expires, returned as DateTime. """ date = getattr(self, 'expiration_date', None) return date is None and self.__CEILING_DATE or date security.declarePublic('modified') def modified(self): """ Dublin Core element - date resource last modified, returned as DateTime. """ date = self.modification_date if date is None: # Upgrade. date = self.bobobase_modification_time() self.modification_date = date return date security.declarePublic('getMetadataHeaders') def getMetadataHeaders(self): """ Return RFC-822-style headers. """ hdrlist = [] hdrlist.append(('Title', self.Title())) hdrlist.append(('Subject', string.join(self.Subject(), ', '))) hdrlist.append(('Publisher', self.Publisher())) hdrlist.append(('Description', self.Description())) hdrlist.append(('Contributors', string.join(self.Contributors(), '; '))) hdrlist.append(('Effective_date', self.EffectiveDate())) hdrlist.append(('Expiration_date', self.ExpirationDate())) hdrlist.append(('Type', self.Type())) hdrlist.append(('Format', self.Format())) hdrlist.append(('Language', self.Language())) hdrlist.append(('Rights', self.Rights())) return hdrlist # # MutableDublinCore methods # security.declarePrivate('_datify') def _datify(self, attrib): if attrib == 'None': attrib = None elif not isinstance(attrib, DateTime): if attrib is not None: attrib = DateTime(attrib) return attrib security.declareProtected(ModifyPortalContent, 'setTitle') def setTitle(self, title): "Dublin Core element - resource name" self.title = title security.declareProtected(ModifyPortalContent, 'setSubject') def setSubject(self, subject): "Dublin Core element - resource keywords" self.subject = tuplize('subject', subject) security.declareProtected(ModifyPortalContent, 'setDescription') def setDescription(self, description): "Dublin Core element - resource summary" self.description = description security.declareProtected(ModifyPortalContent, 'setContributors') def setContributors(self, contributors): "Dublin Core element - additional contributors to resource" # XXX: fixme self.contributors = tuplize('contributors', contributors, semi_split) security.declareProtected(ModifyPortalContent, 'setEffectiveDate') def setEffectiveDate(self, effective_date): """ Dublin Core element - date resource becomes effective. """ self.effective_date = self._datify(effective_date) security.declareProtected(ModifyPortalContent, 'setExpirationDate') def setExpirationDate(self, expiration_date): """ Dublin Core element - date resource expires. """ self.expiration_date = self._datify(expiration_date) security.declareProtected(ModifyPortalContent, 'setFormat') def setFormat(self, format): """ Dublin Core element - resource format """ self.format = format security.declareProtected(ModifyPortalContent, 'setLanguage') def setLanguage(self, language): """ Dublin Core element - resource language """ self.language = language security.declareProtected(ModifyPortalContent, 'setRights') def setRights(self, rights): """ Dublin Core element - resource copyright """ self.rights = rights # # Management tab methods # security.declarePrivate('_editMetadata') def _editMetadata(self, title=_marker, subject=_marker, description=_marker, contributors=_marker, effective_date=_marker, expiration_date=_marker, format=_marker, language=_marker, rights=_marker): """ Update the editable metadata for this resource. """ if title is not _marker: self.setTitle(title) if subject is not _marker: self.setSubject(subject) if description is not _marker: self.setDescription(description) if contributors is not _marker: self.setContributors(contributors) if effective_date is not _marker: self.setEffectiveDate(effective_date) if expiration_date is not _marker: self.setExpirationDate(expiration_date) if format is not _marker: self.setFormat(format) if language is not _marker: self.setLanguage(language) if rights is not _marker: self.setRights(rights) security.declareProtected(ModifyPortalContent, 'manage_metadata') manage_metadata = DTMLFile('zmi_metadata', _dtmldir) security.declareProtected(ModifyPortalContent, 'manage_editMetadata') def manage_editMetadata(self, title, subject, description, contributors, effective_date, expiration_date, format, language, rights, REQUEST): """ Update metadata from the ZMI. """ self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights) REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_metadata' + '?manage_tabs_message=Metadata+updated.') security.declareProtected(ModifyPortalContent, 'editMetadata') def editMetadata(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='en-US', rights=''): """ used to be: editMetadata = WorkflowAction(_editMetadata) Need to add check for webDAV locked resource for TTW methods. """ # as per bug #69, we cant assume they use the webdav # locking interface, and fail gracefully if they dont if hasattr(self, 'failIfLocked'): self.failIfLocked() self._editMetadata(title=title, subject=subject, description=description, contributors=contributors, effective_date=effective_date, expiration_date=expiration_date, format=format, language=language, rights=rights) self.reindexObject()
class ActionsTool(UniqueObject, Folder, ActionProviderBase): """ Weave together the various sources of "actions" which are apropos to the current user and context. """ __implements__ = (IActionsTool, ActionProviderBase.__implements__) id = 'portal_actions' meta_type = 'CMF Actions Tool' _actions = (ActionInformation( id='folderContents', title='Folder contents', action=Expression(text='string:${folder_url}/folder_contents'), condition=Expression(text='python: folder is not object'), permissions=(ListFolderContents, ), category='folder', visible=1), ) action_providers = ('portal_membership', 'portal_actions', 'portal_registration', 'portal_types', 'portal_discussion', 'portal_undo', 'portal_syndication', 'portal_workflow', 'portal_properties') security = ClassSecurityInfo() manage_options = (ActionProviderBase.manage_options + ({ 'label': 'Action Providers', 'action': 'manage_actionProviders' }, { 'label': 'Overview', 'action': 'manage_overview' }) + Folder.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainActionsTool', _dtmldir) manage_actionProviders = DTMLFile('manageActionProviders', _dtmldir) security.declareProtected(ManagePortal, 'manage_aproviders') def manage_aproviders(self, apname='', chosen=(), add_provider=0, del_provider=0, REQUEST=None): """ Manage action providers through-the-web. """ providers = list(self.listActionProviders()) new_providers = [] if add_provider: providers.append(apname) elif del_provider: for item in providers: if item not in chosen: new_providers.append(item) providers = new_providers self.action_providers = tuple(providers) if REQUEST is not None: return self.manage_actionProviders( self, REQUEST, manage_tabs_message='Providers changed.') # # Programmatically manipulate the list of action providers # security.declareProtected(ManagePortal, 'listActionProviders') def listActionProviders(self): """ List the ids of all Action Providers queried by this tool. """ return self.action_providers security.declareProtected(ManagePortal, 'addActionProvider') def addActionProvider(self, provider_name): """ Add an Action Provider id to the providers queried by this tool. """ ap = list(self.action_providers) if hasattr(self, provider_name) and provider_name not in ap: ap.append(provider_name) self.action_providers = tuple(ap) security.declareProtected(ManagePortal, 'deleteActionProvider') def deleteActionProvider(self, provider_name): """ Delete an Action Provider id from providers queried by this tool. """ ap = list(self.action_providers) if provider_name in ap: ap.remove(provider_name) self.action_providers = tuple(ap) # # 'portal_actions' interface methods # security.declarePublic('listFilteredActionsFor') def listFilteredActionsFor(self, object=None): """ List all actions available to the user. """ #cache = None #cache_mgr = getToolByName(self, 'portal_actionscache', None) #if cache_mgr is not None: # cache = cache_mgr.ZCacheManager_getCache() #if cache is not None: # pm = getToolByName(self, 'portal_membership') # if object is None: # object_url = '' # else: # object_url = object.absolute_url() # if pm.isAnonymousUser(): # member = None # else: # member = pm.getAuthenticatedMember() # # Prepare a cache key. # keyset = {'object_url': object_url, # 'member': member, # } # result = cache.ZCache_get(ob=self, keywords=keyset) # if result is not None: # # Got a cached value. # return result actions = [] ec = getExprContext(self, object) # Include actions from specific tools. for provider_name in self.listActionProviders(): provider = getattr(self, provider_name) if IActionProvider.isImplementedBy(provider): start = time() actions.extend(provider.listActionInfos(object=object, ec=ec)) stop = time() open('/tmp/provider_times', 'a').write('%-20s: %8.3f\n' % (provider_name, (stop - start) * 1000)) else: # for Action Providers written for CMF versions before 1.5 actions.extend(self._listActionInfos(provider, object)) # Include actions from object. if object is not None: base = aq_base(object) if IActionProvider.isImplementedBy(base): actions.extend(object.listActionInfos(object=object)) elif hasattr(base, 'listActions'): # for objects written for CMF versions before 1.5 actions.extend(self._listActionInfos(object, object)) # Reorganize the actions by category. filtered_actions = { 'user': [], 'folder': [], 'object': [], 'global': [], 'workflow': [], } for action in actions: catlist = filtered_actions.setdefault(action['category'], []) catlist.append(action) #if cache is not None: # result = cache.ZCache_set(ob=self, data=filtered_actions, # keywords=keyset) return filtered_actions # listFilteredActions() is an alias. security.declarePublic('listFilteredActions') listFilteredActions = listFilteredActionsFor security.declarePrivate('ZCacheable_getModTime') def ZCacheable_getModTime(self, mtime_func=None): '''Returns the highest of the last mod times.''' # Based on: # mtime_func # self.mtime # self.__class__.mtime # (if in a ZClass) zclass_instance.mtime # zclass_instance.__class__.mtime mtime = mtime_func and mtime_func() or 0 base = aq_base(self) return max(getattr(base, '_p_mtime', mtime), mtime) # # Helper method for backwards compatibility # def _listActionInfos(self, provider, object): """ for Action Providers written for CMF versions before 1.5 """ warn( 'ActionProvider interface not up to date. In CMF 1.6 ' 'portal_actions will ignore listActions() of \'%s\'.' % provider.getId(), DeprecationWarning) info = getOAI(self, object) actions = provider.listActions(info) action_infos = [] if actions and not isinstance(actions[0], dict): ec = getExprContext(self, object) for ai in actions: if not ai.getVisibility(): continue permissions = ai.getPermissions() if permissions: category = ai.getCategory() if (object is not None and (category.startswith('object') or category.startswith('workflow'))): context = object elif (info['folder'] is not None and category.startswith('folder')): context = info['folder'] else: context = info['portal'] for permission in permissions: allowed = _checkPermission(permission, context) if allowed: break if not allowed: continue if not ai.testCondition(ec): continue action_infos.append(ai.getAction(ec)) else: for i in actions: if not i.get('visible', 1): continue permissions = i.get('permissions', None) if permissions: category = i['category'] if (object is not None and (category.startswith('object') or category.startswith('workflow'))): context = object elif (info['folder'] is not None and category.startswith('folder')): context = info['folder'] else: context = info['portal'] for permission in permissions: allowed = _checkPermission(permission, context) if allowed: break if not allowed: continue action_infos.append(i) return action_infos
class VersionsTool(UniqueObject, SimpleItemWithProperties): __doc__ = __doc__ # copy from module id = 'portal_versions' meta_type = 'Portal Versions Tool' security = ClassSecurityInfo() manage_options = ({ 'label': 'Overview', 'action': 'manage_overview' }, ) + SimpleItemWithProperties.manage_options # With auto_copy_forward turned on, the versions tool lets users # check out an object even if it is not updated to the latest # revision. It copies the old revision forward. Note that # this feature really shouldn't be enabled unless users also have the # ability to revert to specific revisions. auto_copy_forward = 1 repository_name = 'VersionRepository' _properties = ( { 'id': 'repository_name', 'type': 'string', 'mode': 'w', 'label': 'ID of the version repository' }, { 'id': 'auto_copy_forward', 'type': 'boolean', 'mode': 'w', 'label': 'Copy old revisions forward rather than disallow checkout' }, ) security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainVersionsTool', _wwwdir) # helper methods def _getVersionRepository(self): repo = aq_acquire(self, self.repository_name, containment=1) return repo def _getBranchName(self, info): parts = info.version_id.split('.') if len(parts) > 1: return parts[-2] return 'mainline' # public methods security.declarePublic('isUnderVersionControl') def isUnderVersionControl(self, obj): """Returns a true value if the object is under version control. """ obj = unproxied(obj) repo = self._getVersionRepository() return repo.isUnderVersionControl(obj) security.declarePublic('isCheckedOut') def isCheckedOut(self, obj): """Returns a true value if the object is checked out. """ obj = unproxied(obj) repo = self._getVersionRepository() if not repo.isUnderVersionControl(obj): return 0 info = repo.getVersionInfo(obj) return (info.status == info.CHECKED_OUT) security.declarePublic('isResourceUpToDate') def isResourceUpToDate(self, obj, require_branch=0): """Return true if a version-controlled resource is up to date. """ obj = unproxied(obj) repo = self._getVersionRepository() return repo.isResourceUpToDate(obj, require_branch) # protected methods security.declarePublic('checkout') def checkout(self, obj): """Opens the object for development. Returns the object, which might be different from what was passed to the method if the object was replaced. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() old_state = None if not repo.isUnderVersionControl(obj): repo.applyVersionControl(obj) elif self.auto_copy_forward: if not repo.isResourceUpToDate(obj, require_branch=1): # The object is not at the latest revision or has a # sticky tag. Get it unstuck by copying the old state # forward after the object has been checked out. info = repo.getVersionInfo(obj) old_state = repo.getVersionOfResource(info.history_id, info.version_id) # Momentarily revert to the branch. obj = repo.updateResource(obj, self._getBranchName(info)) obj = repo.checkoutResource(obj) # Copy the old state into the object, minus __vc_info__. # XXX There ought to be some way to do this more cleanly. obj._p_changed = 1 for key in obj.__dict__.keys(): if key != '__vc_info__': if not old_state.__dict__.has_key(key): del obj.__dict__[key] for key, value in old_state.__dict__.items(): if key != '__vc_info__': obj.__dict__[key] = value # Check in as a copy. obj = repo.checkinResource( obj, 'Copied from revision %s' % info.version_id) repo.checkoutResource(obj) return None security.declarePublic('checkin') def checkin(self, obj, message=None): """Checks in a new version. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() if not repo.isUnderVersionControl(obj): repo.applyVersionControl(obj, message) else: if (not repo.isResourceUpToDate(obj, require_branch=1) and self.isCheckedOut(obj)): # This is a strange state, but it can be fixed. # Revert the object to the branch, replace the # reverted state with the new state, and check in. new_dict = obj.__dict__.copy() # Uncheckout obj = repo.uncheckoutResource(obj) info = repo.getVersionInfo(obj) obj = repo.updateResource(obj, self._getBranchName(info)) # Checkout obj = repo.checkoutResource(obj) # Restore the new state for key in obj.__dict__.keys(): if key != '__vc_info__': if not new_dict.has_key(key): del obj.__dict__[key] for key, value in new_dict.items(): if key != '__vc_info__': obj.__dict__[key] = value repo.checkinResource(obj, message or '') return None security.declarePublic('getLogEntries') def getLogEntries(self, obj, only_checkins=0): """Returns the log entries for an object as a sequence of mappings. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() if not repo.isUnderVersionControl(obj): return [] entries = repo.getLogEntries(obj) res = [] for entry in entries: a = entry.action if a == entry.ACTION_CHECKOUT: action = 'checkout' elif a == entry.ACTION_CHECKIN: action = 'checkin' elif a == entry.ACTION_UNCHECKOUT: action = 'uncheckout' elif a == entry.ACTION_UPDATE: action = 'update' else: action = '?' if only_checkins and action != 'checkin': continue res.append({ 'timestamp': entry.timestamp, 'version_id': entry.version_id, 'action': action, 'message': entry.message, 'user_id': entry.user_id, 'path': entry.path, }) return res security.declarePublic('getVersionId') def getVersionId(self, obj, plus=0): """Returns the version ID of the current revision. If the 'plus' flag is set and the object is checked out, the version ID will include a plus sign to indicate that when the object is checked in, it will have a higher version number. """ obj = unproxied(obj) repo = self._getVersionRepository() if repo.isUnderVersionControl(obj): info = repo.getVersionInfo(obj) res = info.version_id if plus and info.status == info.CHECKED_OUT: res += '+' return res else: return '' security.declarePublic('getVersionIds') def getVersionIds(self, obj): """Returns the version IDs of all revisions for an object. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() ids = repo.getVersionIds(obj) ids = map(int, ids) ids.sort() return map(str, ids) security.declarePublic('getHistoryId') def getHistoryId(self, obj): """Returns the version history ID of the object. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() return repo.getVersionInfo(obj).history_id security.declarePublic('revertToVersion') def revertToVersion(self, obj, version_id): """Reverts the object to the given version. If make_new_revision, a new revision is created, so that the object's state can progress along a new line without making the user deal with branches, labels, etc. """ verifyPermission(UseVersionControl, obj) obj = unproxied(obj) repo = self._getVersionRepository() # Verify the object is under version control. repo.getVersionInfo(obj) if self.isCheckedOut(obj): # Save the current data. self.checkin(obj, 'Auto-saved') repo.updateResource(obj, version_id)
"""Logout current user""" p = getattr(REQUEST, '_logout_path', None) if p is not None: return apply(self.restrictedTraverse(p)) realm = RESPONSE.realm RESPONSE.setStatus(401) RESPONSE.setHeader('WWW-Authenticate', 'basic realm="%s"' % realm, 1) RESPONSE.setBody("""<html> <head><title>Logout</title></head> <body> <p> You have been logged out. </p> </body> </html>""") return security.declarePublic('manage_zmi_prefs') manage_zmi_prefs = DTMLFile('dtml/manage_zmi_prefs', globals()) # Navigation doesn't have an inherited __class_init__ so doesn't get # initialized automatically. file = DTMLFile('dtml/manage_page_style.css', globals()) Navigation.security.declarePublic('manage_page_style.css') setattr(Navigation, 'manage_page_style.css', file) InitializeClass(Navigation)
class MetadataTool(UniqueObject, SimpleItem, ActionProviderBase): __implements__ = (IMetadataTool, ActionProviderBase.__implements__) id = 'portal_metadata' meta_type = 'Default Metadata Tool' _actions = () # # Default values. # publisher = '' element_specs = None #initial_values_hook = None #validation_hook = None security = ClassSecurityInfo() def __init__( self, publisher=None #, initial_values_hook=None #, validation_hook=None , element_specs=DEFAULT_ELEMENT_SPECS): self.editProperties(publisher #, initial_values_hook #, validation_hook ) self.element_specs = PersistentMapping() for name, is_multi_valued in element_specs: self.element_specs[name] = ElementSpec(is_multi_valued) # # ZMI methods # manage_options = ( ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, { 'label': 'Properties', 'action': 'propertiesForm' }, { 'label': 'Elements', 'action': 'elementPoliciesForm' } # TODO , { 'label' : 'Types' # , 'action' : 'typesForm' # } ) + SimpleItem.manage_options) security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainMetadataTool', _dtmldir) security.declareProtected(ManagePortal, 'propertiesForm') propertiesForm = DTMLFile('metadataProperties', _dtmldir) security.declareProtected(ManagePortal, 'editProperties') def editProperties( self, publisher=None # TODO , initial_values_hook=None # TODO , validation_hook=None , REQUEST=None): """ Form handler for "tool-wide" properties (including list of metadata elements). """ if publisher is not None: self.publisher = publisher # TODO self.initial_values_hook = initial_values_hook # TODO self.validation_hook = validation_hook if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Tool+updated.') security.declareProtected(ManagePortal, 'elementPoliciesForm') elementPoliciesForm = DTMLFile('metadataElementPolicies', _dtmldir) security.declareProtected(ManagePortal, 'addElementPolicy') def addElementPolicy(self, element, content_type, is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary, REQUEST=None): """ Add a type-specific policy for one of our elements. """ if content_type == '<default>': content_type = None spec = self.getElementSpec(element) spec.addPolicy(content_type) policy = spec.getPolicy(content_type) policy.edit(is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/elementPoliciesForm' + '?element=' + element + '&manage_tabs_message=Policy+added.') security.declareProtected(ManagePortal, 'removeElementPolicy') def removeElementPolicy(self, element, content_type, REQUEST=None): """ Remvoe a type-specific policy for one of our elements. """ if content_type == '<default>': content_type = None spec = self.getElementSpec(element) spec.removePolicy(content_type) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/elementPoliciesForm' + '?element=' + element + '&manage_tabs_message=Policy+removed.') security.declareProtected(ManagePortal, 'updateElementPolicy') def updateElementPolicy(self, element, content_type, is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary, REQUEST=None): """ Update a policy for one of our elements ('content_type' will be '<default>' when we edit the default). """ if content_type == '<default>': content_type = None spec = self.getElementSpec(element) policy = spec.getPolicy(content_type) policy.edit(is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/elementPoliciesForm' + '?element=' + element + '&manage_tabs_message=Policy+updated.') # # Element spec manipulation. # security.declareProtected(ManagePortal, 'listElementSpecs') def listElementSpecs(self): """ Return a list of ElementSpecs representing the elements managed by the tool. """ res = [] for k, v in self.element_specs.items(): res.append((k, v.__of__(self))) return res security.declareProtected(ManagePortal, 'getElementSpec') def getElementSpec(self, element): """ Return an ElementSpec representing the tool's knowledge of 'element'. """ return self.element_specs[element].__of__(self) security.declareProtected(ManagePortal, 'addElementSpec') def addElementSpec(self, element, is_multi_valued, REQUEST=None): """ Add 'element' to our list of managed elements. """ # Don't replace. if self.element_specs.has_key(element): return self.element_specs[element] = ElementSpec(is_multi_valued) if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Element+' + element + '+added.') security.declareProtected(ManagePortal, 'removeElementSpec') def removeElementSpec(self, element, REQUEST=None): """ Remove 'element' from our list of managed elements. """ del self.element_specs[element] if REQUEST is not None: REQUEST['RESPONSE'].redirect(self.absolute_url() + '/propertiesForm' + '?manage_tabs_message=Element+' + element + '+removed.') security.declareProtected(ManagePortal, 'listPolicies') def listPolicies(self, typ=None): """ Show all policies for a given content type, or the default if None. """ result = [] for element, spec in self.listElementSpecs(): result.append((element, spec.getPolicy(typ))) return result # # 'portal_metadata' interface # security.declarePrivate('getFullName') def getFullName(self, userid): """ Convert an internal userid to a "formal" name, if possible, perhaps using the 'portal_membership' tool. Used to map userid's for Creator, Contributor DCMI queries. """ return userid # TODO: do lookup here security.declarePublic('getPublisher') def getPublisher(self): """ Return the "formal" name of the publisher of the portal. """ return self.publisher security.declarePublic('listAllowedVocabulary') def listAllowedVocabulary(self, element, content=None, content_type=None): """ List allowed keywords for a given portal_type, or all possible keywords if none supplied. """ spec = self.getElementSpec(element) if content_type is None and content: content_type = content.getPortalTypeName() return spec.getPolicy(content_type).allowedVocabulary() security.declarePublic('listAllowedSubjects') def listAllowedSubjects(self, content=None, content_type=None): """ List allowed keywords for a given portal_type, or all possible keywords if none supplied. """ return self.listAllowedVocabulary('Subject', content, content_type) security.declarePublic('listAllowedFormats') def listAllowedFormats(self, content=None, content_type=None): """ List the allowed 'Content-type' values for a particular portal_type, or all possible formats if none supplied. """ return self.listAllowedVocabulary('Format', content, content_type) security.declarePublic('listAllowedLanguages') def listAllowedLanguages(self, content=None, content_type=None): """ List the allowed language values. """ return self.listAllowedVocabulary('Language', content, content_type) security.declarePublic('listAllowedRights') def listAllowedRights(self, content=None, content_type=None): """ List the allowed values for a "Rights" selection list; this gets especially important where syndication is involved. """ return self.listAllowedVocabulary('Rights', content, content_type) security.declareProtected(ModifyPortalContent, 'setInitialMetadata') def setInitialMetadata(self, content): """ Set initial values for content metatdata, supplying any site-specific defaults. """ for element, policy in self.listPolicies(content.getPortalTypeName()): if not getattr(content, element)(): if policy.supplyDefault(): setter = getattr(content, 'set%s' % element) setter(policy.defaultValue()) elif policy.isRequired(): raise MetadataError, \ 'Metadata element %s is required.' % element # TODO: Call initial_values_hook, if present security.declareProtected(View, 'validateMetadata') def validateMetadata(self, content): """ Enforce portal-wide policies about DCI, e.g., requiring non-empty title/description, etc. Called by the CMF immediately before saving changes to the metadata of an object. """ for element, policy in self.listPolicies(content.getPortalTypeName()): value = getattr(content, element)() if not value and policy.isRequired(): raise MetadataError, \ 'Metadata element %s is required.' % element if value and policy.enforceVocabulary(): values = policy.isMultiValued() and value or [value] for value in values: if not value in policy.allowedVocabulary(): raise MetadataError, \ 'Value %s is not in allowed vocabulary for ' \ 'metadata element %s.' % ( value, element )
class Tabs(ExtensionClass.Base): """Mix-in provides management folder tab support.""" security = ClassSecurityInfo() security.declarePublic('manage_tabs') manage_tabs = DTMLFile('dtml/manage_tabs', globals()) manage_options = () security.declarePublic('filtered_manage_options') def filtered_manage_options(self, REQUEST=None): validate = getSecurityManager().validate result = [] try: options = tuple(self.manage_options) except TypeError: options = tuple(self.manage_options()) for d in options: filter = d.get('filter', None) if filter is not None and not filter(self): continue path = d.get('path', None) if path is None: path = d['action'] o = self.restrictedTraverse(path, None) if o is None: continue result.append(d) return result manage_workspace__roles__ = ('Authenticated', ) def manage_workspace(self, REQUEST): """Dispatch to first interface in manage_options """ options = self.filtered_manage_options(REQUEST) try: m = options[0]['action'] if m == 'manage_workspace': raise TypeError except (IndexError, KeyError): raise Unauthorized, ('You are not authorized to view this object.') if m.find('/'): raise Redirect, ("%s/%s" % (REQUEST['URL1'], m)) return getattr(self, m)(self, REQUEST) def tabs_path_default( self, REQUEST, # Static var unquote=urllib.unquote, ): steps = REQUEST._steps[:-1] script = REQUEST['BASEPATH1'] linkpat = '<a href="%s/manage_workspace">%s</a>' out = [] url = linkpat % (escape(script, 1), ' /') if not steps: return url last = steps.pop() for step in steps: script = '%s/%s' % (script, step) out.append(linkpat % (escape(script, 1), escape(unquote(step)))) script = '%s/%s' % (script, last) out.append('<a class="strong-link" href="%s/manage_workspace">%s</a>' % (escape(script, 1), escape(unquote(last)))) return '%s%s' % (url, '/'.join(out)) def tabs_path_info( self, script, path, # Static vars quote=urllib.quote, ): out = [] while path[:1] == '/': path = path[1:] while path[-1:] == '/': path = path[:-1] while script[:1] == '/': script = script[1:] while script[-1:] == '/': script = script[:-1] path = path.split('/')[:-1] if script: path = [script] + path if not path: return '' script = '' last = path[-1] del path[-1] for p in path: script = "%s/%s" % (script, quote(p)) out.append('<a href="%s/manage_workspace">%s</a>' % (script, p)) out.append(last) return '/'.join(out) security.declarePublic('class_manage_path') def class_manage_path(self): if self.__class__.__module__[:1] != '*': return path = getattr(self.__class__, '_v_manage_path_roles', None) if path is None: meta_type = self.meta_type for zclass in self.getPhysicalRoot()._getProductRegistryData( 'zclasses'): if zclass['meta_type'] == meta_type: break else: self.__class__._v_manage_path_roles = '' return path = self.__class__._v_manage_path_roles = ( '%(product)s/%(id)s' % zclass) if path: return '/Control_Panel/Products/%s/manage_workspace' % path
class DirectoryViewSurrogate (Folder): meta_type = 'Filesystem Directory View' all_meta_types = () _isDirectoryView = 1 # _is_wrapperish = 1 security = ClassSecurityInfo() def __init__(self, real, data, objects): d = self.__dict__ d.update(data) d.update(real.__dict__) d['_real'] = real d['_objects'] = objects def __setattr__(self, name, value): d = self.__dict__ d[name] = value setattr(d['_real'], name, value) security.declareProtected(ManagePortal, 'manage_propertiesForm') manage_propertiesForm = DTMLFile( 'dirview_properties', _dtmldir ) security.declareProtected(ManagePortal, 'manage_properties') def manage_properties( self, dirpath, REQUEST=None ): """ Update the directory path of the DV. """ self.__dict__['_real']._dirpath = dirpath if REQUEST is not None: REQUEST['RESPONSE'].redirect( '%s/manage_propertiesForm' % self.absolute_url() ) security.declareProtected(AccessContentsInformation, 'getCustomizableObject') def getCustomizableObject(self): ob = aq_parent(aq_inner(self)) while getattr(ob, '_isDirectoryView', 0): ob = aq_parent(aq_inner(ob)) return ob security.declareProtected(AccessContentsInformation, 'listCustFolderPaths') def listCustFolderPaths(self, adding_meta_type=None): ''' Returns a list of possible customization folders as key, value pairs. ''' rval = [] ob = self.getCustomizableObject() listFolderHierarchy(ob, '', rval, adding_meta_type) rval.sort() return rval security.declareProtected(AccessContentsInformation, 'getDirPath') def getDirPath(self): return self.__dict__['_real']._dirpath security.declarePublic('getId') def getId(self): return self.id
class ActionsTool(UniqueObject, Folder, ActionProviderBase): """ Weave together the various sources of "actions" which are apropos to the current user and context. """ __implements__ = (IActionsTool, ActionProviderBase.__implements__) id = 'portal_actions' meta_type = 'CMF Actions Tool' _actions = (ActionInformation( id='folderContents', title='Folder contents', action=Expression(text='string:${folder_url}/folder_contents'), condition=Expression(text='python: folder is not object'), permissions=(ListFolderContents, ), category='folder', visible=1), ) action_providers = ('portal_membership', 'portal_actions', 'portal_registration', 'portal_types', 'portal_discussion', 'portal_undo', 'portal_syndication', 'portal_workflow', 'portal_properties') security = ClassSecurityInfo() manage_options = (ActionProviderBase.manage_options + ({ 'label': 'Action Providers', 'action': 'manage_actionProviders' }, { 'label': 'Overview', 'action': 'manage_overview' }) + Folder.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainActionsTool', _dtmldir) manage_actionProviders = DTMLFile('manageActionProviders', _dtmldir) security.declareProtected(ManagePortal, 'manage_aproviders') def manage_aproviders(self, apname='', chosen=(), add_provider=0, del_provider=0, REQUEST=None): """ Manage action providers through-the-web. """ providers = list(self.listActionProviders()) new_providers = [] if add_provider: providers.append(apname) elif del_provider: for item in providers: if item not in chosen: new_providers.append(item) providers = new_providers self.action_providers = tuple(providers) if REQUEST is not None: return self.manage_actionProviders( self, REQUEST, manage_tabs_message='Providers changed.') # # Programmatically manipulate the list of action providers # security.declareProtected(ManagePortal, 'listActionProviders') def listActionProviders(self): """ List the ids of all Action Providers queried by this tool. """ return self.action_providers security.declareProtected(ManagePortal, 'addActionProvider') def addActionProvider(self, provider_name): """ Add an Action Provider id to the providers queried by this tool. """ ap = list(self.action_providers) if hasattr(self, provider_name) and provider_name not in ap: ap.append(provider_name) self.action_providers = tuple(ap) security.declareProtected(ManagePortal, 'deleteActionProvider') def deleteActionProvider(self, provider_name): """ Delete an Action Provider id from providers queried by this tool. """ ap = list(self.action_providers) if provider_name in ap: ap.remove(provider_name) self.action_providers = tuple(ap) # # 'portal_actions' interface methods # security.declarePublic('listFilteredActionsFor') def listFilteredActionsFor(self, object=None): """ List all actions available to the user. """ actions = [] # Include actions from specific tools. for provider_name in self.listActionProviders(): provider = getattr(self, provider_name) if hasattr(aq_base(provider), 'listActionInfos'): actions.extend(provider.listActionInfos(object=object)) else: # for Action Providers written for CMF versions before 1.5 actions.extend(self._listActionInfos(provider, object)) # Include actions from object. if object is not None: base = aq_base(object) if hasattr(base, 'listActionInfos'): actions.extend(object.listActionInfos(object=object)) elif hasattr(base, 'listActions'): # for objects written for CMF versions before 1.5 actions.extend(self._listActionInfos(object, object)) # Reorganize the actions by category. filtered_actions = { 'user': [], 'folder': [], 'object': [], 'global': [], 'workflow': [], } for action in actions: category = action['category'] catlist = filtered_actions.get(category, None) if catlist is None: filtered_actions[category] = catlist = [] # Filter out duplicate actions by identity... if not action in catlist: catlist.append(action) # ...should you need it, here's some code that filters # by equality (use instead of the two lines above) #if not [a for a in catlist if a==action]: # catlist.append(action) return filtered_actions # listFilteredActions() is an alias. security.declarePublic('listFilteredActions') listFilteredActions = listFilteredActionsFor # # Helper method for backwards compatibility # def _listActionInfos(self, provider, object): """ for Action Providers written for CMF versions before 1.5 """ warn( 'ActionProvider interface not up to date. In CMF 1.6 ' 'portal_actions will ignore listActions() of \'%s\'.' % provider.getId(), DeprecationWarning) info = getOAI(self, object) actions = provider.listActions(info) action_infos = [] if actions and type(actions[0]) is not DictionaryType: ec = getExprContext(self, object) for ai in actions: if not ai.getVisibility(): continue permissions = ai.getPermissions() if permissions: category = ai.getCategory() if (object is not None and (category.startswith('object') or category.startswith('workflow'))): context = object elif (info['folder'] is not None and category.startswith('folder')): context = info['folder'] else: context = info['portal'] for permission in permissions: allowed = _checkPermission(permission, context) if allowed: break if not allowed: continue if not ai.testCondition(ec): continue action_infos.append(ai.getAction(ec)) else: for i in actions: if not i.get('visible', 1): continue permissions = i.get('permissions', None) if permissions: category = i['category'] if (object is not None and (category.startswith('object') or category.startswith('workflow'))): context = object elif (info['folder'] is not None and category.startswith('folder')): context = info['folder'] else: context = info['portal'] for permission in permissions: allowed = _checkPermission(permission, context) if allowed: break if not allowed: continue action_infos.append(i) return action_infos
from Globals import DTMLFile from AccessControl import ClassSecurityInfo from AccessControl.Permissions import view_management_screens, view, change_images_and_files try: from cStringIO import StringIO except ImportError: from StringIO import StringIO class ODF2XHTMLBody(ODF2XHTML): def rewritelink(self, imghref): imghref = imghref.replace("Pictures/", "index_html?pict=") return imghref manage_addODFFileForm = DTMLFile('dtml/odffileAdd', globals()) def manage_addODFFile(self, id='', file='', title='', precondition='', content_type='', conversion='embedded', REQUEST=None): """Add a new File object. Creates a new File object 'id' with the contents of 'file'""" id = str(id)
log = logging.getLogger('zen.Mibs') _pathToMIB = '/var/ext/uploadedMIBs' def manage_addMibOrganizer(context, id, REQUEST=None): """make a device class""" sc = MibOrganizer(id) context._setObject(id, sc) sc = context._getOb(id) if REQUEST is not None: REQUEST['RESPONSE'].redirect(context.absolute_url_path() + '/manage_main') addMibOrganizer = DTMLFile('dtml/addMibOrganizer', globals()) def _oid2name(mibSearch, oid, exactMatch=True, strip=False): """Return a name for an oid. This function is extracted out of the MibOrganizer class and takes mibSearch as a parameter to make it easier to unit test. """ oid = oid.strip('.') if exactMatch: brains = mibSearch(oid=oid) if len(brains) > 0: return brains[0].id else: return ""
from zExceptions import NotFound from Products.ZenUtils.jsonutils import json from Products.ZenUtils.Utils import extractPostContent def manage_addLocation(context, id, description = "", address="", REQUEST = None): """make a Location""" loc = Location(id, description) context._setObject(id, loc) loc.description = description loc.address = address if REQUEST is not None: REQUEST['RESPONSE'].redirect(context.absolute_url_path() +'/manage_main') addLocation = DTMLFile('dtml/addLocation',globals()) class Location(DeviceOrganizer, ZenPackable): """ Location is a DeviceGroup Organizer that manages physical device Locations. """ # Organizer configuration dmdRootName = "Locations" address = '' latlong = None portal_type = meta_type = event_key = 'Location' _properties = DeviceOrganizer._properties + (
@deprecated def manage_addMultiGraphReportClass(context, id, title=None, REQUEST=None): """ Construct a new MultiGraphreportclass """ frc = MultiGraphReportClass(id, title) context._setObject(id, frc) if REQUEST is not None: audit('UI.ReportClass.Add', frc.id, title=title, organizer=context) messaging.IMessageSender(self).sendToBrowser( 'Organizer Created', 'Report organizer %s was created.' % id) REQUEST['RESPONSE'].redirect(context.absolute_url() + '/manage_main') addMultiGraphReportClass = DTMLFile('dtml/addMultiGraphReportClass', globals()) class MultiGraphReportClass(ReportClass): portal_type = meta_type = "MultiGraphReportClass" # Remove this relationship after version 2.1 _relations = ReportClass._relations + ( ('graphDefs', ToManyCont(ToOne, 'Products.ZenModel.GraphDefinition', 'reportClass')), ) security = ClassSecurityInfo() def getReportClass(self):
from Products.ZenRelations.RelSchema import * from ProductClass import ProductClass def manage_addSoftwareClass(context, id, title=None, REQUEST=None): """make a SoftwareClass""" d = SoftwareClass(id, title) context._setObject(id, d) if REQUEST is not None: REQUEST['RESPONSE'].redirect(context.absolute_url() + '/manage_main') addSoftwareClass = DTMLFile('dtml/addSoftwareClass', globals()) class SoftwareClass(ProductClass): """SoftwareClass object""" portal_type = meta_type = 'SoftwareClass' build = "" version = "" _properties = ProductClass._properties + ( { 'id': 'version', 'type': 'string', 'mode': 'w' },
class GroupDataTool(UniqueObject, SimpleItem, PropertyManager, ActionProviderBase): """ This tool wraps group objects, allowing transparent access to properties. """ # BBB: CMF 2.2/Plone 4.0 no longer have Z2 interfaces __implements__ = (IGroupDataTool, getattr(ActionProviderBase, "__implements__", ())) id = 'portal_groupdata' meta_type = 'CMF Group Data Tool' _actions = () _v_temps = None _properties = ({'id': 'title', 'type': 'string', 'mode': 'wd'}, ) security = ClassSecurityInfo() manage_options = (ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, ) + PropertyManager.manage_options + SimpleItem.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('dtml/explainGroupDataTool', globals()) def __init__(self): self._members = OOBTree() # Create the default properties. self._setProperty('description', '', 'text') self._setProperty('email', '', 'string') # # 'portal_groupdata' interface methods # security.declarePrivate('wrapGroup') def wrapGroup(self, g): """Returns an object implementing the GroupData interface""" id = g.getId() members = self._members if not members.has_key(id): # Get a temporary member that might be # registered later via registerMemberData(). temps = self._v_temps if temps is not None and temps.has_key(id): portal_group = temps[id] else: base = aq_base(self) portal_group = GroupData(base, id) if temps is None: self._v_temps = {id: portal_group} if hasattr(self, 'REQUEST'): # No REQUEST during tests. self.REQUEST._hold(CleanupTemp(self)) else: temps[id] = portal_group else: portal_group = members[id] # Return a wrapper with self as containment and # the user as context. return portal_group.__of__(self).__of__(g) security.declarePrivate('registerGroupData') def registerGroupData(self, g, id): ''' Adds the given member data to the _members dict. This is done as late as possible to avoid side effect transactions and to reduce the necessary number of entries. ''' self._members[id] = aq_base(g)