def __init__(self, id, title, file, permissions=None, categories=None): self.id=id self.title=title file,ext=os.path.splitext(file) prefix,file=os.path.split(file) self.index_html=DTMLFile(file,prefix) if permissions is not None: self.permissions=permissions if categories is not None: self.categories=categories
class DTMLTopic(HelpTopic): """ A basic Help Topic. Holds a HTMLFile object. """ def __init__(self, id, title, file, permissions=None, categories=None): self.id=id self.title=title file,ext=os.path.splitext(file) prefix,file=os.path.split(file) self.index_html=DTMLFile(file,prefix) if permissions is not None: self.permissions=permissions if categories is not None: self.categories=categories def SearchableText(self): "The full text of the Help Topic, for indexing purposes" return '%s %s' % (self.title, self.index_html.read())
class MemberDataTool (UniqueObject, SimpleItem, PropertyManager, ActionProviderBase): '''This tool wraps user objects, making them act as Member objects. ''' id = 'portal_memberdata' meta_type = 'CMF Member Data Tool' _actions = [] _v_temps = None _properties = () security = ClassSecurityInfo() manage_options=( ActionProviderBase.manage_options + ({ 'label' : 'Overview' , 'action' : 'manage_overview' } , { 'label' : 'Contents' , 'action' : 'manage_showContents' } ) + PropertyManager.manage_options + SimpleItem.manage_options ) # # ZMI methods # security.declareProtected( CMFCorePermissions.ManagePortal , 'manage_overview' ) manage_overview = DTMLFile( 'explainMemberDataTool', _dtmldir ) security.declareProtected( CMFCorePermissions.ViewManagementScreens , 'manage_showContents') manage_showContents = DTMLFile('memberdataContents', _dtmldir ) security.declareProtected( CMFCorePermissions.ViewManagementScreens , 'getContentsInformation',) def __init__(self): self._members = OOBTree() # Create the default properties. self._setProperty('email', '', 'string') self._setProperty('portal_skin', '', 'string') self._setProperty('listed', '', 'boolean') self._setProperty('login_time', '2000/01/01', 'date') self._setProperty('last_login_time', '2000/01/01', 'date') # # 'portal_memberdata' interface methods # security.declarePrivate('listActions') def listActions(self, info=None): """ Return actions provided via tool. """ return self._actions security.declarePrivate('getMemberDataContents') def getMemberDataContents(self): ''' Return the number of members stored in the _members BTree and some other useful info ''' membertool = getToolByName(self, 'portal_membership') members = self._members user_list = membertool.listMemberIds() member_list = members.keys() member_count = len(members) orphan_count = 0 for member in member_list: if member not in user_list: orphan_count = orphan_count + 1 return [{ 'member_count' : member_count, 'orphan_count' : orphan_count }] security.declarePrivate( 'searchMemberDataContents' ) def searchMemberDataContents( self, search_param, search_term ): """ Search members """ res = [] if search_param == 'username': search_param = 'id' for user_wrapper in self._members.values(): searched = getattr( user_wrapper, search_param, None ) if searched is not None and string.find( searched, search_term ) != -1: res.append( { 'username' : getattr( user_wrapper, 'id' ) , 'email' : getattr( user_wrapper, 'email', '' ) } ) return res security.declarePrivate('pruneMemberDataContents') def pruneMemberDataContents(self): ''' Compare the user IDs stored in the member data tool with the list in the actual underlying acl_users and delete anything not in acl_users ''' membertool= getToolByName(self, 'portal_membership') members = self._members user_list = membertool.listMemberIds() for tuple in members.items(): member_name = tuple[0] member_obj = tuple[1] if member_name not in user_list: del members[member_name] security.declarePrivate('wrapUser') def wrapUser(self, u): ''' If possible, returns the Member object that corresponds to the given User object. ''' id = u.getUserName() 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): m = temps[id] else: base = aq_base(self) m = MemberData(base, id) if temps is None: self._v_temps = {id:m} else: temps[id] = m else: m = members[id] # Return a wrapper with self as containment and # the user as context. return m.__of__(self).__of__(u) security.declarePrivate('registerMemberData') def registerMemberData(self, m, 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] = m
class RegistrationTool(BaseTool): """ Manage through-the-web signup policies. """ __implements__ = BaseTool.__implements__ meta_type = 'Default Registration Tool' _actions = (ActionInformation( id='join', title='Join', description='Click here to Join', action=Expression(text='string:${portal_url}/join_form'), permissions=(AddPortalMember, ), category='user', condition=Expression(text='not: member'), visible=1), ) security = ClassSecurityInfo() # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_options = (ActionProviderBase.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, )) manage_overview = DTMLFile('explainRegistrationTool', _dtmldir) # # 'portal_registration' interface # security.declarePublic('testPasswordValidity') def testPasswordValidity(self, password, confirm=None): """ Verify that the password satisfies the portal's requirements. o If the password is valid, return None. o If not, return a string explaining why. """ if len(password) < 5 and not _checkPermission('Manage portal', self): return 'Your password must contain at least 5 characters.' if confirm is not None and confirm != password: return ('Your password and confirmation did not match. ' + 'Please try again.') return None security.declarePublic('testPropertiesValidity') def testPropertiesValidity(self, props, member=None): """ Verify that the properties supplied satisfy portal's requirements. o If the properties are valid, return None. o If not, return a string explaining why. """ if member is None: # New member. username = props.get('username', '') if not username: return 'You must enter a valid name.' if not self.isMemberIdAllowed(username): return ('The login name you selected is already ' 'in use or is not valid. Please choose another.') email = props.get('email') if email is None: return 'You must enter an email address.' ok, message = _checkEmail(email) if not ok: return 'You must enter a valid email address.' else: # Existing member. email = props.get('email') if email is not None: ok, message = _checkEmail(email) if not ok: return 'You must enter a valid email address.' # Not allowed to clear an existing non-empty email. existing = member.getProperty('email') if existing and email == '': return 'You must enter a valid email address.' return None security.declarePublic('mailPassword') def mailPassword(self, forgotten_userid, REQUEST): """ Email a forgotten password to a member. o Raise an exception if user ID is not found. """ membership = getToolByName(self, 'portal_membership') member = membership.getMemberById(forgotten_userid) if member is None: raise 'NotFound', 'The username you entered could not be found.' # assert that we can actually get an email address, otherwise # the template will be made with a blank To:, this is bad if not member.getProperty('email'): raise 'ValueError', 'That user does not have an email address.' check, msg = _checkEmail(member.getProperty('email')) if not check: raise 'ValueError', msg # Rather than have the template try to use the mailhost, we will # render the message ourselves and send it from here (where we # don't need to worry about 'UseMailHost' permissions). mail_text = self.mail_password_template(self, REQUEST, member=member, password=member.getPassword()) host = self.MailHost host.send(mail_text) return self.mail_password_response(self, REQUEST) security.declarePublic('registeredNotify') def registeredNotify(self, new_member_id): """ Handle mailing the registration / welcome message. """ membership = getToolByName(self, 'portal_membership') member = membership.getMemberById(new_member_id) if member is None: raise 'NotFound', 'The username you entered could not be found.' password = member.getPassword() email = member.getProperty('email') if email is None: raise ValueError('Member %s has no e-mail address!' % new_member_id) check, msg = _checkEmail(email) if not check: raise 'ValueError', msg # Rather than have the template try to use the mailhost, we will # render the message ourselves and send it from here (where we # don't need to worry about 'UseMailHost' permissions). mail_text = self.registered_notify_template(self, self.REQUEST, member=member, password=password, email=email) host = self.MailHost host.send(mail_text) return self.mail_password_response(self, self.REQUEST) security.declareProtected(ManagePortal, 'editMember') def editMember(self, member_id, properties=None, password=None, roles=None, domains=None): """ Edit a user's properties and security settings o Checks should be done before this method is called using testPropertiesValidity and testPasswordValidity """ mtool = getToolByName(self, 'portal_membership') member = mtool.getMemberById(member_id) member.setMemberProperties(properties) member.setSecurityProfile(password, roles, domains) return member
""" invoked by whatever Object manager to create a Redirect challenge plugin. """ # set object on the object manager. self._setObject(id, RedirectChallenge(id, title, path)) if REQUEST: REQUEST['RESPONSE'].redirect("%s/manage_workspace" % self.absolute_url(), lock=1) # the simplest form for create a new RedirectChallenge instance. manage_addRedirectChallengeForm = DTMLFile('../zmi/redirect', globals()) # a very simple challenge plugin for testing. class RedirectChallenge(BasePlugin): """ A simple challenge plugin to redirect un-authenticated user to a static URL. """ # meta_type will be displayed in the add dropdown list on folder # acl_users meta_type = "iScorpio PAS Simple Redirect Challenge" # this will help to manage the properties on Properties tab. _properties = ({
from Products.ZenUtils.Utils import unused from Products.ZenUtils.tbdetail import log_tb def manage_addToManyContRelationship(context, id, REQUEST=None): """factory for ToManyRelationship""" rel = ToManyContRelationship(id) context._setObject(rel.id, rel) if REQUEST: REQUEST['RESPONSE'].redirect(context.absolute_url_path() + '/manage_main') return rel.id addToManyContRelationship = DTMLFile('dtml/addToManyContRelationship', globals()) class ToManyContRelationship(ToManyRelationshipBase): """ ToManyContRelationship is the ToMany side of a realtionship that contains its related objects (like the normal Zope ObjectManager) """ meta_type = "ToManyContRelationship" security = ClassSecurityInfo() def __init__(self, id): """set our instance values""" self.id = id
class DateRangeIndex(UnIndex): """Index for date ranges, such as the "effective-expiration" range in CMF. Any object may return None for either the start or the end date: for the start date, this should be the logical equivalent of "since the beginning of time"; for the end date, "until the end of time". Therefore, divide the space of indexed objects into four containers: - Objects which always match (i.e., they returned None for both); - Objects which match after a given time (i.e., they returned None for the end date); - Objects which match until a given time (i.e., they returned None for the start date); - Objects which match only during a specific interval. """ __implements__ = UnIndex.__implements__ implements(IDateRangeIndex) security = ClassSecurityInfo() meta_type = "DateRangeIndex" manage_options = ({ 'label': 'Properties', 'action': 'manage_indexProperties' }, ) query_options = ['query'] since_field = until_field = None def __init__(self, id, since_field=None, until_field=None, caller=None, extra=None): if extra: since_field = extra.since_field until_field = extra.until_field self._setId(id) self._edit(since_field, until_field) self.clear() security.declareProtected(VIEW_PERMISSION, 'getSinceField') def getSinceField(self): """Get the name of the attribute indexed as start date. """ return self._since_field security.declareProtected(VIEW_PERMISSION, 'getUntilField') def getUntilField(self): """Get the name of the attribute indexed as end date. """ return self._until_field manage_indexProperties = DTMLFile('manageDateRangeIndex', _dtmldir) security.declareProtected(INDEX_MGMT_PERMISSION, 'manage_edit') def manage_edit(self, since_field, until_field, REQUEST): """ """ self._edit(since_field, until_field) REQUEST['RESPONSE'].redirect('%s/manage_main' '?manage_tabs_message=Updated' % REQUEST.get('URL2')) security.declarePrivate('_edit') def _edit(self, since_field, until_field): """ Update the fields used to compute the range. """ self._since_field = since_field self._until_field = until_field security.declareProtected(INDEX_MGMT_PERMISSION, 'clear') def clear(self): """ Start over fresh. """ self._always = IITreeSet() self._since_only = IOBTree() self._until_only = IOBTree() self._since = IOBTree() self._until = IOBTree() self._unindex = IOBTree() # 'datum' will be a tuple of date ints self._length = BTrees.Length.Length() # # PluggableIndexInterface implementation (XXX inherit assertions?) # def getEntryForObject(self, documentId, default=None): """ Get all information contained for the specific object identified by 'documentId'. Return 'default' if not found. """ return self._unindex.get(documentId, default) def index_object(self, documentId, obj, threshold=None): """ Index an object: - 'documentId' is the integer ID of the document - 'obj' is the object to be indexed - ignore threshold """ if self._since_field is None: return 0 since = getattr(obj, self._since_field, None) if safe_callable(since): since = since() since = self._convertDateTime(since) until = getattr(obj, self._until_field, None) if safe_callable(until): until = until() until = self._convertDateTime(until) datum = (since, until) old_datum = self._unindex.get(documentId, None) if datum == old_datum: # No change? bail out! return 0 if old_datum is not None: old_since, old_until = old_datum self._removeForwardIndexEntry(old_since, old_until, documentId) self._insertForwardIndexEntry(since, until, documentId) self._unindex[documentId] = datum return 1 def unindex_object(self, documentId): """ Remove the object corresponding to 'documentId' from the index. """ datum = self._unindex.get(documentId, None) if datum is None: return since, until = datum self._removeForwardIndexEntry(since, until, documentId) del self._unindex[documentId] def uniqueValues(self, name=None, withLengths=0): """ Return a list of unique values for 'name'. If 'withLengths' is true, return a sequence of tuples, in the form '( value, length )'. """ if not name in (self._since_field, self._until_field): return [] if name == self._since_field: t1 = self._since t2 = self._since_only else: t1 = self._until t2 = self._until_only result = [] IntType = type(0) if not withLengths: result.extend(t1.keys()) result.extend(t2.keys()) else: for key in t1.keys(): set = t1[key] if type(set) is IntType: length = 1 else: length = len(set) result.append((key, length)) for key in t2.keys(): set = t2[key] if type(set) is IntType: length = 1 else: length = len(set) result.append((key, length)) return tuple(result) def _apply_index(self, request, cid=''): """ Apply the index to query parameters given in 'request', which should be a mapping object. If the request does not contain the needed parametrs, then return None. If the request contains a parameter with the name of the column + "_usage", snif for information on how to handle applying the index. Otherwise return two objects. The first object is a ResultSet containing the record numbers of the matching records. The second object is a tuple containing the names of all data fields used. """ record = parseIndexRequest(request, self.getId()) if record.keys is None: return None term = self._convertDateTime(record.keys[0]) # # Aggregate sets for each bucket separately, to avoid # large-small union penalties. # #until_only = IISet() #map( until_only.update, self._until_only.values( term ) ) # XXX use multi-union until_only = multiunion(self._until_only.values(term)) #since_only = IISet() #map( since_only.update, self._since_only.values( None, term ) ) # XXX use multi-union since_only = multiunion(self._since_only.values(None, term)) #until = IISet() #map( until.update, self._until.values( term ) ) # XXX use multi-union until = multiunion(self._until.values(term)) #since = IISet() #map( since.update, self._since.values( None, term ) ) # XXX use multi-union since = multiunion(self._since.values(None, term)) bounded = intersection(until, since) # Merge from smallest to largest. #result = union( self._always, until_only ) result = union(bounded, until_only) result = union(result, since_only) #result = union( result, bounded ) result = union(result, self._always) return result, (self._since_field, self._until_field) # # ZCatalog needs this, although it isn't (yet) part of the interface. # security.declareProtected(VIEW_PERMISSION, 'numObjects') def numObjects(self): """ """ return len(self._unindex) def indexSize(self): """ """ return len(self) # # Helper functions. # def _insertForwardIndexEntry(self, since, until, documentId): """ Insert 'documentId' into the appropriate set based on 'datum'. """ if since is None and until is None: self._always.insert(documentId) elif since is None: set = self._until_only.get(until, None) if set is None: set = self._until_only[until] = IISet() # XXX: Store an int? set.insert(documentId) elif until is None: set = self._since_only.get(since, None) if set is None: set = self._since_only[since] = IISet() # XXX: Store an int? set.insert(documentId) else: set = self._since.get(since, None) if set is None: set = self._since[since] = IISet() # XXX: Store an int? set.insert(documentId) set = self._until.get(until, None) if set is None: set = self._until[until] = IISet() # XXX: Store an int? set.insert(documentId) def _removeForwardIndexEntry(self, since, until, documentId): """ Remove 'documentId' from the appropriate set based on 'datum'. """ if since is None and until is None: self._always.remove(documentId) elif since is None: set = self._until_only.get(until, None) if set is not None: set.remove(documentId) if not set: del self._until_only[until] elif until is None: set = self._since_only.get(since, None) if set is not None: set.remove(documentId) if not set: del self._since_only[since] else: set = self._since.get(since, None) if set is not None: set.remove(documentId) if not set: del self._since[since] set = self._until.get(until, None) if set is not None: set.remove(documentId) if not set: del self._until[until] def _convertDateTime(self, value): if value is None: return value if type(value) == type(''): dt_obj = DateTime(value) value = dt_obj.millis() / 1000 / 60 # flatten to minutes if isinstance(value, DateTime): value = value.millis() / 1000 / 60 # flatten to minutes result = int(value) if isinstance(result, long): # this won't work (Python 2.3) raise OverflowError('%s is not within the range of dates allowed' 'by a DateRangeIndex' % value) return result
class AdminNews(SimpleItem, PropertyManager): """ A Blend Admin News object """ meta_type = "Blend Admin News" manage_options = (( { 'label': 'Edit', 'action': 'manage_main', }, { 'label': 'View', 'action': 'manage_view', }, { 'label': 'CMS Edit', 'action': 'adminNewsEditCMS', }, ) + PropertyManager.manage_options + SimpleItem.manage_options) def __init__(self, id, title, data, author, active, tags, created): "initialize a new instance of a Blend Admin News" self.id = id #required self.title = title self.author = author self.data = data self.active = active self.tags = tags self.tags = tags.strip() self.tags = tags.capitalize() self.created = created def manage_editSaveAction(self, title, data, author, active, tags, created, RESPONSE=None): "Edit CMS Admin News object property values" self.title = title self.data = data self.author = author self.active = active self.tags = tags self.tags = tags.strip() self.tags = tags.capitalize() self.created = created self._p_changed = 1 RESPONSE.redirect('adminNewsEditCMS') def manage_editZMI(self, title, author, data, created, RESPONSE=None): "Edit CMS Admin News product property values" self.title = title self.author = author self.data = data self.created = created self._p_changed = 1 RESPONSE.redirect('manage_main') index_html = DTMLFile('dtml/indexAdminNews', globals()) cms_edit_header = DTMLFile('dtml/edit_cms_header', globals()) cms_header = DTMLFile('dtml/standard_cms_header', globals()) cms_footer = DTMLFile('dtml/standard_cms_footer', globals()) news_header = DTMLFile('dtml/news_cms_header', globals()) site_header = DTMLFile('dtml/standard_html_header', globals()) site_footer = DTMLFile('dtml/standard_html_footer', globals()) manage_main = DTMLFile('dtml/manage_editAdminNews', globals()) adminNewsEditCMS = DTMLFile('dtml/manage_editAdminNewsCMS', globals()) checkActive = DTMLFile('dtml/manage_adminNewscheckActive', globals()) delete = DTMLFile('dtml/manage_deleteAdminNews', globals())
class ZenPropertyManager(object, PropertyManager): """ ZenPropertyManager adds keyedselection type to PropertyManager. A keyedselection displays a different name in the popup than the actual value the popup will have. It also has management for zenProperties which are properties that can be inherited long the acquision chain. All properties are for a branch are defined on a "root node" specified by the function which must be returned by the function getZenRootNode that should be over ridden in a sub class. Prperties can then be added further "down" the aq_chain by calling setZenProperty on any contained node. ZenProperties all have the same prefix which is defined by iszprop this can be overridden in a subclass. ZenPropertyManager overrides getProperty and getPropertyType from PropertyManager to support acquisition. If you want to query an object about a property, but do not want it to search the acquistion chain then use the super classes method or aq_base. Example: # acquires property from dmd.Devices dmd.Devices.Server.getProperty('zCollectorPlugins') # does not acquire property from dmd.Devices PropertyManager.getProperty(dmd.Devices.Server, 'zCollectorPlugins') # also does not acquire property from dmd.Devices aq_base(dmd.Devices.Server).getProperty('zSnmpCommunity') The properties are stored as attributes which is convenient, but can be confusing. Attribute access always uses acquistion. Setting an attribute, will not add it to the list of properties, so subsquent calls to hasProperty or getProperty won't return it. Property Transformers are stored at dmd.propertyTransformers and transform the property based on type during calls to the _setProperty, _updateProperty, and getProperty methods. Adding a property using _setProperty applies the appropriate transformer and adds its value as an attribute, but when you access it as an attribute the property transformer is again applied, but this time using its transformForGet method. """ security = ClassSecurityInfo() manage_propertiesForm = DTMLFile('dtml/properties', globals(), property_extensible_schema__=1) def _setPropValue(self, id, value): """Override from PerpertyManager to handle checks and ip creation. """ self._wrapperCheck(value) propType = self.getPropertyType(id) if propType == 'keyedselection': value = int(value) if not getattr(self, '_v_propdict', False): self._v_propdict = self.propdict() if 'setter' in self._v_propdict: settername = self._v_propdict['setter'] setter = getattr(aq_base(self), settername, None) if not setter: raise ValueError("setter %s for property %s doesn't exist" % (settername, id)) if not callable(setter): raise TypeError("setter %s for property %s not callable" % (settername, id)) setter(value) else: setattr(self, id, value) def _setProperty(self, id, value, type='string', label=None, visible=True, setter=None, description=None): """For selection and multiple selection properties the value argument indicates the select variable of the property. """ self._wrapperCheck(value) if not self.valid_property_id(id): raise BadRequest('Id %s is invalid or duplicate' % id) def setprops(**pschema): if setter: pschema['setter'] = setter if label: pschema['label'] = label if description: pschema['description'] = description self._properties = self._properties + (pschema, ) if type in ('selection', 'multiple selection'): # NOTE: Moved `import messaging` here to lazify code and # remove circular import. from Products.ZenWidgets import messaging if not hasattr(self, value): IMessageSender(self).sendToBrowser( "Selection variable '%s' not found" % value, priority=messaging.WARNING, ) return # NOTE: When creating selection properties, specify the name of # another property as the Value. This property should return a list # of strings will be used to provide choices for the selection. select_values = getattr(self, value) if not (isinstance(select_values, (list, tuple)) and all(isinstance(v, basestring) for v in select_values)): IMessageSender(self).sendToBrowser( "Selection variable '%s' must be a LINES type" % value, priority=messaging.WARNING, ) return setprops(id=id, type=type, visible=visible, select_variable=value) self._setPropValue(id, '' if (type == 'selection') else []) else: setprops(id=id, type=type, visible=visible) self._setPropValue(id, value) _onlystars = re.compile("^\*+$").search def _updateProperty(self, id, value): """This method sets a property on a zope object. It overrides the method in PropertyManager. If Zope is upgraded you will need to check that this method has not changed! It is overridden so that we can catch the ValueError returned from the field2* converters in the class Converters.py """ try: # Do not update property if its a password # and value is secured(equals to all asterisk) if self.zenPropIsPassword(id) and self._onlystars(value): return super(ZenPropertyManager, self)._updateProperty(id, value) except ValueError: proptype = self.getPropertyType(id) log.error( "Error Saving Property '%s'. New value '%s' is of invalid " "type. It should be type '%s'.", id, value, proptype) security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'manage_editProperties') def manage_editProperties(self, REQUEST): """Edit object properties via the web. The purpose of this method is to change all property values, even those not listed in REQUEST; otherwise checkboxes that get turned off will be ignored. Use manage_changeProperties() instead for most situations. """ for prop in self._propertyMap(): name = prop['id'] if 'w' in prop.get('mode', 'wd'): value = REQUEST.get(name, '') if self.zenPropIsPassword(name) and self._onlystars(value): continue self._updateProperty(name, value) if getattr(self, "index_object", False): self.index_object() if REQUEST: return self.manage_propertiesForm( self, REQUEST, manage_tabs_message="Saved changes.") def getZenRootNode(self): """Sub class must implement to use zenProperties. """ raise NotImplementedError security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyIds') def zenPropertyIds(self, all=True, pfilt=iszprop): """Return list of device tree property names. If all use list from property root node. """ if all: rootnode = self.getZenRootNode() else: if self.id == self.dmdRootName: return [] rootnode = aq_base(self) return sorted(prop for prop in rootnode.propertyIds() if pfilt(prop)) security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyItems') def zenPropertyItems(self): """Return list of (id, value) tuples of zenProperties. """ return map(lambda x: (x, getattr(self, x)), self.zenPropertyIds()) security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyMap') def zenPropertyMap(self, pfilt=iszprop): """Return property mapping of device tree properties. """ rootnode = self.getZenRootNode() return sorted( (pdict for pdict in rootnode.propertyMap() if pfilt(pdict['id'])), key=lambda x: x['id']) security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyString') def zenPropertyString(self, id): """Return the value of a device tree property as a string. """ def displayLines(lines): return '\n'.join(str(line) for line in lines) def displayPassword(password): return '*' * len(password) def displayOthers(other): return other displayFunctions = {'lines': displayLines, 'password': displayPassword} display = displayFunctions.get(self.getPropertyType(id), displayOthers) return display(self.getProperty(id, '')) security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropIsPassword') def zenPropIsPassword(self, id): """Is this field a password field. """ passwordTypes = [ 'password', 'passwd', 'multilinecredentials', 'instancecredentials' ] return self.getPropertyType(id) in passwordTypes security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyPath') def zenPropertyPath(self, id): """Return the primaryId of where a device tree property is found. """ ob = self._findParentWithProperty(id) if ob is None: path = None else: path = ob.getPrimaryId(self.getZenRootNode().getId()) return path security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'setZenProperty') def setZenProperty(self, propname, propvalue, REQUEST=None): """Add or set the propvalue of the property propname on this node of the device Class tree. """ ptype = self.getPropertyType(propname) if ptype == 'lines': dedupedList = [] for x in propvalue: if x not in dedupedList: dedupedList.append(x) propvalue = dedupedList if getattr(aq_base(self), propname, zenmarker) != zenmarker: self._updateProperty(propname, propvalue) else: if ptype in ("selection", 'multiple selection'): ptype = "string" if ptype in type_converters: propvalue = type_converters[ptype](propvalue) if ptype == "password" \ and propvalue == self.zenPropertyString(propname): # Don't save passwords that haven't changed # and don't save "*" passwords pass elif getattr(self, propname, None) != propvalue: self._setProperty(propname, propvalue, type=ptype) if REQUEST: return self.callZenScreen(REQUEST) security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'saveZenProperties') def saveZenProperties(self, pfilt=iszprop, REQUEST=None): """Save all ZenProperties found in the REQUEST.form object. """ oldValues = {} newValues = {} maskFields = [] for name, value in REQUEST.form.items(): if pfilt(name): if self.zenPropIsPassword(name): maskFields.append(name) if self._onlystars(value): continue oldValues[name] = self.getProperty(name) if name == 'zCollectorPlugins': if tuple(getattr(self, name, ())) != tuple(value): self.setZenProperty(name, value) else: self.setZenProperty(name, value) newValues[name] = self.getProperty(name) if REQUEST: audit(('UI', getDisplayType(self), 'EditProperties'), self, data_=newValues, oldData_=oldValues, maskFields_=maskFields) IMessageSender(self).sendToBrowser( 'Configuration Propeties Updated', 'Configuration properties have been updated.') return self.callZenScreen(REQUEST) security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'deleteZenProperty') def deleteZenProperty(self, propname=None, REQUEST=None): """ Delete device tree properties from the this DeviceClass object. """ if propname: try: self._delProperty(propname) except AttributeError: # Occasional object corruption where the propName is in # _properties but not set as an attribute. filter out the prop # and create a new _properties tuple newProps = [x for x in self._properties if x['id'] != propname] self._properties = tuple(newProps) except ValueError: raise ZenPropertyDoesNotExist() if REQUEST: if propname: audit(('UI', getDisplayType(self), 'DeleteZProperty'), self, property=propname) return self.callZenScreen(REQUEST) security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyOptions') def zenPropertyOptions(self, propname): """Provide a set of default options for a ZProperty. """ unused(propname) return [] security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'isLocal') def isLocal(self, propname): """Check to see if a name is local to our current context. """ v = getattr(aq_base(self), propname, zenmarker) return v != zenmarker security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getOverriddenObjects') def getOverriddenObjects(self, propname, showDevices=False): """Get the objects that override a property somewhere below in the tree """ if showDevices: objects = [] for inst in self.getSubInstances('devices'): if inst.isLocal(propname) and inst not in objects: objects.append(inst) for suborg in self.children(): if suborg.isLocal(propname): objects.append(suborg) for inst in suborg.getOverriddenObjects(propname, showDevices): if inst not in objects: objects.append(inst) return objects return [ org for org in self.getSubOrganizers() if org.isLocal(propname) ] def _findParentWithProperty(self, id): """Returns self or the first acquisition parent that has a property with the id. Returns None if no parent had the id. """ return next( (ob for ob in aq_chain(self) if isinstance(ob, ZenPropertyManager) and ob.hasProperty(id)), None) def hasProperty(self, id, useAcquisition=False): """Override method in PropertyManager to support acquisition. """ if useAcquisition: hasProp = self._findParentWithProperty(id) is not None else: hasProp = PropertyManager.hasProperty(self, id) return hasProp def getProperty(self, id, d=None): """Get property value and apply transformer. Overrides method in Zope's PropertyManager class. Acquire values from aquisiton parents if needed. """ ob = self._findParentWithProperty(id) return d if (ob is None) else PropertyManager.getProperty(ob, id, d) security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getPropertyType') def getPropertyType(self, id): """Overrides methods from PropertyManager to support acquistion. """ ob = self._findParentWithProperty(id) if ob is not None: return PropertyManager.getPropertyType(ob, id) security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getZ') def getZ(self, id, default=None): """Return the value of a zProperty on this object. This method is used to lookup zProperties for a user with a role that doesn't have direct access to an attribute further up the acquisition path. If the requested property is a password, then None is returned. @param id: id of zProperty @type id: string @return: Value of zProperty @permission: ZEN_ZPROPERTIES_VIEW >>> dmd.Devices.getZ('zSnmpPort') 161 >>> dmd.Devices.getZ('zSnmpAuthPassword') >>> """ if self.hasProperty(id, useAcquisition=True) \ and not self.zenPropIsPassword(id): return self.getProperty(id) return default def exportZProperties(self, exclusionList=()): """ @param exclusionList: list of zproperties we do not want to export @type exclusionList: collection For this manager will return the following about each zProperty Will return the following about each Zen Property - id - identifier - islocal - if this object has a local definition - value - value for this object - valueAsString - string representation of the property - type - int string lines etc - path - where it is defined - options - acceptable values of this zProperty """ props = [] root = self.getDmdRoot(self.dmdRootName) for zId in self.zenPropertyIds(): if zId in exclusionList: continue prop = self.exportZProperty(zId, root) if not self.zenPropIsPassword(zId): prop['value'] = self.getZ(zId) else: prop['value'] = self.zenPropertyString(zId) # look up the description and label from the root props.append(prop) return props def exportZProperty(self, zId, root=None): if not root: root = self.getDmdRoot(self.dmdRootName) return dict(id=zId, islocal=self.hasProperty(zId), type=self.getPropertyType(zId), path=self.zenPropertyPath(zId), options=self.zenPropertyOptions(zId), category=getzPropertyCategory(zId), value=None, valueAsString=self.zenPropertyString(zId), label=root.propertyLabel(zId), description=root.propertyDescription(zId))
class DiscussionTool(UniqueObject, SimpleItem, ActionProviderBase): __implements__ = (IOldstyleDiscussionTool, ActionProviderBase.__implements__) id = 'portal_discussion' meta_type = 'Oldstyle CMF Discussion Tool' # This tool is used to find the discussion for a given content object. security = ClassSecurityInfo() manage_options = ({ 'label': 'Overview', 'action': 'manage_overview' }, ) + SimpleItem.manage_options # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainDiscussionTool', _dtmldir) # # 'portal_discussion' interface methods # security.declarePublic('getDiscussionFor') def getDiscussionFor(self, content): '''Gets the PortalDiscussion object that applies to content. ''' return OldDiscussable(content).__of__(content) security.declarePublic('isDiscussionAllowedFor') def isDiscussionAllowedFor(self, content): ''' Returns a boolean indicating whether a discussion is allowed for the specified content. ''' if hasattr(content, 'allow_discussion'): return content.allow_discussion typeInfo = getToolByName(self, 'portal_types').getTypeInfo(content) if typeInfo: return typeInfo.allowDiscussion() return 0 security.declarePrivate('listActions') def listActions(self, info=None, object=None): # Return actions for reply and show replies if object is None and info is None: return () if info is None: info = getOAI(self, object) if object is None: object = info.object content = object if content is None or not self.isDiscussionAllowedFor(content): return () discussion = self.getDiscussionFor(content) if discussion.aq_base == content.aq_base: discussion_url = info.object_url else: discussion_url = discussion.absolute_url() actions = ({ 'name': 'Reply', 'url': discussion_url + '/discussion_reply_form', 'permissions': [ReplyToItem], 'category': 'object' }, ) return actions
from DeviceOrganizer import DeviceOrganizer from ZenPackable import ZenPackable def manage_addSystem(context, id, description=None, REQUEST=None): """make a System""" d = System(id, description) context._setObject(id, d) if REQUEST is not None: REQUEST['RESPONSE'].redirect(context.absolute_url_path() + '/manage_main') addSystem = DTMLFile('dtml/addSystem', globals()) class System(DeviceOrganizer, ZenPackable): """ System class is a device organizer that represents a business system. May need to manage "services" as well so that more sophisticated dependencies can be tracked. """ # Organizer configuration dmdRootName = "Systems" portal_type = meta_type = 'System' event_key = "System"
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 def _convertQuery(self, kw): # Convert query to modern syntax for k in 'effective', 'expires': kusage = k + '_usage' if not kw.has_key(kusage): continue usage = kw[kusage] if not usage.startswith('range:'): raise ValueError("Incorrect usage %s" % ` usage `) kw[k] = {'query': kw[k], 'range': usage[6:]} del kw[kusage] # 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() self._convertQuery(kw) # Intersect query restrictions with those implicit to the tool for k in 'effective', 'expires': if kw.has_key(k): range = kw[k]['range'] or '' query = kw[k]['query'] if (not isinstance(query, TupleType) and not isinstance(query, ListType)): query = (query, ) else: range = '' query = None if range.find('min') > -1: lo = min(query) else: lo = None if range.find('max') > -1: hi = max(query) else: hi = None if k == 'effective': if hi is None or hi > now: hi = now if lo is not None and hi < lo: return () else: # 'expires': if lo is None or lo < now: lo = now if hi is not None and hi < lo: return () # Rebuild a query if lo is None: query = hi range = 'max' elif hi is None: query = lo range = 'min' else: query = (lo, hi) range = 'min:max' kw[k] = {'query': query, 'range': range} return 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 TopicIndex(Persistent, SimpleItem): """A TopicIndex maintains a set of FilteredSet objects. Every FilteredSet object consists of an expression and and IISet with all Ids of indexed objects that eval with this expression to 1. """ __implements__ = (PluggableIndex.PluggableIndexInterface, ) implements(ITopicIndex, IPluggableIndex) meta_type = "TopicIndex" query_options = ('query', 'operator') manage_options = ({ 'label': 'FilteredSets', 'action': 'manage_main', 'help': ('TopicIndex', 'TopicIndex_searchResults.stx') }, ) def __init__(self, id, caller=None): self.id = id self.filteredSets = OOBTree() self.operators = ('or', 'and') self.defaultOperator = 'or' def getId(self): return self.id def clear(self): for fs in self.filteredSets.values(): fs.clear() def index_object(self, docid, obj, threshold=100): """ hook for (Z)Catalog """ for fid, filteredSet in self.filteredSets.items(): filteredSet.index_object(docid, obj) return 1 def unindex_object(self, docid): """ hook for (Z)Catalog """ for fs in self.filteredSets.values(): try: fs.unindex_object(docid) except KeyError: LOG.debug('Attempt to unindex document' ' with id %s failed' % docid) return 1 def numObjects(self): return "n/a" def search(self, filter_id): if self.filteredSets.has_key(filter_id): return self.filteredSets[filter_id].getIds() def _apply_index(self, request, cid=''): """ hook for (Z)Catalog 'request' -- mapping type (usually {"topic": "..." } 'cid' -- ??? """ record = parseIndexRequest(request, self.id, self.query_options) if record.keys is None: return None operator = record.get('operator', self.defaultOperator).lower() if operator == 'or': set_func = union else: set_func = intersection res = None for filter_id in record.keys: rows = self.search(filter_id) res = set_func(res, rows) if res: return res, (self.id, ) else: return IITreeSet(), (self.id, ) def uniqueValues(self, name=None, withLength=0): """ needed to be consistent with the interface """ return self.filteredSets.keys() def getEntryForObject(self, docid, default=_marker): """ Takes a document ID and returns all the information we have on that specific object. """ return self.filteredSets.keys() def addFilteredSet(self, filter_id, typeFilteredSet, expr): # Add a FilteredSet object. if self.filteredSets.has_key(filter_id): raise KeyError,\ 'A FilteredSet with this name already exists: %s' % filter_id self.filteredSets[filter_id] = \ FilteredSet.factory(filter_id, typeFilteredSet, expr) def delFilteredSet(self, filter_id): # Delete the FilteredSet object specified by 'filter_id'. if not self.filteredSets.has_key(filter_id): raise KeyError,\ 'no such FilteredSet: %s' % filter_id del self.filteredSets[filter_id] def clearFilteredSet(self, filter_id): # Clear the FilteredSet object specified by 'filter_id'. if not self.filteredSets.has_key(filter_id): raise KeyError,\ 'no such FilteredSet: %s' % filter_id self.filteredSets[filter_id].clear() def manage_addFilteredSet(self, filter_id, typeFilteredSet, expr, URL1, \ REQUEST=None,RESPONSE=None): """ add a new filtered set """ if len(filter_id) == 0: raise RuntimeError, 'Length of ID too short' if len(expr) == 0: raise RuntimeError, 'Length of expression too short' self.addFilteredSet(filter_id, typeFilteredSet, expr) if RESPONSE: RESPONSE.redirect(URL1 + '/manage_workspace?' 'manage_tabs_message=FilteredSet%20added') def manage_delFilteredSet(self, filter_ids=[], URL1=None, \ REQUEST=None,RESPONSE=None): """ delete a list of FilteredSets""" for filter_id in filter_ids: self.delFilteredSet(filter_id) if RESPONSE: RESPONSE.redirect(URL1 + '/manage_workspace?' 'manage_tabs_message=FilteredSet(s)%20deleted') def manage_saveFilteredSet(self,filter_id, expr, URL1=None,\ REQUEST=None,RESPONSE=None): """ save expression for a FilteredSet """ self.filteredSets[filter_id].setExpression(expr) if RESPONSE: RESPONSE.redirect(URL1 + '/manage_workspace?' 'manage_tabs_message=FilteredSet(s)%20updated') def getIndexSourceNames(self): """ return names of indexed attributes """ return ('n/a', ) def manage_clearFilteredSet(self, filter_ids=[], URL1=None, \ REQUEST=None,RESPONSE=None): """ clear a list of FilteredSets""" for filter_id in filter_ids: self.clearFilteredSet(filter_id) if RESPONSE: RESPONSE.redirect(URL1 + '/manage_workspace?' 'manage_tabs_message=FilteredSet(s)%20cleared') manage = manage_main = DTMLFile('dtml/manageTopicIndex', globals()) manage_main._setName('manage_main') editFilteredSet = DTMLFile('dtml/editFilteredSet', globals())
RESPONSE.redirect(URL1 + '/manage_workspace?' 'manage_tabs_message=FilteredSet(s)%20updated') def getIndexSourceNames(self): """ return names of indexed attributes """ return ('n/a', ) def manage_clearFilteredSet(self, filter_ids=[], URL1=None, \ REQUEST=None,RESPONSE=None): """ clear a list of FilteredSets""" for filter_id in filter_ids: self.clearFilteredSet(filter_id) if RESPONSE: RESPONSE.redirect(URL1 + '/manage_workspace?' 'manage_tabs_message=FilteredSet(s)%20cleared') manage = manage_main = DTMLFile('dtml/manageTopicIndex', globals()) manage_main._setName('manage_main') editFilteredSet = DTMLFile('dtml/editFilteredSet', globals()) manage_addTopicIndexForm = DTMLFile('dtml/addTopicIndex', globals()) def manage_addTopicIndex(self, id, REQUEST=None, RESPONSE=None, URL3=None): """Add a TopicIndex""" return self.manage_addIndex(id, 'TopicIndex', extra=None, \ REQUEST=REQUEST, RESPONSE=RESPONSE, URL1=URL3)
class WorkflowTool(UniqueObject, Folder): """ Mediator tool, mapping workflow objects """ id = 'portal_workflow' meta_type = 'CMF Workflow Tool' __implements__ = portal_workflow _chains_by_type = None # PersistentMapping _default_chain = ('default_workflow', ) _default_cataloging = 1 security = ClassSecurityInfo() manage_options = ({ 'label': 'Workflows', 'action': 'manage_selectWorkflows' }, { 'label': 'Overview', 'action': 'manage_overview' }) + Folder.manage_options # # ZMI methods # security.declareProtected(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(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(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': ManagePortal }, ) _manage_selectWorkflows = DTMLFile('selectWorkflows', _dtmldir) security.declareProtected(ManagePortal, 'manage_selectWorkflows') def manage_selectWorkflows(self, REQUEST, manage_tabs_message=None): """ Show 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.Title() 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(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. if not (props is None): for t in ti: id = t.getId() field_name = 'chain_%s' % id chain = props.get(field_name, '(Default)').strip() if chain == '(Default)': # Remove from cbt. if cbt.has_key(id): del cbt[id] else: chain = chain.replace(',', ' ') ids = [] for wf_id in chain.split(' '): 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 = default_chain.replace(',', ' ') ids = [] for wf_id in default_chain.split(' '): 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.') # # portal_workflow implementation. # security.declarePrivate('getCatalogVariablesFor') def getCatalogVariablesFor(self, ob): """ Returns a mapping of the catalog variables that apply to ob. o Invoked by portal_catalog. o Allows workflows to add variables to the catalog based on workflow status, making it possible to implement queues. """ 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): """ Returns a list of actions to be displayed to the user. o Invoked by the portal_actions tool. o Allows workflows to include actions to be displayed in the actions box. o Object actions are supplied by workflows that apply to the object. o Global actions are supplied by all workflows. """ 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 security.declarePublic('getActionsFor') def getActionsFor(self, ob): """ Return a list of action dictionaries for 'ob', just as though queried via 'ActionsTool.listFilteredActionsFor'. """ return self.listActions(WorkflowInformation(ob)) security.declarePublic('doActionFor') def doActionFor(self, ob, action, wf_id=None, *args, **kw): """ Execute the given workflow action for the object. o Invoked by user interface code. o Allows the user to request a workflow action. o The workflow object must perform its own security checks. """ wfs = self.getWorkflowsFor(ob) if wfs is None: wfs = () if wf_id is None: if not wfs: raise WorkflowException('No workflows found.') found = 0 for wf in wfs: if wf.isActionSupported(ob, action): found = 1 break if not found: raise WorkflowException( 'No workflow provides the "%s" action.' % action) else: wf = self.getWorkflowById(wf_id) if wf is None: raise WorkflowException( 'Requested workflow definition not found.') return self._invokeWithNotification(wfs, ob, action, wf.doActionFor, (ob, action) + args, kw) security.declarePublic('getInfoFor') def getInfoFor(self, ob, name, default=_marker, wf_id=None, *args, **kw): """ Return a given workflow-specific property for an object. o Invoked by user interface code. o Allows the user to request information provided by the workflow. o The workflow object must perform its own security checks. """ if wf_id is None: wfs = self.getWorkflowsFor(ob) if wfs is None: if default is _marker: raise WorkflowException('No workflows found.') else: return default found = 0 for wf in wfs: if wf.isInfoSupported(ob, name): found = 1 break if not found: if default is _marker: raise WorkflowException( 'No workflow provides "%s" information.' % name) else: return default else: wf = self.getWorkflowById(wf_id) if wf is None: if default is _marker: raise WorkflowException( 'Requested workflow definition not found.') else: return default res = apply(wf.getInfoFor, (ob, name, default) + args, kw) if res is _marker: raise WorkflowException('Could not get info: %s' % name) return res security.declarePrivate('notifyCreated') def notifyCreated(self, ob): """ Notify all applicable workflows that an object has been created and put in its new place. """ wfs = self.getWorkflowsFor(ob) for wf in wfs: wf.notifyCreated(ob) self._reindexWorkflowVariables(ob) security.declarePrivate('notifyBefore') def notifyBefore(self, ob, action): """ Notifies all applicable workflows of an action before it happens, allowing veto by exception. o Unless an exception is thrown, either a notifySuccess() or notifyException() can be expected later on. o The action usually corresponds to a method name. """ wfs = self.getWorkflowsFor(ob) for wf in wfs: wf.notifyBefore(ob, action) security.declarePrivate('notifySuccess') def notifySuccess(self, ob, action, result=None): """ Notify all applicable workflows that an action has taken place. """ wfs = self.getWorkflowsFor(ob) for wf in wfs: wf.notifySuccess(ob, action, result) security.declarePrivate('notifyException') def notifyException(self, ob, action, exc): """ Notify all applicable workflows that an action failed. """ wfs = self.getWorkflowsFor(ob) for wf in wfs: wf.notifyException(ob, action, exc) security.declarePrivate('getHistoryOf') def getHistoryOf(self, wf_id, ob): """ Return the history of an object. o Invoked by workflow definitions. """ if hasattr(aq_base(ob), 'workflow_history'): wfh = ob.workflow_history return wfh.get(wf_id, None) return () security.declarePrivate('getStatusOf') def getStatusOf(self, wf_id, ob): """ Return the last entry of a workflow history. o Invoked by workflow definitions. """ wfh = self.getHistoryOf(wf_id, ob) if wfh: return wfh[-1] return None security.declarePrivate('setStatusOf') def setStatusOf(self, wf_id, ob, status): """ Append an entry to the workflow history. o Invoked by workflow definitions. """ wfh = None has_history = 0 if hasattr(aq_base(ob), 'workflow_history'): history = ob.workflow_history if history is not None: has_history = 1 wfh = history.get(wf_id, None) if wfh is not None: wfh = list(wfh) if not wfh: wfh = [] wfh.append(status) if not has_history: ob.workflow_history = PersistentMapping() ob.workflow_history[wf_id] = tuple(wfh) # # Administration methods # security.declareProtected(ManagePortal, 'setDefaultChain') def setDefaultChain(self, default_chain): """ Set the default chain for this tool """ default_chain = default_chain.replace(',', ' ') ids = [] for wf_id in default_chain.split(' '): 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(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(lambda x: x.strip(), chain.split(',')) ti = self._listTypeInfo() for t in ti: id = t.getId() if id in pt_names: cbt[id] = tuple(chain) security.declareProtected(ManagePortal, 'updateRoleMappings') def updateRoleMappings(self, REQUEST=None): """ Allow workflows to update the role-permission mappings. """ 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 security.declarePrivate('getWorkflowById') def getWorkflowById(self, wf_id): """ Retrieve a given workflow. """ wf = getattr(self, wf_id, None) if getattr(wf, '_isAWorkflow', 0): return wf else: return None security.declarePrivate('getDefaultChainFor') def getDefaultChainFor(self, ob): """ Return the default chain, if applicable, for ob. """ types_tool = getToolByName(self, 'portal_types', None) if (types_tool is not None and types_tool.getTypeInfo(ob) is not None): return self._default_chain return () security.declarePrivate('getChainFor') def getChainFor(self, ob): """ Returns the chain that applies to the given object. If we get a string as the ob parameter, use it as the portal_type. """ cbt = self._chains_by_type if type(ob) == type(''): pt = ob elif hasattr(aq_base(ob), '_getPortalTypeName'): pt = ob._getPortalTypeName() else: pt = None if pt is None: return () 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): """ Return 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.declareProtected(ManagePortal, 'getWorkflowsFor') def getWorkflowsFor(self, ob): """ Find the workflows 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('wrapWorkflowMethod') def wrapWorkflowMethod(self, ob, method_id, func, args, kw): """ To be invoked only by WorkflowCore. Allows a workflow definition to wrap a WorkflowMethod. """ wf = None wfs = self.getWorkflowsFor(ob) if wfs: for w in wfs: if (hasattr(w, 'isWorkflowMethodSupported') and w.isWorkflowMethodSupported(ob, method_id)): wf = w break else: wfs = () if wf is None: # No workflow wraps this method. return apply(func, args, kw) return self._invokeWithNotification(wfs, ob, method_id, wf.wrapWorkflowMethod, (ob, method_id, func, args, kw), {}) # # Helper methods # security.declarePrivate('_listTypeInfo') def _listTypeInfo(self): """ List the portal types which are available. """ pt = getToolByName(self, 'portal_types', None) if pt is None: return () else: return pt.listTypeInfo() security.declarePrivate('_invokeWithNotification') def _invokeWithNotification(self, wfs, ob, action, func, args, kw): """ Private utility method: call 'func', and deal with exceptions indicating that the object has been deleted or moved. """ 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()
from ZenModelRM import ZenModelRM def manage_addServiceClass(context, id=None, REQUEST = None): """make a device class""" if id: sc = ServiceClass(id) context._setObject(id, sc) sc = context._getOb(id) sc.createCatalog() sc.buildZProperties() if REQUEST is not None: REQUEST['RESPONSE'].redirect(context.absolute_url() + '/manage_main') addServiceClass = DTMLFile('dtml/addServiceClass',globals()) class ServiceClass(ZenModelRM, Commandable, ZenPackable): zope.interface.implements(IIndexed) meta_type = "ServiceClass" dmdRootName = "Services" default_catalog = "serviceSearch" name = "" serviceKeys = () description = "" port = 0 #FIXME prevent failures when ServiceClass is added manually _properties = ( {'id':'name', 'type':'string', 'mode':'w'}, {'id':'serviceKeys', 'type':'lines', 'mode':'w'},
adminNewsEditCMS = DTMLFile('dtml/manage_editAdminNewsCMS', globals()) checkActive = DTMLFile('dtml/manage_adminNewscheckActive', globals()) delete = DTMLFile('dtml/manage_deleteAdminNews', globals()) #Constructor pages. Only used when the product is added to a folder. def manage_addAdminNewsAction(self, id, title='', data='', author='', active=0, tags='', created=DateTime().strftime('%Y/%m/%d'), RESPONSE=None): "Add a Blend Admin News to a folder" id = id.lower() id = id.lstrip() id = id.rstrip() id = id.replace(' ', '_') self._setObject(id, AdminNews(id, title, data, author, active, tags, created)) RESPONSE.redirect('../../../adminNews_html') manage_addAdminNews = DTMLFile('dtml/manage_addAdminNews', globals()) InitializeClass(AdminNews)
class LockTool(UniqueObject, SimpleItemWithProperties): __doc__ = __doc__ # copy from module id = 'portal_lock' meta_type = 'Portal Lock Tool' security = ClassSecurityInfo() manage_options = ( { 'label' : 'Overview', 'action' : 'manage_overview' } , ) + SimpleItemWithProperties.manage_options # With auto_version on, locking automatically causes a version checkout # and unlocking automatically causes a checkin. This is one form # of autoversioning described in the DeltaV introduction. # http://www.webdav.org/deltav/WWW10/deltav-intro.htm auto_version = 1 timeout_days = 14 # 2 weeks _properties = ( {'id': 'auto_version', 'type': 'boolean', 'mode': 'w', 'label': 'Auto checkout and checkin using portal_versions'}, {'id': 'timeout_days', 'type': 'int', 'mode': 'w', 'label': 'Lock timeout in days'}, ) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview' ) manage_overview = DTMLFile('explainLockTool', _wwwdir) # # 'LockTool' interface methods # security.declarePublic('lock') def lock(self, object): '''Locks an object''' if not _checkPermission(LockObjects, object): raise LockingError, 'Inadequate permissions to lock %s' % object locker = self.locker(object) if locker: raise LockingError, '%s is already locked' % pathOf(object) if self.auto_version: vt = getToolByName(self, 'portal_versions', None) if vt is not None: if (vt.isUnderVersionControl(object) and not vt.isCheckedOut(object)): object = vt.checkout(object) user = getSecurityManager().getUser() lockitem = LockItem(user, timeout=(self.timeout_days * 86400)) object.wl_setLock(lockitem.getLockToken(), lockitem) security.declarePublic('breaklock') def breaklock(self, object, message=''): """emergency breaklock....""" locker = self.locker(object) if not _checkPermission(UnlockObjects, object): raise LockingError, ("You cannot unlock %s: lock is held by %s" % (pathOf(object), locker)) object.wl_clearLocks() if self.auto_version: vt = getToolByName(self, 'portal_versions', None) if vt is not None: vt.checkin(object, message) security.declarePublic('unlock') def unlock(self, object, message=''): '''Unlocks an object''' if not _checkPermission(UnlockObjects, object): raise LockingError, "Inadequate permissions to unlock %s" % object locker = self.locker(object) if not locker: raise LockingError, ("Unlocking an unlocked item: %s" % pathOf(object)) user = getSecurityManager().getUser() if user.getId() != locker: raise LockingError, ("Cannot unlock %s: lock is held by %s" % (pathOf(object), locker)) # According to WriteLockInterface, we shouldn't call # wl_clearLocks(), but it seems like the right thing to do anyway. object.wl_clearLocks() if self.auto_version: vt = getToolByName(self, 'portal_versions', None) if vt is not None: vt.checkin(object, message) security.declarePublic('locker') def locker(self, object): '''Returns the locker of an object''' if not WriteLockInterface.isImplementedBy(object): raise LockingError, "%s is not lockable" % pathOf(object) values = object.wl_lockValues() if not values: return '' for lock in values: if lock.isValid(): creator = lock.getCreator() if creator: return creator[1] # The user id without the path # All of the locks are expired or invalid return '' security.declarePublic('isLockedOut') def isLockedOut(self, object): '''Returns a true value if the current user is locked out.''' locker_id = self.locker(object) if locker_id: uid = getSecurityManager().getUser().getId() if uid != locker_id: return 1 return 0 security.declarePublic('locked') def locked(self, object): '''Returns true if an object is locked. Also accepts non-lockable objects, always returning 0.''' if not WriteLockInterface.isImplementedBy(object): return 0 return not not self.locker(object) security.declarePublic('isLockable') def isLockable(self, object): """Return true if object supports locking, regardless of lock state or whether the current user can actually lock.""" return WriteLockInterface.isImplementedBy(object) security.declarePublic('canLock') def canLock(self, object): """Returns true if the current user can lock the given object.""" if self.locked(object): return 0 if not WriteLockInterface.isImplementedBy(object): return 0 if _checkPermission(LockObjects, object): return 1 return 0 security.declarePublic('canUnlock') def canUnlock(self, object): """Returns true if the current user can unlock the given object.""" if not self.locked(object): return 0 if self.isLockedOut(object): return 0 if _checkPermission(UnlockObjects, object): return 1 return 0 security.declarePublic('canChange') def canChange(self, object): """Returns true if the current user can change the given object.""" if not WriteLockInterface.isImplementedBy(object): if self.isLockedOut(object): return 0 if not _checkPermission(ModifyPortalContent, object): return 0 vt = getToolByName(self, 'portal_versions', None) if vt is not None: if (vt.isUnderVersionControl(object) and not vt.isCheckedOut(object)): return 0 return 1
return value if type(value) == type(''): dt_obj = DateTime(value) value = dt_obj.millis() / 1000 / 60 # flatten to minutes if isinstance(value, DateTime): value = value.millis() / 1000 / 60 # flatten to minutes result = int(value) if isinstance(result, long): # this won't work (Python 2.3) raise OverflowError('%s is not within the range of dates allowed' 'by a DateRangeIndex' % value) return result InitializeClass(DateRangeIndex) manage_addDateRangeIndexForm = DTMLFile('addDateRangeIndex', _dtmldir) def manage_addDateRangeIndex(self, id, extra=None, REQUEST=None, RESPONSE=None, URL3=None): """ Add a date range index to the catalog, using the incredibly icky double-indirection-which-hides-NOTHING. """ return self.manage_addIndex(id, 'DateRangeIndex', extra, REQUEST, RESPONSE, URL3)
__version__ = '$Revision: 1.52 $'[11:-2] from Globals import Persistent, DTMLFile, MessageDialog, HTML import OFS.SimpleItem, Acquisition from Globals import InitializeClass from AccessControl import ClassSecurityInfo from AccessControl.Permissions import change_external_methods from AccessControl.Permissions import view_management_screens from AccessControl.Permissions import view as View import AccessControl.Role, sys, os, stat, traceback from OFS.SimpleItem import pretty_tb from App.Extensions import getObject, getPath, FuncCode from Globals import DevelopmentMode from App.Management import Navigation from ComputedAttribute import ComputedAttribute manage_addExternalMethodForm = DTMLFile('dtml/methodAdd', globals()) def manage_addExternalMethod(self, id, title, module, function, REQUEST=None): """Add an external method to a folder Un addition to the standard object-creation arguments, 'id' and title, the following arguments are defined: function -- The name of the python function. This can be a an ordinary Python function, or a bound method. module -- The name of the file containing the function definition. The module normally resides in the 'Extensions'
class DiscussionTool(UniqueObject, SimpleItem): """ Links content to discussions. """ implements(IDiscussionTool) id = 'portal_discussion' meta_type = 'Default Discussion Tool' security = ClassSecurityInfo() manage_options = (({ 'label': 'Overview', 'action': 'manage_overview' }, ) + SimpleItem.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainDiscussionTool', _dtmldir) # # 'portal_discussion' interface methods # security.declarePublic('overrideDiscussionFor') def overrideDiscussionFor(self, content, allowDiscussion): """ Override discussability for the given object or clear the setting. """ if not _checkPermission(ModifyPortalContent, content): raise AccessControl_Unauthorized if allowDiscussion is None or allowDiscussion == 'None': disc_flag = getattr(aq_base(content), 'allow_discussion', _marker) if disc_flag is not _marker: try: del content.allow_discussion except AttributeError: # https://bugs.launchpad.net/zope-cmf/+bug/162532 pass else: content.allow_discussion = bool(allowDiscussion) security.declarePublic('getDiscussionFor') def getDiscussionFor(self, content): """ Get DiscussionItemContainer for content, create it if necessary. """ if not self.isDiscussionAllowedFor(content): raise DiscussionNotAllowed if not IDiscussionResponse.providedBy(content) and \ getattr( aq_base(content), 'talkback', None ) is None: # Discussion Items use the DiscussionItemContainer object of the # related content item, so only create one for other content items self._createDiscussionFor(content) return content.talkback # Return wrapped talkback security.declarePublic('isDiscussionAllowedFor') def isDiscussionAllowedFor(self, content): """ Get boolean indicating whether discussion is allowed for content. """ if hasattr(aq_base(content), 'allow_discussion'): return bool(content.allow_discussion) typeInfo = content.getTypeInfo() if typeInfo: return bool(typeInfo.allowDiscussion()) return False # # Utility methods # security.declarePrivate('_createDiscussionFor') def _createDiscussionFor(self, content): """ Create DiscussionItemContainer for content, if allowed. """ if not self.isDiscussionAllowedFor(content): raise DiscussionNotAllowed content.talkback = DiscussionItemContainer() return content.talkback
class ExternalMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit, AccessControl.Role.RoleManager, Navigation): """Web-callable functions that encapsulate external python functions. The function is defined in an external file. This file is treated like a module, but is not a module. It is not imported directly, but is rather read and evaluated. The file must reside in the 'Extensions' subdirectory of the Zope installation, or in an 'Extensions' subdirectory of a product directory. Due to the way ExternalMethods are loaded, it is not *currently* possible to use Python modules that reside in the 'Extensions' directory. It is possible to load modules found in the 'lib/python' directory of the Zope installation, or in packages that are in the 'lib/python' directory. """ meta_type = 'External Method' security = ClassSecurityInfo() security.declareObjectProtected(View) func_defaults = ComputedAttribute(lambda self: self.getFuncDefaults()) func_code = ComputedAttribute(lambda self: self.getFuncCode()) ZopeTime = Acquisition.Acquired HelpSys = Acquisition.Acquired manage_page_header = Acquisition.Acquired manage_options = (( { 'label': 'Properties', 'action': 'manage_main', 'help': ('ExternalMethod', 'External-Method_Properties.stx') }, { 'label': 'Test', 'action': '', 'help': ('ExternalMethod', 'External-Method_Try-It.stx') }, ) + OFS.SimpleItem.Item.manage_options + AccessControl.Role.RoleManager.manage_options) def __init__(self, id, title, module, function): self.id = id self.manage_edit(title, module, function) security.declareProtected(view_management_screens, 'manage_main') manage_main = DTMLFile('dtml/methodEdit', globals()) security.declareProtected(change_external_methods, 'manage_edit') def manage_edit(self, title, module, function, REQUEST=None): """Change the external method See the description of manage_addExternalMethod for a descriotion of the arguments 'module' and 'function'. Note that calling 'manage_edit' causes the "module" to be effectively reloaded. This is useful during debugging to see the effects of changes, but can lead to problems of functions rely on shared global data. """ title = str(title) module = str(module) function = str(function) self.title = title if module[-3:] == '.py': module = module[:-3] elif module[-4:] == '.pyc': module = module[:-4] self._module = module self._function = function self.getFunction(1) if REQUEST: message = "External Method Uploaded." return self.manage_main(self, REQUEST, manage_tabs_message=message) def getFunction(self, reload=0): f = getObject(self._module, self._function, reload) if hasattr(f, 'im_func'): ff = f.im_func else: ff = f self._v_func_defaults = ff.func_defaults self._v_func_code = FuncCode(ff, f is not ff) self._v_f = f return f def reloadIfChanged(self): # If the file has been modified since last loaded, force a reload. ts = os.stat(self.filepath())[stat.ST_MTIME] if (not hasattr(self, '_v_last_read') or (ts != self._v_last_read)): self._v_f = self.getFunction(1) self._v_last_read = ts if DevelopmentMode: # In development mode we do an automatic reload # if the module code changed def getFuncDefaults(self): self.reloadIfChanged() if not hasattr(self, '_v_func_defaults'): self._v_f = self.getFunction() return self._v_func_defaults def getFuncCode(self): self.reloadIfChanged() if not hasattr(self, '_v_func_code'): self._v_f = self.getFunction() return self._v_func_code else: def getFuncDefaults(self): if not hasattr(self, '_v_func_defaults'): self._v_f = self.getFunction() return self._v_func_defaults def getFuncCode(self): if not hasattr(self, '_v_func_code'): self._v_f = self.getFunction() return self._v_func_code security.declareProtected(View, '__call__') def __call__(self, *args, **kw): """Call an ExternalMethod Calling an External Method is roughly equivalent to calling the original actual function from Python. Positional and keyword parameters can be passed as usual. Note however that unlike the case of a normal Python method, the "self" argument must be passed explicitly. An exception to this rule is made if: - The supplied number of arguments is one less than the required number of arguments, and - The name of the function\'s first argument is 'self'. In this case, the URL parent of the object is supplied as the first argument. """ filePath = self.filepath() if filePath == None: raise RuntimeError,\ "external method could not be called " \ "because it is None" if not os.path.exists(filePath): raise RuntimeError,\ "external method could not be called " \ "because the file does not exist" if DevelopmentMode: self.reloadIfChanged() if hasattr(self, '_v_f'): f = self._v_f else: f = self.getFunction() __traceback_info__ = args, kw, self._v_func_defaults try: return f(*args, **kw) except TypeError, v: tb = sys.exc_info()[2] try: if ((self._v_func_code.co_argcount - len(self._v_func_defaults or ()) - 1 == len(args)) and self._v_func_code.co_varnames[0] == 'self'): return f(self.aq_parent.this(), *args, **kw) raise TypeError, v, tb finally: tb = None
class Document(PortalContent, DefaultDublinCoreImpl): """A Document - Handles both StructuredText and HTML. """ implements(IMutableDocument, IDocument, IDAVAware) __implements__ = (z2IMutableDocument, z2IDocument, PortalContent.__implements__, DefaultDublinCoreImpl.__implements__) meta_type = 'Document' effective_date = expiration_date = None cooked_text = text = text_format = '' _size = 0 _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 = _(u'Intervening changes from elsewhere detected. ' u'Please refetch the document and reapply your changes. ' u'(You may be able to recover your version using the ' u"browser 'back' button, but will have to apply them to " u'a freshly fetched copy.)') raise EditingConflict(msg) self.text = text self._size = len(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) # # IMutableDocument method # security.declareProtected(ModifyPortalContent, 'edit') def edit(self, text_format, text, file='', safety_belt=''): """ Update the document. 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) and text_format.lower() != 'plain': 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 # # IContentish method # 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()) # # IDocument methods # security.declareProtected(View, 'CookedBody') def CookedBody(self, stx_level=None, setlevel=0): """ Get the "cooked" (ready for presentation) form of the text. 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): """ Get the "raw" (as edited) form of the text. 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 # # IDublinCore method # 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' # # IMutableDublinCore method # security.declareProtected(ModifyPortalContent, 'setFormat') def setFormat(self, format): """ Set text format and Dublin Core resource format. """ value = str(format) old_value = self.text_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' # Did the format change? We might need to re-cook the content. if value != old_value: if html_headcheck(self.text) and value != 'plain': self.text = bodyfinder(self.text) self._edit(self.text, text_format=self.text_format, safety_belt=self._safety_belt) ## 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... transaction.abort() RESPONSE.setStatus(450) return RESPONSE except ResourceLockedError, msg: transaction.abort() RESPONSE.setStatus(423) return RESPONSE
from Products.ZenRelations.RelSchema import * from Products.ZenUtils.ZenTales import talesEval from ZenModelRM import ZenModelRM def manage_addRRDGraph(context, id, REQUEST=None): """make a RRDGraph""" graph = RRDGraph(id) context._setObject(graph.id, graph) if REQUEST is not None: REQUEST['RESPONSE'].redirect(context.absolute_url_path() + '/manage_main') addRRDGraph = DTMLFile('dtml/addRRDGraph', globals()) class RRDGraph(ZenModelRM): meta_type = 'RRDGraph' security = ClassSecurityInfo() dsnames = [] sequence = 0 height = 100 width = 500 threshmap = [] units = "" log = False
class Document(PortalContent, DefaultDublinCoreImpl): """ A Document - Handles both StructuredText and HTML """ __implements__ = (PortalContent.__implements__, DefaultDublinCoreImpl.__implements__) meta_type = 'Document' effective_date = expiration_date = None text_format = '' _isDiscussable = 1 _stx_level = 1 # Structured text level _last_safety_belt_editor = '' _last_safety_belt = '' _safety_belt = '' # Declarative security (replaces __ac_permissions__) security = ClassSecurityInfo() def __init__(self, id, title='', description='', text_format='', text=''): DefaultDublinCoreImpl.__init__(self) self.id = id self.title = title self.description = description self.text = text self.text_format = text_format self.edit(text_format=text_format, text=text) security.declareProtected(CMFCorePermissions.ModifyPortalContent, 'manage_edit') manage_edit = DTMLFile('zmi_editDocument', _dtmldir) security.declareProtected(CMFCorePermissions.ModifyPortalContent, 'manage_editDocument') def manage_editDocument(self, text_format, text, file='', REQUEST=None): """ A ZMI (Zope Management Interface) level editing method """ self._edit(text_format, text, file) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/manage_edit' + '?manage_tabs_message=Document+updated') def _edit(self, text_format, text, file='', safety_belt=''): """ Edit the Document - Parses headers and cooks the body""" self.text = text headers = {} if file and (type(file) is not type('')): contents = file.read() if contents: text = self.text = contents headers, body, cooked, format = self.handleText(text, text_format) if not safety_belt: safety_belt = headers.get('SafetyBelt', '') 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_format = format self.cooked_text = cooked self.text = body headers['Format'] = self.Format() new_subject = keywordsplitter(headers) headers['Subject'] = new_subject or self.Subject() haveheader = headers.has_key for key, value in self.getMetadataHeaders(): if key != 'Format' and 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.declareProtected(CMFCorePermissions.ModifyPortalContent, 'edit') edit = WorkflowAction(_edit) security.declarePrivate('guessFormat') def guessFormat(self, text): """ Simple stab at guessing the inner format of the text """ if utils.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, cooked, format """ headers = {} body = cooked = text level = stx_level or self._stx_level 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 bodyfound = bodyfinder(text) if bodyfound: cooked = body = bodyfound else: headers, body = parseHeadersBody(text, headers) cooked = _format_stx(text=body, level=level) self._stx_level = level return headers, body, cooked, 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().getUserName() 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(CMFCorePermissions.View, 'SearchableText') def SearchableText(self): """ Used by the catalog for basic full text indexing """ return "%s %s %s" % (self.title, self.description, self.text) security.declareProtected(CMFCorePermissions.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 (stx_level is None) or (stx_level == self._stx_level)): return self.cooked_text else: cooked = _format_stx(self.text, stx_level) if setlevel: self._stx_level = stx_level self.cooked_text = cooked return cooked security.declareProtected(CMFCorePermissions.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(CMFCorePermissions.View, 'Description') def Description(self): """ Dublin core description, also important for indexing """ return self.description security.declareProtected(CMFCorePermissions.View, 'Format') def Format(self): """ Returns a content-type style format of the underlying source """ if self.text_format == 'html': return 'text/html' else: return 'text/plain' security.declareProtected(CMFCorePermissions.ModifyPortalContent, 'setFormat') def setFormat(self, value): value = str(value) if value == 'text/html': self.text_format = 'html' else: self.text_format = 'structured-text' setFormat = WorkflowAction(setFormat) ## FTP handlers security.declareProtected(CMFCorePermissions.ModifyPortalContent, 'PUT') def PUT(self, REQUEST, RESPONSE): """ Handle HTTP (and presumably FTP?) PUT requests """ self.dav__init(REQUEST, RESPONSE) body = REQUEST.get('BODY', '') guessedformat = REQUEST.get_header('Content-Type', 'text/plain') ishtml = (guessedformat == 'text/html') or utils.html_headcheck(body) if ishtml: self.setFormat('text/html') else: self.setFormat('text/plain') try: self.edit(text_format=self.text_format, text=body) 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 RESPONSE.setStatus(204) return RESPONSE
def manage_addIpNetwork(context, id, netmask=24, REQUEST = None, version=4): """make a IpNetwork""" net = IpNetwork(id, netmask=netmask, version=version) context._setObject(net.id, net) if id.endswith("Networks"): net = context._getOb(net.id) net.dmdRootName = id net.buildZProperties() net.createCatalog() net.initialize_network_cache(net) #manage_addZDeviceDiscoverer(context) if REQUEST is not None: REQUEST['RESPONSE'].redirect(context.absolute_url_path()+'/manage_main') addIpNetwork = DTMLFile('dtml/addIpNetwork',globals()) # When an IP is added the default location will be # into class A->B->C network tree defaultNetworkTree = (32,) class IpNetwork(DeviceOrganizer, IpNetworkIndexable): """IpNetwork object""" implements(IObjectEventsSubscriber) isInTree = True buildLinks = True
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 MajorMinorPredicate(SimpleItem): """ Predicate matching on 'major/minor' content types. Empty major or minor implies wildcard (all match). """ major = minor = None PREDICATE_TYPE = 'major_minor' security = ClassSecurityInfo() def __init__(self, id): self.id = id security.declareProtected(ManagePortal, 'getMajorType') def getMajorType(self, join=string.join): """ """ if self.major is None: return 'None' return join(self.major) security.declareProtected(ManagePortal, 'getMinorType') def getMinorType(self, join=string.join): """ """ if self.minor is None: return 'None' return join(self.minor) security.declareProtected(ManagePortal, 'edit') def edit(self, major, minor, COMMA_SPLIT=re.compile(r'[, ]')): if major == 'None': major = None if type(major) is type(''): major = filter(None, COMMA_SPLIT.split(major)) if minor == 'None': minor = None if type(minor) is type(''): minor = filter(None, COMMA_SPLIT.split(minor)) self.major = major self.minor = minor # # ContentTypeRegistryPredicate interface # security.declareObjectPublic() def __call__(self, name, typ, body, SLASH_SPLIT=re.compile('/')): """ Return true if the rule matches, else false. """ if self.major is None: return 0 if self.minor is None: return 0 typ = typ or '/' if not '/' in typ: typ = typ + '/' major, minor = SLASH_SPLIT.split(typ) if self.major and not major in self.major: return 0 if self.minor and not minor in self.minor: return 0 return 1 security.declareProtected(ManagePortal, 'getTypeLabel') def getTypeLabel(self): """ Return a human-readable label for the predicate type. """ return self.PREDICATE_TYPE security.declareProtected(ManagePortal, 'predicateWidget') predicateWidget = DTMLFile('majorMinorWidget', _dtmldir)
class UndoTool(UniqueObject, SimpleItem, ActionProviderBase): """ This tool is used to undo changes. """ implements(IUndoTool) __implements__ = (z2IUndoTool, ActionProviderBase.__implements__) id = 'portal_undo' meta_type = 'CMF Undo Tool' security = ClassSecurityInfo() manage_options = (ActionProviderBase.manage_options + SimpleItem.manage_options + ({ 'label': 'Overview', 'action': 'manage_overview' }, )) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainUndoTool', _dtmldir) # # 'portal_undo' interface methods # security.declareProtected(ListUndoableChanges, 'listUndoableTransactionsFor') def listUndoableTransactionsFor(self, object, first_transaction=None, last_transaction=None, PrincipiaUndoBatchSize=None): '''Lists all transaction IDs the user is allowed to undo. ''' # arg list for undoable_transactions() changed in Zope 2.2. portal = queryUtility(ISiteRoot) if site is None: # fallback portal = self.aq_inner.aq_parent transactions = portal.undoable_transactions( first_transaction=first_transaction, last_transaction=last_transaction, PrincipiaUndoBatchSize=PrincipiaUndoBatchSize) for t in transactions: # Ensure transaction ids don't have embedded LF. t['id'] = t['id'].replace('\n', '') if not _checkPermission(ManagePortal, portal): # Filter out transactions done by other members of the portal. user_id = _getAuthenticatedUser(self).getId() transactions = filter(lambda record, user_id=user_id: record[ 'user_name'].split()[-1] == user_id, transactions) return transactions security.declarePublic('undo') def undo(self, object, transaction_info): """ Undo the list of transactions passed in 'transaction_info', first verifying that the current user is allowed to undo them. """ # Belt and suspenders: make sure that the user is actually # allowed to undo the transation(s) in transaction_info. xids = {} # set of allowed transaction IDs allowed = self.listUndoableTransactionsFor(object) for xid in map(lambda x: x['id'], allowed): xids[xid] = 1 if type(transaction_info) == type(''): transaction_info = [transaction_info] for tinfo in transaction_info: if not xids.get(tinfo, None): raise AccessControl_Unauthorized object.manage_undo_transactions(transaction_info)
class ContentTypeRegistry(SimpleItem): """ Registry for rules which map PUT args to a CMF Type Object. """ meta_type = 'Content Type Registry' id = 'content_type_registry' manage_options = ({ 'label': 'Predicates', 'action': 'manage_predicates' }, { 'label': 'Test', 'action': 'manage_testRegistry' }) + SimpleItem.manage_options security = ClassSecurityInfo() def __init__(self): self.predicate_ids = () self.predicates = PersistentMapping() # # ZMI # security.declarePublic('listPredicateTypes') def listPredicateTypes(self): """ """ return map(lambda x: x[0], _predicate_types) security.declareProtected(ManagePortal, 'manage_predicates') manage_predicates = DTMLFile('registryPredList', _dtmldir) security.declareProtected(ManagePortal, 'doAddPredicate') def doAddPredicate(self, predicate_id, predicate_type, REQUEST): """ """ self.addPredicate(predicate_id, predicate_type) REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_predicates' + '?manage_tabs_message=Predicate+added.') security.declareProtected(ManagePortal, 'doUpdatePredicate') def doUpdatePredicate(self, predicate_id, predicate, typeObjectName, REQUEST): """ """ self.updatePredicate(predicate_id, predicate, typeObjectName) REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_predicates' + '?manage_tabs_message=Predicate+updated.') security.declareProtected(ManagePortal, 'doMovePredicateUp') def doMovePredicateUp(self, predicate_id, REQUEST): """ """ predicate_ids = list(self.predicate_ids) ndx = predicate_ids.index(predicate_id) if ndx == 0: msg = "Predicate+already+first." else: self.reorderPredicate(predicate_id, ndx - 1) msg = "Predicate+moved." REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_predicates' + '?manage_tabs_message=%s' % msg) security.declareProtected(ManagePortal, 'doMovePredicateDown') def doMovePredicateDown(self, predicate_id, REQUEST): """ """ predicate_ids = list(self.predicate_ids) ndx = predicate_ids.index(predicate_id) if ndx == len(predicate_ids) - 1: msg = "Predicate+already+last." else: self.reorderPredicate(predicate_id, ndx + 1) msg = "Predicate+moved." REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_predicates' + '?manage_tabs_message=%s' % msg) security.declareProtected(ManagePortal, 'doRemovePredicate') def doRemovePredicate(self, predicate_id, REQUEST): """ """ self.removePredicate(predicate_id) REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_predicates' + '?manage_tabs_message=Predicate+removed.') security.declareProtected(ManagePortal, 'manage_testRegistry') manage_testRegistry = DTMLFile('registryTest', _dtmldir) security.declareProtected(ManagePortal, 'doTestRegistry') def doTestRegistry(self, name, content_type, body, REQUEST): """ """ typeName = self.findTypeName(name, content_type, body) if typeName is None: typeName = '<unknown>' REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_testRegistry' + '?testResults=Type:%s' % urllib.quote(typeName)) # # Predicate manipulation # security.declarePublic('getPredicate') def getPredicate(self, predicate_id): """ Find the predicate whose id is 'id'; return the predicate object, if found, or else None. """ return self.predicates.get(predicate_id, (None, None))[0] security.declarePublic('listPredicates') def listPredicates(self): """ Return a sequence of tuples, '( id, ( predicate, typeObjectName ) )' for all predicates in the registry """ result = [] for predicate_id in self.predicate_ids: result.append((predicate_id, self.predicates[predicate_id])) return tuple(result) security.declarePublic('getTypeObjectName') def getTypeObjectName(self, predicate_id): """ Find the predicate whose id is 'id'; return the name of the type object, if found, or else None. """ return self.predicates.get(predicate_id, (None, None))[1] security.declareProtected(ManagePortal, 'addPredicate') def addPredicate(self, predicate_id, predicate_type): """ Add a predicate to this element of type 'typ' to the registry. """ if predicate_id in self.predicate_ids: raise ValueError, "Existing predicate: %s" % predicate_id klass = None for key, value in _predicate_types: if key == predicate_type: klass = value if klass is None: raise ValueError, "Unknown predicate type: %s" % predicate_type self.predicates[predicate_id] = (klass(predicate_id), None) self.predicate_ids = self.predicate_ids + (predicate_id, ) security.declareProtected(ManagePortal, 'addPredicate') def updatePredicate(self, predicate_id, predicate, typeObjectName): """ Update a predicate in this element. """ if not predicate_id in self.predicate_ids: raise ValueError, "Unknown predicate: %s" % predicate_id predObj = self.predicates[predicate_id][0] mapply(predObj.edit, (), predicate.__dict__) self.assignTypeName(predicate_id, typeObjectName) security.declareProtected(ManagePortal, 'removePredicate') def removePredicate(self, predicate_id): """ Remove a predicate from the registry. """ del self.predicates[predicate_id] idlist = list(self.predicate_ids) ndx = idlist.index(predicate_id) idlist = idlist[:ndx] + idlist[ndx + 1:] self.predicate_ids = tuple(idlist) security.declareProtected(ManagePortal, 'reorderPredicate') def reorderPredicate(self, predicate_id, newIndex): """ Move a given predicate to a new location in the list. """ idlist = list(self.predicate_ids) ndx = idlist.index(predicate_id) pred = idlist[ndx] idlist = idlist[:ndx] + idlist[ndx + 1:] idlist.insert(newIndex, pred) self.predicate_ids = tuple(idlist) security.declareProtected(ManagePortal, 'assignTypeName') def assignTypeName(self, predicate_id, typeObjectName): """ Bind the given predicate to a particular type object. """ pred, oldTypeObjName = self.predicates[predicate_id] self.predicates[predicate_id] = (pred, typeObjectName) # # ContentTypeRegistry interface # def findTypeName(self, name, typ, body): """ Perform a lookup over a collection of rules, returning the the name of the Type object corresponding to name/typ/body. Return None if no match found. """ for predicate_id in self.predicate_ids: pred, typeObjectName = self.predicates[predicate_id] if pred(name, typ, body): return typeObjectName return None
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 PythonScript(Script, Historical, Cacheable): """Web-callable scripts written in a safe subset of Python. The function may include standard python code, so long as it does not attempt to use the "exec" statement or certain restricted builtins. """ __implements__ = (WriteLockInterface, ) meta_type = 'Script (Python)' _proxy_roles = () _params = _body = '' errors = warnings = () _v_change = 0 manage_options = ( {'label':'Edit', 'action':'ZPythonScriptHTML_editForm', 'help': ('PythonScripts', 'PythonScript_edit.stx')}, ) + BindingsUI.manage_options + ( {'label':'Test', 'action':'ZScriptHTML_tryForm', 'help': ('PythonScripts', 'PythonScript_test.stx')}, {'label':'Proxy', 'action':'manage_proxyForm', 'help': ('OFSP','DTML-DocumentOrMethod_Proxy.stx')}, ) + Historical.manage_options + SimpleItem.manage_options + \ Cacheable.manage_options def __init__(self, id): self.id = id self.ZBindings_edit(defaultBindings) self._makeFunction() security = AccessControl.ClassSecurityInfo() security.declareObjectProtected('View') security.declareProtected('View', '__call__') security.declareProtected('View management screens', 'ZPythonScriptHTML_editForm', 'manage_main', 'read', 'ZScriptHTML_tryForm', 'PrincipiaSearchSource', 'document_src', 'params', 'body', 'get_filepath') ZPythonScriptHTML_editForm = DTMLFile('www/pyScriptEdit', globals()) manage = manage_main = ZPythonScriptHTML_editForm ZPythonScriptHTML_editForm._setName('ZPythonScriptHTML_editForm') security.declareProtected('Change Python Scripts', 'ZPythonScriptHTML_editAction', 'ZPythonScript_setTitle', 'ZPythonScript_edit', 'ZPythonScriptHTML_upload', 'ZPythonScriptHTML_changePrefs') def ZPythonScriptHTML_editAction(self, REQUEST, title, params, body): """Change the script's main parameters.""" self.ZPythonScript_setTitle(title) self.ZPythonScript_edit(params, body) message = "Saved changes." return self.ZPythonScriptHTML_editForm(self, REQUEST, manage_tabs_message=message) def ZPythonScript_setTitle(self, title): title = str(title) if self.title != title: self.title = title self.ZCacheable_invalidate() def ZPythonScript_edit(self, params, body): self._validateProxy() if self.wl_isLocked(): raise ResourceLockedError, "The script is locked via WebDAV." if type(body) is not type(''): body = body.read() if self._params <> params or self._body <> body or self._v_change: self._params = str(params) self.write(body) def ZPythonScriptHTML_upload(self, REQUEST, file=''): """Replace the body of the script with the text in file.""" if self.wl_isLocked(): raise ResourceLockedError, "The script is locked via WebDAV." if type(file) is not type(''): if not file: raise ValueError, 'File not specified' file = file.read() self.write(file) message = 'Saved changes.' return self.ZPythonScriptHTML_editForm(self, REQUEST, manage_tabs_message=message) def ZPythonScriptHTML_changePrefs(self, REQUEST, height=None, width=None, dtpref_cols="100%", dtpref_rows="20"): """Change editing preferences.""" dr = {"Taller": 5, "Shorter": -5}.get(height, 0) dc = {"Wider": 5, "Narrower": -5}.get(width, 0) if isinstance(height, int): dtpref_rows = height if isinstance(width, int) or \ isinstance(width, str) and width.endswith('%'): dtpref_cols = width rows = str(max(1, int(dtpref_rows) + dr)) cols = str(dtpref_cols) if cols.endswith('%'): cols = str(min(100, max(25, int(cols[:-1]) + dc))) + '%' else: cols = str(max(35, int(cols) + dc)) e = (DateTime("GMT") + 365).rfc822() setCookie = REQUEST["RESPONSE"].setCookie setCookie("dtpref_rows", rows, path='/', expires=e) setCookie("dtpref_cols", cols, path='/', expires=e) REQUEST.other.update({"dtpref_cols": cols, "dtpref_rows": rows}) return self.manage_main(self, REQUEST) 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] != '*' and re.match('\w', name): param_names.append(name.split('=', 1)[0].strip()) return param_names def manage_historyCompare(self, rev1, rev2, REQUEST, historyComparisonResults=''): return PythonScript.inheritedAttribute('manage_historyCompare')( self, rev1, rev2, REQUEST, historyComparisonResults=html_diff(rev1.read(), rev2.read())) def __setstate__(self, state): Script.__setstate__(self, state) if (getattr(self, 'Python_magic', None) != Python_magic or getattr(self, 'Script_magic', None) != Script_magic): global _log_complaint if _log_complaint: LOG.info(_log_complaint) _log_complaint = 0 # Changes here won't get saved, unless this Script is edited. body = self._body.rstrip() if body: self._body = body + '\n' self._compile() self._v_change = 1 elif self._code is None: self._v_ft = self._v_f = None else: self._newfun(marshal.loads(self._code)) def _compiler(self, *args, **kw): return RestrictedPython.compile_restricted_function(*args, **kw) def _compile(self): bind_names = self.getBindingAssignments().getAssignedNamesInOrder() r = self._compiler(self._params, self._body or 'pass', self.id, self.meta_type, globalize=bind_names) code = r[0] errors = r[1] self.warnings = tuple(r[2]) if errors: self._code = None self._v_ft = self._v_f = None self._setFuncSignature((), (), 0) # Fix up syntax errors. filestring = ' File "<string>",' for i in range(len(errors)): line = errors[i] if line.startswith(filestring): errors[i] = line.replace(filestring, ' Script', 1) self.errors = errors return self._code = marshal.dumps(code) self.errors = () f = self._newfun(code) fc = f.func_code self._setFuncSignature(f.func_defaults, fc.co_varnames, fc.co_argcount) self.Python_magic = Python_magic self.Script_magic = Script_magic self._v_change = 0 def _newfun(self, code): g = get_safe_globals() g['_getattr_'] = guarded_getattr g['__debug__'] = __debug__ g['__name__'] = None l = {} exec code in g, l self._v_f = f = l.values()[0] self._v_ft = (f.func_code, g, f.func_defaults or ()) return f def _makeFunction(self, dummy=0): # CMFCore.FSPythonScript uses dummy arg. self.ZCacheable_invalidate() self._compile() if not (aq_parent(self) is None or hasattr(self, '_filepath')): # It needs a _filepath, and has an acquisition wrapper. self._filepath = self.get_filepath() def _editedBindings(self): if getattr(self, '_v_ft', None) is not None: self._makeFunction() def _exec(self, bound_names, args, kw): """Call a Python Script Calling a Python Script is an actual function invocation. """ # Retrieve the value from the cache. 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] = aq_parent(self).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 #__traceback_info__ = bound_names, args, kw, self.func_defaults ft = self._v_ft if ft is None: __traceback_supplement__ = (PythonScriptTracebackSupplement, self) raise RuntimeError, '%s %s has errors.' % (self.meta_type, self.id) fcode, g, fadefs = ft g = g.copy() if bound_names is not None: g.update(bound_names) g['__traceback_supplement__'] = (PythonScriptTracebackSupplement, self, -1) g['__file__'] = getattr(self, '_filepath', None) or self.get_filepath() f = new.function(fcode, g, None, fadefs) result = f(*args, **kw) if keyset is not None: # Store the result in the cache. self.ZCacheable_set(result, keywords=keyset) return result def manage_afterAdd(self, item, container): if item is self: self._filepath = self.get_filepath() def manage_beforeDelete(self, item, container): # shut up deprecation warnings pass def manage_afterClone(self, item): # shut up deprecation warnings pass def get_filepath(self): return self.meta_type + ':' + '/'.join(self.getPhysicalPath()) def manage_haveProxy(self, r): return r in self._proxy_roles def _validateProxy(self, roles=None): if roles is None: roles = self._proxy_roles if not roles: return user = getSecurityManager().getUser() if user is not None and user.allowed(self, roles): return raise Forbidden, ( 'You are not authorized to change <em>%s</em> ' 'because you do not have proxy roles.\n<!--%s, %s-->' % (self.id, user, roles)) security.declareProtected('Change proxy roles', 'manage_proxyForm', 'manage_proxy') manage_proxyForm = DTMLFile('www/pyScriptProxy', globals()) @postonly def manage_proxy(self, roles=(), REQUEST=None): "Change Proxy Roles" self._validateProxy(roles) self._validateProxy() self.ZCacheable_invalidate() self._proxy_roles = tuple(roles) if REQUEST: return MessageDialog(title='Success!', message='Your changes have been saved', action='manage_main') security.declareProtected('Change Python Scripts', 'PUT', 'manage_FTPput', 'write', 'manage_historyCopy', 'manage_beforeHistoryCopy', 'manage_afterHistoryCopy') def PUT(self, REQUEST, RESPONSE): """ Handle HTTP PUT requests """ self.dav__init(REQUEST, RESPONSE) self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1) self.write(REQUEST.get('BODY', '')) RESPONSE.setStatus(204) return RESPONSE manage_FTPput = PUT def write(self, text): """ Change the Script by parsing a read()-style source text. """ self._validateProxy() mdata = self._metadata_map() bindmap = self.getBindingAssignments().getAssignedNames() bup = 0 st = 0 try: while 1: # Find the next non-empty line m = _nonempty_line.search(text, st) if not m: # There were no non-empty body lines body = '' break line = m.group(0).strip() if line[:2] != '##': # We have found the first line of the body body = text[m.start(0):] break st = m.end(0) # Parse this header line if len(line) == 2 or line[2] == ' ' or '=' not in line: # Null header line continue k, v = line[2:].split('=', 1) k = k.strip().lower() v = v.strip() if not mdata.has_key(k): raise SyntaxError, 'Unrecognized header line "%s"' % line if v == mdata[k]: # Unchanged value continue # Set metadata value if k == 'title': self.title = v elif k == 'parameters': self._params = v elif k[:5] == 'bind ': bindmap[_nice_bind_names[k[5:]]] = v bup = 1 body = body.rstrip() if body: body = body + '\n' if body != self._body: self._body = body if bup: self.ZBindings_edit(bindmap) else: self._makeFunction() except: LOG.error('write failed', exc_info=sys.exc_info()) raise def manage_FTPget(self): "Get source for FTP download" self.REQUEST.RESPONSE.setHeader('Content-Type', 'text/plain') return self.read() def _metadata_map(self): m = { 'title': self.title, 'parameters': self._params, } bindmap = self.getBindingAssignments().getAssignedNames() for k, v in _nice_bind_names.items(): m['bind ' + k] = bindmap.get(v, '') return m def read(self): """ Generate a text representation of the Script source. Includes specially formatted comment lines for parameters, bindings, and the title. """ # Construct metadata header lines, indented the same as the body. m = _first_indent.search(self._body) if m: prefix = m.group(0) + '##' else: prefix = '##' hlines = ['%s %s "%s"' % (prefix, self.meta_type, self.id)] mm = self._metadata_map().items() mm.sort() for kv in mm: hlines.append('%s=%s' % kv) if self.errors: hlines.append('') hlines.append(' Errors:') for line in self.errors: hlines.append(' ' + line) if self.warnings: hlines.append('') hlines.append(' Warnings:') for line in self.warnings: hlines.append(' ' + line) hlines.append('') return ('\n' + prefix).join(hlines) + '\n' + self._body def params(self): return self._params def body(self): return self._body def get_size(self): return len(self.read()) getSize = get_size def PrincipiaSearchSource(self): "Support for searching - the document's contents are searched." return "%s\n%s" % (self._params, self._body) 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.read()