class MetadataSchema(SimpleItem): """ Describe a metadata schema. """ security = ClassSecurityInfo() meta_type = 'Metadata Schema' publisher = '' def __init__(self, id, element_specs=()): self._setId(id) self.element_specs = PersistentMapping() for name, is_multi_valued in element_specs: self.element_specs[name] = ElementSpec(is_multi_valued) # # ZMI methods # manage_options = (({ 'label': 'Elements', 'action': 'elementPoliciesForm' }, ) + SimpleItem.manage_options) security.declareProtected(ManagePortal, 'elementPoliciesForm') elementPoliciesForm = DTMLFile('metadataElementPolicies', WWW_DIR) @security.protected(ManagePortal) 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.protected(ManagePortal) def removeElementPolicy(self, element, content_type, REQUEST=None): # Remove 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.protected(ManagePortal) 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.protected(ManagePortal) def listElementSpecs(self): # Return a list of ElementSpecs representing the elements we manage. res = [] for k, v in self.element_specs.items(): res.append((k, v.__of__(self))) return res @security.protected(ManagePortal) def getElementSpec(self, element): # Return an ElementSpec for the given 'element'. return self.element_specs[element].__of__(self) @security.protected(ManagePortal) def addElementSpec(self, element, is_multi_valued, REQUEST=None): # Add 'element' to our list of managed elements. # Don't replace. if element in self.element_specs: 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.protected(ManagePortal) 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.protected(ManagePortal) def listPolicies(self, typ=None): # Show all policies for a given content type. # If 'typ' is none, return the list of default policies. result = [] for element, spec in self.listElementSpecs(): result.append((element, spec.getPolicy(typ))) return result
class ContentTypeRegistry( SimpleItem ): """ Registry for rules which map PUT args to a CMF Type Object. """ implements(IContentTypeRegistry) 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 ): """ """ # XXX: this method violates the rules for tools/utilities: # it depends on a non-utility tool typeName = self.findTypeName( name, content_type, body ) if typeName is None: typeName = '<unknown>' else: types_tool = getToolByName(self, 'portal_types') typeName = types_tool.getTypeInfo(typeName).Title() 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 ): """List '(id, (predicate, typeObjectName))' tuples for all predicates. """ return tuple([ (id, self.predicates[id]) for id in self.predicate_ids ]) 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, 'updatePredicate' ) 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 ImportConfiguratorBase(Implicit): # old code, will become deprecated """ Synthesize data from XML description. """ security = ClassSecurityInfo() security.setDefaultAccess('allow') def __init__(self, site, encoding='utf-8'): self._site = site self._encoding = encoding security.declareProtected(ManagePortal, 'parseXML') def parseXML(self, xml): """ Pseudo API. """ reader = getattr(xml, 'read', None) if reader is not None: xml = reader() dom = parseString(xml) root = dom.documentElement return self._extractNode(root) def _extractNode(self, node): """ Please see docs/configurator.txt for information about the import mapping syntax. """ nodes_map = self._getImportMapping() if node.nodeName not in nodes_map: nodes_map = self._getSharedImportMapping() if node.nodeName not in nodes_map: raise ValueError('Unknown node: %s' % node.nodeName) node_map = nodes_map[node.nodeName] info = {} for name, val in node.attributes.items(): key = node_map[name].get(KEY, str(name)) val = self._encoding and val.encode(self._encoding) or val info[key] = val for child in node.childNodes: name = child.nodeName if name == '#comment': continue if not name == '#text': key = node_map[name].get(KEY, str(name)) info[key] = info.setdefault(key, ()) + (self._extractNode(child), ) elif '#text' in node_map: key = node_map['#text'].get(KEY, 'value') val = child.nodeValue.lstrip() val = self._encoding and val.encode(self._encoding) or val info[key] = info.setdefault(key, '') + val for k, v in node_map.items(): key = v.get(KEY, k) if DEFAULT in v and not key in info: if isinstance(v[DEFAULT], six.string_types): info[key] = v[DEFAULT] % info else: info[key] = v[DEFAULT] elif CONVERTER in v and key in info: info[key] = v[CONVERTER](info[key]) if key is None: info = info[key] return info def _getSharedImportMapping(self): return { 'object': { 'i18n:domain': {}, 'name': { KEY: 'id' }, 'meta_type': {}, 'insert-before': {}, 'insert-after': {}, 'property': { KEY: 'properties', DEFAULT: () }, 'object': { KEY: 'objects', DEFAULT: () }, 'xmlns:i18n': {} }, 'property': { 'name': { KEY: 'id' }, '#text': { KEY: 'value', DEFAULT: '' }, 'element': { KEY: 'elements', DEFAULT: () }, 'type': {}, 'select_variable': {}, 'i18n:translate': {} }, 'element': { 'value': { KEY: None } }, 'description': { '#text': { KEY: None, DEFAULT: '' } } } def _convertToBoolean(self, val): return val.lower() in ('true', 'yes', '1') def _convertToUnique(self, val): assert len(val) == 1 return val[0]
class TarballExportContext(BaseContext): security = ClassSecurityInfo() def __init__(self, tool, encoding=None): BaseContext.__init__(self, tool, encoding) timestamp = time.gmtime() archive_name = ('setup_tool-%4d%02d%02d%02d%02d%02d.tar.gz' % timestamp[:6]) self._archive_stream = cStringIO() self._archive_filename = archive_name self._archive = TarFile.open(archive_name, 'w:gz', self._archive_stream) security.declareProtected(ManagePortal, 'writeDataFile') def writeDataFile(self, filename, text, content_type, subdir=None): """ See IExportContext. """ if subdir is not None: filename = '/'.join((subdir, filename)) parents = filename.split('/')[:-1] while parents: path = '/'.join(parents) + '/' if path not in self._archive.getnames(): info = TarInfo(path) info.type = DIRTYPE # tarfile.filemode(0o755) == '-rwxr-xr-x' info.mode = 0o755 info.mtime = time.time() self._archive.addfile(info) parents.pop() info = TarInfo(filename) if isinstance(text, str): stream = cStringIO(text) info.size = len(text) elif isinstance(text, unicode): raise ValueError("Unicode text is not supported, even if it only " "contains ascii. Please encode your data. See " "GS 1.7.0 changes for more") else: # Assume text is a an instance of a class like # Products.Archetypes.WebDAVSupport.PdataStreamIterator, # as in the case of ATFile stream = text.file info.size = text.size info.mtime = time.time() self._archive.addfile(info, stream) security.declareProtected(ManagePortal, 'getArchive') def getArchive(self): """ Close the archive, and return it as a big string. """ self._archive.close() return self._archive_stream.getvalue() security.declareProtected(ManagePortal, 'getArchiveFilename') def getArchiveFilename(self): """ Close the archive, and return it as a big string. """ return self._archive_filename
class DirectoryImportContext(BaseContext): security = ClassSecurityInfo() def __init__(self, tool, profile_path, should_purge=False, encoding=None): BaseContext.__init__(self, tool, encoding) self._profile_path = profile_path self._should_purge = bool(should_purge) security.declareProtected(ManagePortal, 'openDataFile') def openDataFile(self, filename, subdir=None): """ See IImportContext. """ if subdir is None: full_path = os.path.join(self._profile_path, filename) else: full_path = os.path.join(self._profile_path, subdir, filename) if not os.path.exists(full_path): return None return open(full_path, 'rb') security.declareProtected(ManagePortal, 'readDataFile') def readDataFile(self, filename, subdir=None): """ See IImportContext. """ result = None file = self.openDataFile(filename, subdir) if file is not None: result = file.read() file.close() return result security.declareProtected(ManagePortal, 'getLastModified') def getLastModified(self, path): """ See IImportContext. """ full_path = os.path.join(self._profile_path, path) if not os.path.exists(full_path): return None return DateTime(os.path.getmtime(full_path)) security.declareProtected(ManagePortal, 'isDirectory') def isDirectory(self, path): """ See IImportContext. """ full_path = os.path.join(self._profile_path, path) if not os.path.exists(full_path): return None return os.path.isdir(full_path) security.declareProtected(ManagePortal, 'listDirectory') def listDirectory(self, path, skip=SKIPPED_FILES, skip_suffixes=SKIPPED_SUFFIXES): """ See IImportContext. """ if path is None: path = '' full_path = os.path.join(self._profile_path, path) if not os.path.exists(full_path) or not os.path.isdir(full_path): return None names = [] for name in os.listdir(full_path): if name in skip: continue if [s for s in skip_suffixes if name.endswith(s)]: continue names.append(name) return names
from chameleon.tales import StringExpr from chameleon.tales import NotExpr from chameleon.tal import RepeatDict from z3c.pt.expressions import PythonExpr from .expressions import PathExpr from .expressions import TrustedPathExpr from .expressions import ProviderExpr from .expressions import NocallExpr from .expressions import ExistsExpr from .expressions import UntrustedPythonExpr # Declare Chameleon's repeat dictionary public RepeatDict.security = ClassSecurityInfo() RepeatDict.security.declareObjectPublic() RepeatDict.__allow_access_to_unprotected_subobjects__ = True InitializeClass(RepeatDict) class Program(object): implements(IPageTemplateProgram) classProvides(IPageTemplateEngine) # Zope 2 Page Template expressions secure_expression_types = { 'python': UntrustedPythonExpr, 'string': StringExpr, 'not': NotExpr,
class MembershipTool(BaseTool): """ Implement 'portal_membership' interface using "stock" policies. """ implements(IMembershipTool) meta_type = 'Default Membership Tool' membersfolder_id = 'Members' security = ClassSecurityInfo() # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainMembershipTool', _dtmldir) security.declareProtected(ManagePortal, 'manage_mapRoles') manage_mapRoles = DTMLFile('membershipRolemapping', _dtmldir) security.declareProtected(ManagePortal, 'manage_setMembersFolderById') def manage_setMembersFolderById(self, id='', REQUEST=None): """ ZMI method to set the members folder object by its id. """ self.setMembersFolderById(id) if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/manage_mapRoles' + '?manage_tabs_message=Members+folder+changed.') # # 'portal_membership' interface methods # security.declareProtected(ListPortalMembers, 'getRoster') def getRoster(self): """ Return a list of mappings for 'listed' members. If Manager, return a list of all usernames. The mapping contains the id and listed variables. """ isUserManager = _checkPermission(ManageUsers, self) roster = [] for member in self.listMembers(): if isUserManager or member.listed: roster.append({'id': member.getId(), 'listed': member.listed}) return roster security.declareProtected(ManagePortal, 'setMembersFolderById') def setMembersFolderById(self, id=''): """ Set the members folder object by its id. """ self.membersfolder_id = id.strip() security.declarePublic('getMembersFolder') def getMembersFolder(self): """ Get the members folder object. """ parent = aq_parent(aq_inner(self)) try: members_folder = parent.restrictedTraverse(self.membersfolder_id) except (AttributeError, KeyError): members_folder = None return members_folder security.declarePublic('createMemberArea') def createMemberArea(self, member_id=''): """ Create a member area for 'member_id' or authenticated user. """ if not self.getMemberareaCreationFlag(): return None members = self.getMembersFolder() if members is None: return None if self.isAnonymousUser(): return None # Note: We can't use getAuthenticatedMember() and getMemberById() # because they might be wrapped by MemberDataTool. user = _getAuthenticatedUser(self) user_id = user.getId() if member_id in ('', user_id): member = user member_id = user_id else: if _checkPermission(ManageUsers, self): member = self.acl_users.getUserById(member_id, None) if member: member = member.__of__(self.acl_users) else: raise ValueError, 'Member %s does not exist' % member_id else: return None if hasattr(aq_base(members), member_id): return None # Note: We can't use invokeFactory() to add folder and content because # the user might not have the necessary permissions. # Create Member's home folder. members.manage_addPortalFolder(id=member_id, title="%s's Home" % member_id) f = members._getOb(member_id) # Grant Ownership and Owner role to Member f.changeOwnership(member) f.__ac_local_roles__ = None f.manage_setLocalRoles(member_id, ['Owner']) # Create Member's initial content. if hasattr(self, 'createMemberContent'): self.createMemberContent(member=member, member_id=member_id, member_folder=f) else: addDocument(f, 'index_html', member_id + "'s Home", member_id + "'s front page", "structured-text", (DEFAULT_MEMBER_CONTENT % member_id)) # Grant Ownership and Owner role to Member f.index_html.changeOwnership(member) f.index_html.__ac_local_roles__ = None f.index_html.manage_setLocalRoles(member_id, ['Owner']) f.index_html._setPortalTypeName('Document') f.index_html.reindexObject() f.index_html.notifyWorkflowCreated() return f security.declarePublic('createMemberarea') createMemberarea = createMemberArea def getHomeFolder(self, id=None, verifyPermission=0): """ Return a member's home folder object, or None. """ if id is None: member = self.getAuthenticatedMember() if not hasattr(member, 'getMemberId'): return None id = member.getMemberId() members = self.getMembersFolder() if members: try: folder = members._getOb(id) if verifyPermission and not _checkPermission(View, folder): # Don't return the folder if the user can't get to it. return None return folder except (AttributeError, TypeError, KeyError): pass return None def getHomeUrl(self, id=None, verifyPermission=0): """ Return the URL to a member's home folder, or None. """ home = self.getHomeFolder(id, verifyPermission) if home is not None: return home.absolute_url() else: return None
class MetadataElementPolicy(SimpleItem): """ Represent a type-specific policy about a particular metadata element. """ security = ClassSecurityInfo() # # Default values. # is_required = 0 supply_default = 0 default_value = '' enforce_vocabulary = 0 allowed_vocabulary = () def __init__(self, is_multi_valued=False): self.is_multi_valued = bool(is_multi_valued) # # Mutator. # @security.protected(ManagePortal) def edit(self, is_required, supply_default, default_value, enforce_vocabulary, allowed_vocabulary): self.is_required = bool(is_required) self.supply_default = bool(supply_default) self.default_value = default_value self.enforce_vocabulary = bool(enforce_vocabulary) self.allowed_vocabulary = tuple(allowed_vocabulary) # # Query interface # @security.protected(View) def isMultiValued(self): # Can this element hold multiple values? return self.is_multi_valued @security.protected(View) def isRequired(self): # Must this element be supplied? return self.is_required @security.protected(View) def supplyDefault(self): # Should the tool supply a default? return self.supply_default @security.protected(View) def defaultValue(self): # If so, what is the default? return self.default_value @security.protected(View) def enforceVocabulary(self): # Should the tool enforce the policy's vocabulary? return self.enforce_vocabulary @security.protected(View) def allowedVocabulary(self): # What are the allowed values? return self.allowed_vocabulary
class ZuiteResults(Folder): security = ClassSecurityInfo() meta_type = 'Zuite Results' _properties = ( { 'id': 'test_case_metatypes', 'type': 'lines', 'mode': 'w' }, { 'id': 'completed', 'type': 'date', 'mode': 'w' }, { 'id': 'finished', 'type': 'boolean', 'mode': 'w' }, { 'id': 'passed', 'type': 'boolean', 'mode': 'w' }, { 'id': 'time_secs', 'type': 'float', 'mode': 'w' }, { 'id': 'tests_passed', 'type': 'int', 'mode': 'w' }, { 'id': 'tests_failed', 'type': 'int', 'mode': 'w' }, { 'id': 'commands_passed', 'type': 'int', 'mode': 'w' }, { 'id': 'commands_failed', 'type': 'int', 'mode': 'w' }, { 'id': 'commands_with_errors', 'type': 'int', 'mode': 'w' }, { 'id': 'user_agent', 'type': 'string', 'mode': 'w' }, { 'id': 'remote_addr', 'type': 'string', 'mode': 'w' }, { 'id': 'http_host', 'type': 'string', 'mode': 'w' }, { 'id': 'server_software', 'type': 'string', 'mode': 'w' }, { 'id': 'product_info', 'type': 'lines', 'mode': 'w' }, ) security.declareObjectProtected(View) security.declarePublic('index_html') index_html = PageTemplateFile('resultsView', _WWW_DIR) security.declareProtected(View, 'error_icon') error_icon = ImageFile('error.gif', _WWW_DIR) security.declareProtected(View, 'check_icon') check_icon = ImageFile('check.gif', _WWW_DIR) def __getitem__(self, key, default=_MARKER): if key in self.objectIds(): return self._getOb(key) if key == 'error.gif': return self.error_icon if key == 'check.gif': return self.check_icon if default is not _MARKER: return default raise KeyError(key)
class OldDiscussable(Implicit): """ Adapter for PortalContent to implement "old-style" discussions. """ implements(IOldstyleDiscussable) security = ClassSecurityInfo() def __init__(self, content): self.content = content security.declareProtected(ReplyToItem, 'createReply') def createReply(self, title, text, REQUEST, RESPONSE): """ Create a reply in the proper place """ location, id = self.getReplyLocationAndID(REQUEST) location.addDiscussionItem(id, title, title, 'structured-text', text, self.content) RESPONSE.redirect(self.absolute_url() + '/view') def getReplyLocationAndID(self, REQUEST): # It is not yet clear to me what the correct location for this hook is # Find the folder designated for replies, creating if missing mtool = getUtility(IMembershipTool) home = mtool.getHomeFolder() if not hasattr(home, 'Correspondence'): home.manage_addPortalFolder('Correspondence') location = home.Correspondence location.manage_permission(View, ['Anonymous'], 1) location.manage_permission(AccessContentsInformation, ['Anonymous'], 1) # Find an unused id in location id = int(DateTime().timeTime()) while hasattr(location, repr(id)): id = id + 1 return location, repr(id) security.declareProtected(View, 'getReplyResults') def getReplyResults(self): """ Return the ZCatalog results that represent this object's replies. Often, the actual objects are not needed. This is less expensive than fetching the objects. """ ctool = queryUtility(ICatalogTool) if ctool is not None: return ctool.searchResults( in_reply_to=urllib.unquote('/' + self.absolute_url(1))) security.declareProtected(View, 'getReplies') def getReplies(self): """ Return a sequence of the DiscussionResponse objects which are associated with this Discussable """ ctool = queryUtility(ICatalogTool) if ctool is not None: results = self.getReplyResults() rids = map(lambda x: x.data_record_id_, results) objects = map(ctool.getobject, rids) return objects def quotedContents(self): """ Return this object's contents in a form suitable for inclusion as a quote in a response. """ return ""
class MajorMinorPredicate( SimpleItem ): """ Predicate matching on 'major/minor' content types. Empty major or minor implies wildcard (all match). """ implements(IContentTypeRegistryPredicate) major = minor = None PREDICATE_TYPE = 'major_minor' security = ClassSecurityInfo() def __init__( self, id ): self.id = id security.declareProtected( ManagePortal, 'getMajorType' ) def getMajorType(self): """ Get major content types. """ if self.major is None: return 'None' return ' '.join(self.major) security.declareProtected( ManagePortal, 'getMinorType' ) def getMinorType(self): """ Get minor content types. """ 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 ): """ 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 = typ.split('/', 1) 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 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 ProfileRegistry(Implicit): """ Track registered profiles. """ implements(IProfileRegistry) security = ClassSecurityInfo() security.setDefaultAccess('allow') def __init__(self): self._registered = GlobalRegistryStorage(IProfile) self.clear() security.declareProtected(ManagePortal, 'getProfileInfo') def getProfileInfo(self, profile_id, for_=None): """ See IProfileRegistry. """ result = self._registered.get(profile_id) if result is None: raise KeyError(profile_id) if for_ is not None: if not issubclass(for_, result['for']): raise KeyError(profile_id) return result.copy() security.declareProtected(ManagePortal, 'listProfiles') def listProfiles(self, for_=None): """ See IProfileRegistry. """ result = [] for profile_id in self._registered.keys(): info = self.getProfileInfo(profile_id) if for_ is None or issubclass(for_, info['for']): result.append(profile_id) return tuple(result) security.declareProtected(ManagePortal, 'listProfileInfo') def listProfileInfo(self, for_=None): """ See IProfileRegistry. """ candidates = [self.getProfileInfo(id) for id in self.listProfiles()] return [ x for x in candidates if for_ is None or x['for'] is None or issubclass(for_, x['for']) ] security.declareProtected(ManagePortal, 'registerProfile') def registerProfile(self, name, title, description, path, product=None, profile_type=BASE, for_=None): """ See IProfileRegistry. """ profile_id = self._computeProfileId(name, product) if self._registered.get(profile_id) is not None: raise KeyError('Duplicate profile ID: %s' % profile_id) info = { 'id': profile_id, 'title': title, 'description': description, 'path': path, 'product': product, 'type': profile_type, 'for': for_ } metadata = ProfileMetadata(path, product=product)() # metadata.xml description trumps ZCML description... awkward info.update(metadata) self._registered[profile_id] = info def _computeProfileId(self, name, product): profile_id = '%s:%s' % (product or 'other', name) return profile_id security.declareProtected(ManagePortal, 'unregisterProfile') def unregisterProfile(self, name, product=None): profile_id = self._computeProfileId(name, product) del self._registered[profile_id] security.declarePrivate('clear') def clear(self): self._registered.clear()
class ToolsetRegistry(Implicit): """ Track required / forbidden tools. """ implements(IToolsetRegistry) security = ClassSecurityInfo() security.setDefaultAccess('allow') def __init__(self): self.clear() # # Toolset API # security.declareProtected(ManagePortal, 'listForbiddenTools') def listForbiddenTools(self): """ See IToolsetRegistry. """ result = list(self._forbidden) result.sort() return result security.declareProtected(ManagePortal, 'addForbiddenTool') def addForbiddenTool(self, tool_id): """ See IToolsetRegistry. """ if tool_id in self._forbidden: return if self._required.get(tool_id) is not None: raise ValueError('Tool %s is required!' % tool_id) self._forbidden.append(tool_id) security.declareProtected(ManagePortal, 'listRequiredTools') def listRequiredTools(self): """ See IToolsetRegistry. """ result = list(self._required.keys()) result.sort() return result security.declareProtected(ManagePortal, 'getRequiredToolInfo') def getRequiredToolInfo(self, tool_id): """ See IToolsetRegistry. """ return self._required[tool_id] security.declareProtected(ManagePortal, 'listRequiredToolInfo') def listRequiredToolInfo(self): """ See IToolsetRegistry. """ return [self.getRequiredToolInfo(x) for x in self.listRequiredTools()] security.declareProtected(ManagePortal, 'addRequiredTool') def addRequiredTool(self, tool_id, dotted_name): """ See IToolsetRegistry. """ if tool_id in self._forbidden: raise ValueError("Forbidden tool ID: %s" % tool_id) self._required[tool_id] = {'id': tool_id, 'class': dotted_name} security.declareProtected(ManagePortal, 'generateXML') def generateXML(self, encoding='utf-8'): """ Pseudo API. """ return self._toolsetConfig().encode('utf-8') security.declareProtected(ManagePortal, 'parseXML') def parseXML(self, text, encoding='utf-8'): """ Pseudo-API """ reader = getattr(text, 'read', None) if reader is not None: text = reader() parser = _ToolsetParser(encoding) parseString(text, parser) for tool_id in parser._forbidden: self.addForbiddenTool(tool_id) for tool_id, dotted_name in parser._required.items(): self.addRequiredTool(tool_id, dotted_name) security.declarePrivate('clear') def clear(self): self._forbidden = [] self._required = {} # # Helper methods. # security.declarePrivate('_toolsetConfig') _toolsetConfig = PageTemplateFile('tscExport.xml', _xmldir, __name__='toolsetConfig')
class ExportStepRegistry(BaseStepRegistry): """ Registry of known site-configuration export steps. o Each step is registered with a unique id. o When called, with the portal object passed in as an argument, the step must return a sequence of three-tuples, ( 'data', 'content_type', 'filename' ), one for each file exported by the step. - 'data' is a string containing the file data; - 'content_type' is the MIME type of the data; - 'filename' is a suggested filename for use when downloading. """ implements(IExportStepRegistry) security = ClassSecurityInfo() RegistryParser = _ExportStepRegistryParser security.declarePrivate('registerStep') def registerStep(self, id, handler, title=None, description=None): """ Register an export step. o 'id' is the unique identifier for this step o 'handler' is the dottoed name of a handler which should implement IImportPlugin. o 'title' is a one-line UI description for this step. If None, the first line of the documentation string of the step is used, or the id if no docstring can be found. o 'description' is a one-line UI description for this step. If None, the remaining line of the documentation string of the step is used, or default to ''. """ if not isinstance(handler, str): handler = _getDottedName(handler) if title is None or description is None: method = _resolveDottedName(handler) if method is None: t, d = id, '' else: t, d = _extractDocstring(method, id, '') title = title or t description = description or d info = { 'id': id, 'handler': handler, 'title': title, 'description': description } self._registered[id] = info # # Helper methods # security.declarePrivate('_exportTemplate') _exportTemplate = PageTemplateFile('esrExport.xml', _xmldir)
class Zuite(OrderedFolder): """ TTW-manageable browser test suite A Zuite instance is an ordered folder, whose 'index_html' provides the typical "TestRunner.html" view from Selenium. It generates the "TestSuite.html" view from its 'objectItems' list (which allows the user to control ordering), selecting File and PageTemplate objects whose names start with 'test'. """ meta_type = 'Zuite' manage_options = (OrderedFolder.manage_options + ({ 'label': 'Zip', 'action': 'manage_zipfile' }, )) implements(IZuite) test_case_metatypes = ('File', 'Page Template') filesystem_path = '' filename_glob = '' testsuite_name = '' _v_filesystem_objects = None _v_selenium_objects = None _properties = ({ 'id': 'test_case_metatypes', 'type': 'lines', 'mode': 'w' }, { 'id': 'filesystem_path', 'type': 'string', 'mode': 'w' }, { 'id': 'filename_glob', 'type': 'string', 'mode': 'w' }, { 'id': 'testsuite_name', 'type': 'string', 'mode': 'w' }) security = ClassSecurityInfo() security.declareObjectProtected(View) security.declareProtected(ManageSeleniumTestCases, 'manage_main') manage_main = DTMLFile('suiteMain', _WWW_DIR) security.declareProtected(View, 'index_html') index_html = PageTemplateFile('suiteView', _WWW_DIR) security.declareProtected(View, 'test_suite_html') test_suite_html = PageTemplateFile('suiteTests', _WWW_DIR) security.declareProtected(View, 'splash_html') splash_html = PageTemplateFile('suiteSplash', _WWW_DIR) security.declareProtected(View, 'test_prompt_html') test_prompt_html = PageTemplateFile('testPrompt', _WWW_DIR) security.declareProtected(ManageSeleniumTestCases, 'manage_zipfile') manage_zipfile = PageTemplateFile('suiteZipFile', _WWW_DIR) def __getitem__(self, key, default=_MARKER): if key in self.objectIds(): return self._getOb(key) if key in _SUPPORT_FILES.keys(): return _SUPPORT_FILES[key].__of__(self) proxy = _FilesystemProxy(key, self._listFilesystemObjects()).__of__(self) localdefault = object() value = proxy.get(key, localdefault) if value is not localdefault: return value proxy = _FilesystemProxy(key, self._listSeleniumObjects()).__of__(self) value = proxy.get(key, default) if value is not _MARKER: return value raise KeyError(key) security.declareProtected(View, 'listTestCases') def listTestCases(self, prefix=()): """ Return a list of our contents which qualify as test cases. """ result = [] self._recurseListTestCases(result, prefix, self) return result def _recurseListTestCases(self, result, prefix, ob): for tcid, test_case in ob.objectItems(): if isinstance(test_case, self.__class__): result.extend(test_case.listTestCases(prefix=prefix + (tcid, ))) elif test_case.isPrincipiaFolderish: self._recurseListTestCases(result, prefix + (tcid, ), test_case) elif test_case.meta_type in self.test_case_metatypes: path = '/'.join(prefix + (tcid, )) result.append({ 'id': tcid, 'title': test_case.title_or_id(), 'url': path, 'path': path, 'test_case': test_case }) fsobjs = self._listFilesystemObjects() _recurseFSTestCases(result, prefix, fsobjs) security.declareProtected(ManageSeleniumTestCases, 'getZipFileName') def getZipFileName(self): """ Generate a suitable name for the zip file. """ now = _getNow() now_str = now.ISO()[:10] return '%s-%s.zip' % (self.getId(), now_str) security.declareProtected(ManageSeleniumTestCases, 'manage_getZipFile') def manage_getZipFile(self, archive_name=None, include_selenium=True, RESPONSE=None): """ Export the test suite as a zip file. """ if archive_name is None or archive_name.strip() == '': archive_name = self.getZipFileName() bits = self._getZipFile(include_selenium) if RESPONSE is None: return bits RESPONSE.setHeader('Content-type', 'application/zip') RESPONSE.setHeader('Content-length', str(len(bits))) RESPONSE.setHeader('Content-disposition', 'inline;filename=%s' % archive_name) RESPONSE.write(bits) security.declareProtected(ManageSeleniumTestCases, 'manage_createSnapshot') def manage_createSnapshot(self, archive_name=None, include_selenium=True, RESPONSE=None): """ Save the test suite as a zip file *in the zuite*. """ if archive_name is None or archive_name.strip() == '': archive_name = self.getZipFileName() archive = File(archive_name, title='', file=self._getZipFile(include_selenium)) self._setObject(archive_name, archive) if RESPONSE is not None: RESPONSE.redirect('%s/manage_main?manage_tabs_message=%s' % (self.absolute_url(), 'Snapshot+added')) security.declarePublic('postResults') def postResults(self, REQUEST): """ Record the results of a test run. o Create a folder with properties representing the summary results, and files containing the suite and the individual test runs. o REQUEST will have the following form fields: result -- one of "failed" or "passed" totalTime -- time in floating point seconds for the run numTestPasses -- count of test runs which passed numTestFailures -- count of test runs which failed numCommandPasses -- count of commands which passed numCommandFailures -- count of commands which failed numCommandErrors -- count of commands raising non-assert errors suite -- Colorized HTML of the suite table testTable.<n> -- Colorized HTML of each test run """ completed = DateTime() result_id = 'result_%s' % completed.strftime('%Y%m%d_%H%M%S.%f') self._setObject(result_id, ZuiteResults(result_id)) result = self._getOb(result_id) rfg = REQUEST.form.get reg = REQUEST.environ.get result._updateProperty('completed', completed) result._updateProperty('passed', rfg('result').lower() == 'passed') result._updateProperty('finished', rfg('finished').lower() == 'true') result._updateProperty('time_secs', float(rfg('totalTime', 0))) result._updateProperty('tests_passed', int(rfg('numTestPasses', 0))) result._updateProperty('tests_failed', int(rfg('numTestFailures', 0))) result._updateProperty('commands_passed', int(rfg('numCommandPasses', 0))) result._updateProperty('commands_failed', int(rfg('numCommandFailures', 0))) result._updateProperty('commands_with_errors', int(rfg('numCommandErrors', 0))) result._updateProperty('user_agent', reg('HTTP_USER_AGENT', 'unknown')) result._updateProperty('remote_addr', reg('REMOTE_ADDR', 'unknown')) result._updateProperty('http_host', reg('HTTP_HOST', 'unknown')) result._updateProperty('server_software', reg('SERVER_SOFTWARE', 'unknown')) result._updateProperty('product_info', self._listProductInfo()) result._setObject( 'suite.html', File('suite.html', 'Test Suite', unquote(rfg('suite')), 'text/html')) test_ids = [ x for x in REQUEST.form.keys() if x.startswith('testTable') ] test_ids.sort() for test_id in test_ids: body = unquote(rfg(test_id)) result._setObject( test_id, File(test_id, 'Test case: %s' % test_id, body, 'text/html')) testcase = result._getOb(test_id) # XXX: this is silly, but we have no other metadata. testcase._setProperty('passed', _PINK_BACKGROUND.search(body) is None, 'boolean') # # Helper methods # security.declarePrivate('_listFilesystemObjects') def _listFilesystemObjects(self): """ Return a mapping of any filesystem objects we "hold". """ if (self._v_filesystem_objects is not None and not getConfiguration().debug_mode): return self._v_filesystem_objects if not self.filesystem_path: return {'testcases': (), 'subdirs': {}} path = os.path.abspath(self.filesystem_path) self._v_filesystem_objects = self._grubFilesystem(path) return self._v_filesystem_objects security.declarePrivate('_listSeleniumObjects') def _listSeleniumObjects(self): """ Return a mapping of any filesystem objects we "hold". """ if (self._v_selenium_objects is not None and not getConfiguration().debug_mode): return self._v_selenium_objects self._v_selenium_objects = self._grubFilesystem(_SUPPORT_DIR) return self._v_selenium_objects security.declarePrivate('_grubFilesystem') def _grubFilesystem(self, path): info = {'testcases': (), 'subdirs': {}} # Look for a specified test suite # or a '.objects' file with an explicit manifiest manifest = os.path.join(path, self.testsuite_name or '.objects') if os.path.isfile(manifest): filenames = filter(None, [x.strip() for x in open(manifest).readlines()]) elif self.filename_glob: globbed = glob.glob(os.path.join(path, self.filename_glob)) filenames = [os.path.split(x)[1] for x in globbed] else: # guess filenames = [ x for x in os.listdir(path) if x not in _EXCLUDE_NAMES ] filenames.sort() info['ordered'] = filenames for name in filenames: fqfn = os.path.join(path, name) if os.path.isfile(fqfn): testcase = _makeFile(fqfn) info['testcases'] += (testcase, ) elif os.path.isdir(fqfn): info['subdirs'][name] = self._grubFilesystem(fqfn) else: logger.warning( '%r was neither a file nor directory and so has been ignored', fqfn) return info security.declarePrivate('_getFilename') def _getFilename(self, name): """ Convert 'name' to a suitable filename, if needed. """ if '.' not in name: return '%s.html' % name return name security.declarePrivate('_getZipFile') def _getZipFile(self, include_selenium=True): """ Generate a zip file containing both tests and scaffolding. """ stream = StringIO.StringIO() archive = zipfile.ZipFile(stream, 'w') def convertToBytes(body): if isinstance(body, types.UnicodeType): return body.encode(_DEFAULTENCODING) else: return body archive.writestr( 'index.html', convertToBytes(self.index_html(suite_name='testSuite.html'))) test_cases = self.listTestCases() paths = {'': []} def _ensurePath(prefix, element): elements = paths.setdefault(prefix, []) if element not in elements: elements.append(element) for info in test_cases: # ensure suffixes path = self._getFilename(info['path']) info['path'] = path info['url'] = self._getFilename(info['url']) elements = path.split(os.path.sep) _ensurePath('', elements[0]) for i in range(1, len(elements)): prefix = '/'.join(elements[:i]) _ensurePath(prefix, elements[i]) archive.writestr( 'testSuite.html', convertToBytes(self.test_suite_html(test_cases=test_cases))) for pathname, filenames in paths.items(): if pathname == '': filename = '.objects' else: filename = '%s/.objects' % pathname archive.writestr(convertToBytes(filename), convertToBytes(u'\n'.join(filenames))) for info in test_cases: test_case = info['test_case'] if getattr(test_case, '__call__', None) is not None: body = test_case() # XXX: DTML? else: body = test_case.manage_FTPget() archive.writestr(convertToBytes(info['path']), convertToBytes(body)) if include_selenium: for k, v in _SUPPORT_FILES.items(): archive.writestr( convertToBytes(k), convertToBytes(v.__of__(self).manage_FTPget())) archive.close() return stream.getvalue() security.declarePrivate('_listProductInfo') def _listProductInfo(self): """ Return a list of strings of form '%(name)s %(version)s'. o Each line describes one product installed in the Control_Panel. """ result = [] cp = self.getPhysicalRoot().Control_Panel products = cp.Products.objectItems() products.sort() for product_name, product in products: version = product.version or 'unreleased' result.append('%s %s' % (product_name, version)) return result
class MembershipTool(UniqueObject, Folder): """ This tool accesses member data through an acl_users object. It can be replaced with something that accesses member data in a different way. """ id = 'portal_membership' meta_type = 'CMF Membership Tool' memberareaCreationFlag = 1 _HOME_FOLDER_FACTORY_NAME = 'cmf.folder.home.bbb1' security = ClassSecurityInfo() manage_options = (({ 'label': 'Configuration', 'action': 'manage_mapRoles' }, { 'label': 'Overview', 'action': 'manage_overview' }) + Folder.manage_options) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainMembershipTool', _dtmldir) # # 'portal_membership' interface methods # security.declareProtected(ManagePortal, 'manage_mapRoles') manage_mapRoles = DTMLFile('membershipRolemapping', _dtmldir) @security.protected(SetOwnPassword) @postonly def setPassword(self, password, domains=None, REQUEST=None): '''Allows the authenticated member to set his/her own password. ''' if not self.isAnonymousUser(): member = self.getAuthenticatedMember() rtool = queryUtility(IRegistrationTool) if rtool is not None: failMessage = rtool.testPasswordValidity(password) if failMessage is not None: raise BadRequest(failMessage) member.setSecurityProfile(password=password, domains=domains) else: raise BadRequest('Not logged in.') @security.public def getAuthenticatedMember(self): ''' Returns the currently authenticated member object or the Anonymous User. Never returns None. ''' u = getSecurityManager().getUser() if u is None: u = nobody return self.wrapUser(u) @security.private def wrapUser(self, u, wrap_anon=0): """ Set up the correct acquisition wrappers for a user object. Provides an opportunity for a portal_memberdata tool to retrieve and store member data independently of the user object. """ b = getattr(u, 'aq_base', None) if b is None: # u isn't wrapped at all. Wrap it in self.acl_users. b = u u = u.__of__(self.acl_users) if (b is nobody and not wrap_anon) or hasattr(b, 'getMemberId'): # This user is either not recognized by acl_users or it is # already registered with something that implements the # member data tool at least partially. return u # Apply any role mapping if we have it if hasattr(self, 'role_map'): for portal_role in self.role_map.keys(): if (self.role_map.get(portal_role) in u.roles and portal_role not in u.roles): u.roles.append(portal_role) mdtool = queryUtility(IMemberDataTool) if mdtool is not None: try: u = mdtool.wrapUser(u) except ConflictError: raise except: logger.exception("Error during wrapUser") return u @security.protected(ManagePortal) def getPortalRoles(self): """ Return all local roles defined by the portal itself, which means roles that are useful and understood by the portal object """ parent = self.aq_inner.aq_parent roles = list(parent.userdefined_roles()) # This is *not* a local role in the portal but used by it roles.append('Manager') roles.append('Owner') return roles @security.protected(ManagePortal) @postonly def setRoleMapping(self, portal_role, userfolder_role, REQUEST=None): """ set the mapping of roles between roles understood by the portal and roles coming from outside user sources """ if not hasattr(self, 'role_map'): self.role_map = PersistentMapping() if len(userfolder_role) < 1: del self.role_map[portal_role] else: self.role_map[portal_role] = userfolder_role return MessageDialog(title='Mapping updated', message='The Role mappings have been updated', action='manage_mapRoles') @security.protected(ManagePortal) def getMappedRole(self, portal_role): """ returns a role name if the portal role is mapped to something else or an empty string if it is not """ if hasattr(self, 'role_map'): return self.role_map.get(portal_role, '') else: return '' @security.public def getMembersFolder(self): """ Get the members folder object. """ parent = aq_parent(aq_inner(self)) members_folder = getattr(parent, 'Members', None) if members_folder is None: return None request_container = RequestContainer(REQUEST=getRequest()) return members_folder.__of__(request_container) @security.protected(ManagePortal) def getMemberareaCreationFlag(self): """ Returns the flag indicating whether the membership tool will create a member area if an authenticated user from an underlying user folder logs in first without going through the join process """ return self.memberareaCreationFlag @security.protected(ManagePortal) def setMemberareaCreationFlag(self): """ sets the flag indicating whether the membership tool will create a member area if an authenticated user from an underlying user folder logs in first without going through the join process """ if not hasattr(self, 'memberareaCreationFlag'): self.memberareaCreationFlag = 0 if self.memberareaCreationFlag == 0: self.memberareaCreationFlag = 1 else: self.memberareaCreationFlag = 0 return MessageDialog( title='Member area creation flag changed', message='Member area creation flag has been updated', action='manage_mapRoles') @security.public def createMemberArea(self, member_id=''): """ Create a member area for 'member_id' or authenticated user. """ if not self.getMemberareaCreationFlag(): return None members = self.getMembersFolder() if members is None: return None if self.isAnonymousUser(): return None if member_id: if not self.isMemberAccessAllowed(member_id): return None member = self.getMemberById(member_id) if member is None: return None else: member = self.getAuthenticatedMember() member_id = member.getId() if hasattr(aq_base(members), member_id): return None factory_name = self._HOME_FOLDER_FACTORY_NAME portal_type_name = 'Folder' ttool = queryUtility(ITypesTool) if ttool is not None: portal_type = ttool.getTypeInfo('Home Folder') if portal_type is not None: factory_name = portal_type.factory portal_type_name = portal_type.getId() factory = getUtility(IFactory, factory_name) obj = factory(id=member_id) obj._setPortalTypeName(portal_type_name) members._setObject(member_id, obj) f = members._getOb(member_id) f.changeOwnership(member) return f security.declarePublic('createMemberarea') createMemberarea = createMemberArea @security.protected(ManageUsers) @postonly def deleteMemberArea(self, member_id, REQUEST=None): """ Delete member area of member specified by member_id. """ members = self.getMembersFolder() if not members: return 0 if hasattr(aq_base(members), member_id): members.manage_delObjects(member_id) return 1 else: return 0 @security.public def isAnonymousUser(self): ''' Returns 1 if the user is not logged in. ''' u = getSecurityManager().getUser() if u is None or u.getUserName() == 'Anonymous User': return 1 return 0 @security.public def checkPermission(self, permissionName, object, subobjectName=None): ''' Checks whether the current user has the given permission on the given object or subobject. ''' if subobjectName is not None: object = getattr(object, subobjectName) return _checkPermission(permissionName, object) @security.protected(ManageUsers) def isMemberAccessAllowed(self, member_id): """Check if the authenticated user is this member or an user manager. """ sm = getSecurityManager() user = sm.getUser() if user is None: return False if member_id == user.getId(): return True return sm.checkPermission(ManageUsers, self) @security.public def credentialsChanged(self, password, REQUEST=None): ''' Notifies the authentication mechanism that this user has changed passwords. This can be used to update the authentication cookie. Note that this call should *not* cause any change at all to user databases. ''' if not self.isAnonymousUser(): user = getSecurityManager().getUser() name = user.getUserName() # this really does need to be the user name, and not the user id, # because we're dealing with authentication credentials cctool = queryUtility(ICookieCrumbler) if cctool is not None: cctool.credentialsChanged(user, name, password, REQUEST) @security.protected(ManageUsers) def getMemberById(self, id): ''' Returns the given member. ''' user = self._huntUser(id, self) if user is not None: user = self.wrapUser(user) return user def _huntUserFolder(self, member_id, context): """Find userfolder containing user in the hierarchy starting from context """ uf = context.acl_users while uf is not None: user = uf.getUserById(member_id) if user is not None: return uf container = aq_parent(aq_inner(uf)) parent = aq_parent(aq_inner(container)) uf = getattr(parent, 'acl_users', None) return None def _huntUser(self, member_id, context): """Find user in the hierarchy of userfolders starting from context """ uf = self._huntUserFolder(member_id, context) if uf is not None: return uf.getUserById(member_id).__of__(uf) def __getPUS(self): """ Retrieve the nearest user folder """ warn( '__getPUS is deprecated and will be removed in CMF 2.4, ' 'please acquire "acl_users" instead.', DeprecationWarning, stacklevel=2) return self.acl_users @security.protected(ManageUsers) def listMemberIds(self): '''Lists the ids of all members. This may eventually be replaced with a set of methods for querying pieces of the list rather than the entire list at once. ''' user_folder = self.acl_users return [x.getId() for x in user_folder.getUsers()] @security.protected(ManageUsers) def listMembers(self): '''Gets the list of all members. ''' return map(self.wrapUser, self.acl_users.getUsers()) @security.protected(ListPortalMembers) def searchMembers(self, search_param, search_term): """ Search the membership """ mdtool = queryUtility(IMemberDataTool) if mdtool is not None: return mdtool.searchMemberData(search_param, search_term) return None @security.protected(View) def getCandidateLocalRoles(self, obj): """ What local roles can I assign? """ member = self.getAuthenticatedMember() member_roles = member.getRolesInContext(obj) if _checkPermission(ManageUsers, obj): local_roles = self.getPortalRoles() if 'Manager' not in member_roles: local_roles.remove('Manager') else: local_roles = [ role for role in member_roles if role not in ('Member', 'Authenticated') ] local_roles.sort() return tuple(local_roles) @security.protected(View) @postonly def setLocalRoles(self, obj, member_ids, member_role, reindex=1, REQUEST=None): """ Add local roles on an item. """ if (_checkPermission(ChangeLocalRoles, obj) and member_role in self.getCandidateLocalRoles(obj)): for member_id in member_ids: roles = list(obj.get_local_roles_for_userid(userid=member_id)) if member_role not in roles: roles.append(member_role) obj.manage_setLocalRoles(member_id, roles) if reindex and hasattr(aq_base(obj), 'reindexObjectSecurity'): obj.reindexObjectSecurity() @security.protected(View) @postonly def deleteLocalRoles(self, obj, member_ids, reindex=1, recursive=0, REQUEST=None): """ Delete local roles of specified members. """ if _checkPermission(ChangeLocalRoles, obj): for member_id in member_ids: if obj.get_local_roles_for_userid(userid=member_id): obj.manage_delLocalRoles(userids=member_ids) break if recursive and hasattr(aq_base(obj), 'contentValues'): for subobj in obj.contentValues(): self.deleteLocalRoles(subobj, member_ids, 0, 1) if reindex and hasattr(aq_base(obj), 'reindexObjectSecurity'): # reindexObjectSecurity is always recursive obj.reindexObjectSecurity() @security.private def addMember(self, id, password, roles, domains, properties=None): '''Adds a new member to the user folder. Security checks will have already been performed. Called by portal_registration. ''' self.acl_users._doAddUser(id, password, roles, domains) if properties is not None: member = self.getMemberById(id) member.setMemberProperties(properties) @security.protected(ManageUsers) @postonly def deleteMembers(self, member_ids, delete_memberareas=1, delete_localroles=1, REQUEST=None): """ Delete members specified by member_ids. """ # Delete members in acl_users. acl_users = self.acl_users if _checkPermission(ManageUsers, acl_users): if isinstance(member_ids, basestring): member_ids = (member_ids, ) member_ids = list(member_ids) for member_id in member_ids[:]: if not acl_users.getUserById(member_id, None): member_ids.remove(member_id) try: acl_users.userFolderDelUsers(member_ids) except (AttributeError, NotImplementedError): raise NotImplementedError('The underlying User Folder ' 'doesn\'t support deleting members.') else: raise AccessControl_Unauthorized( 'You need the \'Manage users\' ' 'permission for the underlying User Folder.') # Delete member data in portal_memberdata. mdtool = queryUtility(IMemberDataTool) if mdtool is not None: for member_id in member_ids: mdtool.deleteMemberData(member_id) # Delete members' home folders including all content items. if delete_memberareas: for member_id in member_ids: self.deleteMemberArea(member_id) # Delete members' local roles. if delete_localroles: self.deleteLocalRoles(getUtility(ISiteRoot), member_ids, reindex=1, recursive=1) return tuple(member_ids) @security.public def getHomeFolder(self, id=None, verifyPermission=0): """Returns a member's home folder object or None. Set verifyPermission to 1 to return None when the user doesn't have the View permission on the folder. """ return None @security.public def getHomeUrl(self, id=None, verifyPermission=0): """Returns the URL to a member's home folder or None. Set verifyPermission to 1 to return None when the user doesn't have the View permission on the folder. """ return None
class misc_: "Miscellaneous product information" security = ClassSecurityInfo() security.declareObjectPublic()
class Connection(ConnectionBase): """ Zope database adapter for MySQL/MariaDB """ meta_type = 'Z MySQL Database Connection' security = ClassSecurityInfo() zmi_icon = 'fas fa-database' auto_create_db = True use_unicode = False charset = None timeout = None _v_connected = '' _isAnSQLConnection = 1 info = None security.declareProtected( view_management_screens, # NOQA: D001 'manage_browse') manage_browse = HTMLFile('www/browse', globals()) security.declareProtected( change_database_methods, # NOQA: D001 'manage_properties') manage_properties = HTMLFile('www/connectionEdit', globals()) manage_properties._setName('manage_main') manage_main = manage_properties manage_options = (ConnectionBase.manage_options[1:] + ({ 'label': 'Browse', 'action': 'manage_browse' }, )) def __init__(self, id, title, connection_string, check, use_unicode=None, charset=None, auto_create_db=None, timeout=None): """ Instance setup. Optionally opens the connection. :string: id -- The id of the ZMySQLDA Connection :string: title -- The title of the ZMySQLDA Connection :string: connection_string -- The connection string describes how to connect to the relational database. See the documentation for details. :bool: check -- Check if the database connection can be opened after instantiation. :bool: use_unicode -- If set to ``True``, values from columns of type ``CHAR``, ``VARCHAR`` and ``TEXT`` are returned as unicode strings by the database backend. Combined with the hardcoded ``utf8`` character set of this package the setting allows you to control the character set of database return values better. Default: False. :string: charset -- The character set for the connection. MySQL/MariaDB will encode query results to this character set. On Python 2, both utf8 and Latin1 will work. On Python 3, only utf8 will work. Default on Python 2: Latin1 when ``use_unicode`` is off, utf8 otherwise Default on Python 3: utf8 :bool: auto_create_db -- If the database given in ``connection_string`` does not exist, create it automatically. Default: False. :int: timeout -- The connect timeout for the connection in seconds. Default: None """ self.use_unicode = bool(use_unicode) self.charset = charset self.auto_create_db = bool(auto_create_db) self.timeout = int(timeout) if timeout else None return super(Connection, self).__init__(id, title, connection_string, check) def __setstate__(self, state): """ Skip super's __setstate__ as it connects which we don't want due to pool_key depending on acquisition. """ Persistent.__setstate__(self, state) security.declareProtected(use_database_methods, 'factory') # NOQA: D001 def factory(self): """ Base API. Returns factory method for DB connections. """ return DB def _pool_key(self): """ Return key used for DA pool. """ return self.getPhysicalPath() def _getConnection(self): """ Helper method to retrieve an existing or create a new connection """ try: return self._v_database_connection except AttributeError: self.connect(self.connection_string) return self._v_database_connection security.declareProtected(use_database_methods, 'connect') # NOQA: D001 def connect(self, conn_string): """ Base API. Opens connection to mysql. Raises if problems. :string: conn_string -- The database connection string """ pool_key = self._pool_key() conn = database_connection_pool.get(pool_key) if conn is not None and conn.connection == conn_string: self._v_database_connection = conn self._v_connected = conn.connected_timestamp else: if conn is not None: conn.closeConnection() conn_pool = DBPool(self.factory(), create_db=self.auto_create_db, use_unicode=self.use_unicode, charset=self.charset, timeout=self.timeout) database_connection_pool_lock.acquire() try: conn = conn_pool(conn_string) database_connection_pool[pool_key] = conn finally: database_connection_pool_lock.release() self._v_database_connection = conn # If date is used as such, it can be wrong because an # existing connection may be reused. But this is suposedly # only used as a marker to know if connection was successfull. self._v_connected = conn.connected_timestamp return self # ??? why doesn't this return the connection ??? security.declareProtected( use_database_methods, # NOQA: D001 'sql_quote__') def sql_quote__(self, sql_str, escapes={}): """ Base API. Used to massage SQL strings for use in queries. :string: sql_str -- The raw SQL string to transform. :dict: escapes -- Additional escape transformations. Default: empty ``dict``. """ connection = self._getConnection() if self.use_unicode and isinstance(sql_str, six.text_type): # Confusing naming: unicode_literal does not return an unencoded # ("unicode") string, but an encoded bytes string. encoded = connection.unicode_literal(sql_str) # If the SQL string was unencoded to begin with we want to make # sure to return the same thing, so decode it here. charset = self.charset or 'latin1' if charset.startswith('utf8'): charset = 'utf-8' return encoded.decode(charset) else: return connection.string_literal(sql_str) security.declareProtected( change_database_methods, # NOQA: D001 'manage_edit') def manage_edit(self, title, connection_string, check=None, use_unicode=None, charset=None, auto_create_db=None, timeout=None, REQUEST=None): """ Edit the connection attributes through the Zope ZMI. :string: title -- The title of the ZMySQLDA Connection :string: connection_string -- The connection string describes how to connect to the relational database. See the documentation for details. :bool: check -- Check if the database connection can be opened after instantiation. Default: False. :bool: use_unicode -- Use unicode internally. Default: False. :string: charset -- The character set for the connection. MySQL/MariaDB will encode query results to this character set. On Python 2, both utf8 and Latin1 will work. On Python 3, only utf8 will work. Default on Python 2: Latin1 when ``use_unicode`` is off, utf8 otherwise Default on Python 3: utf8 :bool: auto_create_db -- If the database given in ``connection_string`` does not exist, create it automatically. Default: False. :int: timeout -- The connect timeout for the connection in seconds. Default: None :request: REQUEST -- A Zope REQUEST object """ self.use_unicode = bool(use_unicode) self.charset = charset self.auto_create_db = bool(auto_create_db) self.timeout = int(timeout) if timeout else None try: result = super(Connection, self).manage_edit(title, connection_string, check=check) msg = 'Changes applied.' except Exception as exc: msg = 'ERROR: %s' % str(exc) if REQUEST is None: raise if REQUEST is None: return result else: url = '%s/manage_properties?manage_tabs_message=%s' REQUEST.RESPONSE.redirect(url % (self.absolute_url(), msg)) security.declareProtected( view_management_screens, # NOQA: D001 'tpValues') def tpValues(self): """ Support the DTML ``tree`` tag Used in the Zope ZMI ``Browse`` tab """ t_list = [] connection = self._getConnection() for t_info in connection.tables(rdb=0): try: t_browser = TableBrowser() t_browser.__name__ = t_info['table_name'] t_browser._d = t_info t_browser._c = connection t_browser.icon = table_icons.get(t_info['table_type'], 'text') t_list.append(t_browser) except Exception: pass return t_list
class MetadataTool(PloneBaseTool, UniqueObject, Folder): id = 'portal_metadata' meta_type = 'Default Metadata Tool' toolicon = 'skins/plone_images/info_icon.png' # # Default values. # publisher = '' security = ClassSecurityInfo() def __init__(self, publisher=None): self.editProperties(publisher) self.DCMI = MetadataSchema('DCMI', _DCMI_ELEMENT_SPECS) # # ZMI methods # manage_options = (({ 'label': 'Schema', 'action': 'propertiesForm' }, { 'label': 'Overview', 'action': 'manage_overview' }) + Folder.manage_options) security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainMetadataTool', WWW_DIR) security.declareProtected(ManagePortal, 'propertiesForm') propertiesForm = DTMLFile('metadataProperties', WWW_DIR) @security.protected(ManagePortal) def editProperties(self, publisher=None, REQUEST=None): """ Form handler for "tool-wide" properties """ if publisher is not None: self.publisher = publisher if REQUEST is not None: REQUEST['RESPONSE'].redirect( self.absolute_url() + '/propertiesForm?manage_tabs_message=Tool+updated.') @security.protected(ManagePortal) def manage_addSchema(self, schema_id, elements, REQUEST): """ ZMI wrapper around addSchema """ massaged = [] for element in elements: if isinstance(element, basestring): element = element.split(',') if len(element) < 2: element.append(0) massaged.append(element) self.addSchema(schema_id, massaged) REQUEST['RESPONSE'].redirect( self.absolute_url() + '/propertiesForm?manage_tabs_message=Schema+added.') @security.protected(ManagePortal) def manage_removeSchemas(self, schema_ids, REQUEST): """ ZMI wrapper around removeSchema """ if not schema_ids: raise ValueError('No schemas selected!') for schema_id in schema_ids: self.removeSchema(schema_id) REQUEST['RESPONSE'].redirect( self.absolute_url() + '/propertiesForm?manage_tabs_message=Schemas+removed.') @security.private def getFullName(self, userid): # See IMetadataTool. return userid # TODO: do lookup here @security.public def getPublisher(self): # See IMetadataTool. return self.publisher @security.public def listAllowedSubjects(self, content=None, content_type=None): # See IMetadataTool. return self.listAllowedVocabulary('DCMI', 'Subject', content, content_type) @security.public def listAllowedFormats(self, content=None, content_type=None): # See IMetadataTool. return self.listAllowedVocabulary('DCMI', 'Format', content, content_type) @security.public def listAllowedLanguages(self, content=None, content_type=None): # See IMetadataTool. return self.listAllowedVocabulary('DCMI', 'Language', content, content_type) @security.public def listAllowedRights(self, content=None, content_type=None): # See IMetadata Tool. return self.listAllowedVocabulary('DCMI', 'Rights', content, content_type) @security.public def listAllowedVocabulary(self, schema, element, content=None, content_type=None): # See IMetadataTool. schema_def = getattr(self, schema) spec = schema_def.getElementSpec(element) if content_type is None and content: content_type = content.getPortalTypeName() return spec.getPolicy(content_type).allowedVocabulary() @security.public def listSchemas(self): # See IMetadataTool. result = [('DCMI', self.DCMI)] result.extend(self.objectItems([MetadataSchema.meta_type])) return result @security.protected(ModifyPortalContent) def addSchema(self, schema_id, elements=()): # See IMetadataTool. if schema_id == 'DCMI' or schema_id in self.objectIds(): raise KeyError('Duplicate schema ID: %s' % schema_id) schema = MetadataSchema(schema_id, elements) self._setObject(schema_id, schema) return self._getOb(schema_id) @security.protected(ModifyPortalContent) def removeSchema(self, schema_id): # See IMetadataTool. if schema_id == 'DCMI' or schema_id not in self.objectIds(): raise KeyError('Invalid schema ID: %s' % schema_id) self._delObject(schema_id) @security.protected(ModifyPortalContent) def setInitialMetadata(self, content): # See IMetadataTool. for schema_id, schema in self.listSchemas(): for element, policy in schema.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.protected(View) def validateMetadata(self, content): # See IMetadataTool. for schema_id, schema in self.listSchemas(): for element, policy in schema.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 value not in policy.allowedVocabulary(): raise MetadataError( 'Value %s is not in allowed vocabulary for ' 'metadata element %s.' % (value, element))
class PrivacyTool(UniqueObject, IFAwareObjectManager, OrderedFolder, PloneBaseTool): """ Manage through-the-web signup policies. """ meta_type = 'Plone Privacy Tool' _product_interfaces = (IProcessingReason, ) security = ClassSecurityInfo() toolicon = 'skins/plone_images/pencil_icon.png' id = 'portal_privacy' plone_tool = 1 def _setId(self, *args, **kwargs): return def getId(self): return 'portal_privacy' def __init__(self, *args, **kwargs): super(PrivacyTool, self).__init__(self, *args, **kwargs) self._signing_secret = uuid.uuid4().hex @security.private def signIdentifier(self, processing_reason_id, user=None): processing_reason = self.getProcessingReason(processing_reason_id) if user is None: identifier = processing_reason.identifier_factory.getIdentifierForCurrentRequest( self.REQUEST) else: identifier = processing_reason.identifier_factory.getIdentifierForUser( user) if identifier is None: raise ValueError("Couldn't identify user") return hmac.new(self._signing_secret, msg=str(identifier)).hexdigest() @security.private def verifyIdentifier(self, signed, processing_reason_id, user=None): return hmac.compare_digest( signed, self.signIdentifier(processing_reason_id, user)) @security.private def getConsentLink(self, processing_reason_id, user=None): site = self.portal_url.getPortalObject() return "{}/@@consent?processing_reason={}&user_id={}&authentication={}".format( site.absolute_url(), processing_reason_id, user, self.signIdentifier(processing_reason_id, user)) @security.public def bannerConsent(self, processing_reason, consent=None, refuse=None): """User-accessible consent action""" if consent: self.consentToProcessing(processing_reason) elif refuse: self.objectToProcessing(processing_reason) return @security.public def getAllReasons(self): return dict(getUtilitiesFor(IProcessingReason)) @security.public def getProcessingReason(self, processing_reason_id): # We might be called from Diazo, so we should explicitly get the site manager lsm = self.aq_inner.aq_parent.getSiteManager() return lsm.getUtility(IProcessingReason, name=processing_reason_id) @security.public def processingIsAllowed(self, processing_reason_id, user=None): processing_reason = self.getProcessingReason(processing_reason_id) return processing_reason.isProcessingAllowed(self.REQUEST, user) @security.private def objectToProcessing(self, processing_reason_id, user=None): processing_reason = self.getProcessingReason(processing_reason_id) processing_reason.objectToProcessing(request=self.REQUEST, user=user) @security.private def consentToProcessing(self, processing_reason_id, user=None): processing_reason = self.getProcessingReason(processing_reason_id) processing_reason.consentToProcessing(request=self.REQUEST, user=user) def requestPorting(self, identifier, topic=None): raise NotImplementedError def requestDeletion(self, identifier, topic=None): raise NotImplementedError
class DefaultDublinCoreImpl(PropertyManager): """ Mix-in class which provides Dublin Core methods. """ security = ClassSecurityInfo() def __init__(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='', rights=''): now = DateTime() self.creation_date = now self.modification_date = now self.creators = () self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights) # # Set-modification-date-related methods. # In DefaultDublinCoreImpl for lack of a better place. # # Class variable default for an upgrade. modification_date = None security.declarePrivate('notifyModified') def notifyModified(self): # Take appropriate action after the resource has been modified. # Update creators and modification_date. self.addCreator() self.setModificationDate() security.declareProtected(ModifyPortalContent, 'addCreator') def addCreator(self, creator=None): # Add creator to Dublin Core creators. if creator is None: user = getSecurityManager().getUser() creator = user and user.getId() # call self.listCreators() to make sure self.creators exists if creator and not creator in self.listCreators(): self.creators = self.creators + (creator, ) security.declareProtected(ModifyPortalContent, 'setModificationDate') def setModificationDate(self, modification_date=None): # Set the date when the resource was last modified. # When called without an argument, sets the date to now. if modification_date is None: self.modification_date = DateTime() else: self.modification_date = self._datify(modification_date) # # DublinCore interface query methods # security.declareProtected(View, 'Title') def Title(self): # Dublin Core Title element - resource name. return self.title security.declareProtected(View, 'listCreators') def listCreators(self): # List Dublin Core Creator elements - resource authors. if not hasattr(aq_base(self), 'creators'): # for content created with CMF versions before 1.5 owner_tuple = self.getOwnerTuple() if owner_tuple: self.creators = (owner_tuple[1], ) else: self.creators = () return self.creators security.declareProtected(View, 'Creator') def Creator(self): # Dublin Core Creator element - resource author. creators = self.listCreators() return creators and creators[0] or '' security.declareProtected(View, 'Subject') def Subject(self): # Dublin Core Subject element - resource keywords. return getattr(self, 'subject', ()) # compensate for *old* content security.declareProtected(View, 'Description') def Description(self): # Dublin Core Description element - resource summary. return self.description security.declareProtected(View, 'Publisher') def Publisher(self): # Dublin Core Publisher element - resource publisher. tool = getToolByName(self, 'portal_metadata', None) if tool is not None: return tool.getPublisher() return 'No publisher' security.declareProtected(View, 'listContributors') def listContributors(self): # Dublin Core Contributor elements - resource collaborators. return self.contributors security.declareProtected(View, 'Contributors') def Contributors(self): # Deprecated alias of listContributors. return self.listContributors() security.declareProtected(View, 'Date') def Date(self, zone=None): # Dublin Core Date element - default date. if zone is None: zone = _zone # Return effective_date if set, modification date otherwise date = getattr(self, 'effective_date', None) if date is None: date = self.modified() return date.toZone(zone).ISO() security.declareProtected(View, 'CreationDate') def CreationDate(self, zone=None): # Dublin Core Date element - date resource created. if zone is None: zone = _zone # return unknown if never set properly if self.creation_date: return self.creation_date.toZone(zone).ISO() else: return 'Unknown' security.declareProtected(View, 'EffectiveDate') def EffectiveDate(self, zone=None): # Dublin Core Date element - date resource becomes effective. if zone is None: zone = _zone ed = getattr(self, 'effective_date', None) return ed and ed.toZone(zone).ISO() or 'None' security.declareProtected(View, 'ExpirationDate') def ExpirationDate(self, zone=None): # Dublin Core Date element - date resource expires. if zone is None: zone = _zone ed = getattr(self, 'expiration_date', None) return ed and ed.toZone(zone).ISO() or 'None' security.declareProtected(View, 'ModificationDate') def ModificationDate(self, zone=None): # Dublin Core Date element - date resource last modified. if zone is None: zone = _zone return self.modified().toZone(zone).ISO() security.declareProtected(View, 'Type') def Type(self): # Dublin Core Type element - resource type. ti = self.getTypeInfo() return ti is not None and ti.Title() or 'Unknown' security.declareProtected(View, 'Format') def Format(self): # Dublin Core Format element - resource format. return self.format security.declareProtected(View, 'Identifier') def Identifier(self): # Dublin Core Identifier element - resource ID. # XXX: fixme using 'portal_metadata' (we need to prepend the # right prefix to self.getPhysicalPath(). return self.absolute_url() security.declareProtected(View, 'Language') def Language(self): # Dublin Core Language element - resource language. return self.language security.declareProtected(View, 'Rights') def Rights(self): # Dublin Core Rights element - resource copyright. return self.rights # # DublinCore utility methods # def content_type(self): """ WebDAV needs this to do the Right Thing (TM). """ return self.Format() __FLOOR_DATE = DateTime(1970, 0) # always effective security.declareProtected(View, 'isEffective') def isEffective(self, date): # Is the date within the resource's effective range? pastEffective = (self.effective_date is None or self.effective_date <= date) beforeExpiration = (self.expiration_date is None or self.expiration_date >= date) return pastEffective and beforeExpiration # # CatalogableDublinCore methods # security.declareProtected(View, 'created') def created(self): # Dublin Core Date element - date resource created. # allow for non-existent creation_date, existed always date = getattr(self, 'creation_date', None) return date is None and self.__FLOOR_DATE or date security.declareProtected(View, 'effective') def effective(self): # Dublin Core Date element - date resource becomes effective. marker = [] date = getattr(self, 'effective_date', marker) if date is marker: date = getattr(self, 'creation_date', None) return date is None and self.__FLOOR_DATE or date __CEILING_DATE = DateTime(2500, 0) # never expires security.declareProtected(View, 'expires') def expires(self): # Dublin Core Date element - date resource expires. date = getattr(self, 'expiration_date', None) return date is None and self.__CEILING_DATE or date security.declareProtected(View, 'modified') def modified(self): # Dublin Core Date element - date resource last modified. date = self.modification_date if date is None: # Upgrade. date = DateTime(self._p_mtime) self.modification_date = date return date security.declareProtected(View, 'getMetadataHeaders') def getMetadataHeaders(self): # Return RFC-822-style headers. hdrlist = [] hdrlist.append(('Title', self.Title())) hdrlist.append(('Subject', ', '.join(self.Subject()))) hdrlist.append(('Publisher', self.Publisher())) hdrlist.append(('Description', self.Description())) hdrlist.append(('Contributors', '; '.join(self.Contributors()))) hdrlist.append(('Effective_date', self.EffectiveDate())) hdrlist.append(('Expiration_date', self.ExpirationDate())) hdrlist.append(('Type', self.Type())) hdrlist.append(('Format', self.Format())) hdrlist.append(('Language', self.Language())) hdrlist.append(('Rights', self.Rights())) return hdrlist # # MutableDublinCore methods # security.declarePrivate('_datify') def _datify(self, attrib): if attrib == 'None': attrib = None elif not isinstance(attrib, DateTime): if attrib is not None: attrib = DateTime(attrib) return attrib security.declareProtected(ModifyPortalContent, 'setTitle') def setTitle(self, title): # Set Dublin Core Title element - resource name. self.title = title security.declareProtected(ModifyPortalContent, 'setCreators') def setCreators(self, creators): # Set Dublin Core Creator elements - resource authors. self.creators = tuplize('creators', creators) security.declareProtected(ModifyPortalContent, 'setSubject') def setSubject(self, subject): # Set Dublin Core Subject element - resource keywords. self.subject = tuplize('subject', subject) security.declareProtected(ModifyPortalContent, 'setDescription') def setDescription(self, description): # Set Dublin Core Description element - resource summary. self.description = description security.declareProtected(ModifyPortalContent, 'setContributors') def setContributors(self, contributors): # Set Dublin Core Contributor elements - resource collaborators. semi_split = lambda s: map(lambda x: x.strip(), s.split(';')) self.contributors = tuplize('contributors', contributors, semi_split) security.declareProtected(ModifyPortalContent, 'setEffectiveDate') def setEffectiveDate(self, effective_date): # Set Dublin Core Date element - date resource becomes effective. self.effective_date = self._datify(effective_date) security.declareProtected(ModifyPortalContent, 'setExpirationDate') def setExpirationDate(self, expiration_date): # Set Dublin Core Date element - date resource expires. self.expiration_date = self._datify(expiration_date) security.declareProtected(ModifyPortalContent, 'setFormat') def setFormat(self, format): # Set Dublin Core Format element - resource format. self.format = format security.declareProtected(ModifyPortalContent, 'setLanguage') def setLanguage(self, language): # Set Dublin Core Language element - resource language. self.language = language security.declareProtected(ModifyPortalContent, 'setRights') def setRights(self, rights): # Set Dublin Core Rights element - resource copyright. self.rights = rights # # Management tab methods # security.declarePrivate('_editMetadata') def _editMetadata(self, title=_marker, subject=_marker, description=_marker, contributors=_marker, effective_date=_marker, expiration_date=_marker, format=_marker, language=_marker, rights=_marker): # Update the editable metadata for this resource. if title is not _marker: self.setTitle(title) if subject is not _marker: self.setSubject(subject) if description is not _marker: self.setDescription(description) if contributors is not _marker: self.setContributors(contributors) if effective_date is not _marker: self.setEffectiveDate(effective_date) if expiration_date is not _marker: self.setExpirationDate(expiration_date) if format is not _marker: self.setFormat(format) if language is not _marker: self.setLanguage(language) if rights is not _marker: self.setRights(rights) security.declareProtected(ModifyPortalContent, 'manage_metadata') manage_metadata = DTMLFile('zmi_metadata', WWW_DIR) security.declareProtected(ModifyPortalContent, 'manage_editMetadata') def manage_editMetadata(self, title, subject, description, contributors, effective_date, expiration_date, format, language, rights, REQUEST): """ Update metadata from the ZMI. """ self._editMetadata(title, subject, description, contributors, effective_date, expiration_date, format, language, rights) REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_metadata' + '?manage_tabs_message=Metadata+updated.') security.declareProtected(ModifyPortalContent, 'editMetadata') def editMetadata(self, title='', subject=(), description='', contributors=(), effective_date=None, expiration_date=None, format='text/html', language='en-US', rights=''): # Need to add check for webDAV locked resource for TTW methods. # As per bug #69, we can't assume they use the webdav # locking interface, and fail gracefully if they don't. if hasattr(self, 'failIfLocked'): self.failIfLocked() self._editMetadata(title=title, subject=subject, description=description, contributors=contributors, effective_date=effective_date, expiration_date=expiration_date, format=format, language=language, rights=rights) self.reindexObject()
class BTreeFolder2Base(Persistent): """Base for BTree-based folders. """ security = ClassSecurityInfo() manage_options = (({ 'label': 'Contents', 'action': 'manage_main' }, ) + Folder.manage_options[1:]) security.declareProtected(view_management_screens, 'manage_main') manage_main = DTMLFile('contents', globals()) _tree = None # OOBTree: { id -> object } _count = None # A BTrees.Length _v_nextid = 0 # The integer component of the next generated ID _mt_index = None # OOBTree: { meta_type -> OIBTree: { id -> 1 } } title = '' # superValues() looks for the _objects attribute, but the implementation # would be inefficient, so superValues() support is disabled. _objects = () def __init__(self, id=None): if id is not None: self.id = id self._initBTrees() def _initBTrees(self): self._tree = OOBTree() self._count = Length() self._mt_index = OOBTree() def _populateFromFolder(self, source): """Fill this folder with the contents of another folder. """ for name in source.objectIds(): value = source._getOb(name, None) if value is not None: self._setOb(name, aq_base(value)) security.declareProtected(view_management_screens, 'manage_fixCount') def manage_fixCount(self): """Calls self._fixCount() and reports the result as text. """ old, new = self._fixCount() path = '/'.join(self.getPhysicalPath()) if old == new: return "No count mismatch detected in BTreeFolder2 at %s." % path else: return ("Fixed count mismatch in BTreeFolder2 at %s. " "Count was %d; corrected to %d" % (path, old, new)) def _fixCount(self): """Checks if the value of self._count disagrees with len(self.objectIds()). If so, corrects self._count. Returns the old and new count values. If old==new, no correction was performed. """ old = self._count() new = len(self.objectIds()) if old != new: self._count.set(new) return old, new security.declareProtected(view_management_screens, 'manage_cleanup') def manage_cleanup(self): """Calls self._cleanup() and reports the result as text. """ v = self._cleanup() path = '/'.join(self.getPhysicalPath()) if v: return "No damage detected in BTreeFolder2 at %s." % path else: return ("Fixed BTreeFolder2 at %s. " "See the log for more details." % path) def _cleanup(self): """Cleans up errors in the BTrees. Certain ZODB bugs have caused BTrees to become slightly insane. Fortunately, there is a way to clean up damaged BTrees that always seems to work: make a new BTree containing the items() of the old one. Returns 1 if no damage was detected, or 0 if damage was detected and fixed. """ from BTrees.check import check path = '/'.join(self.getPhysicalPath()) try: check(self._tree) for key in self._tree.keys(): if key not in self._tree: raise AssertionError("Missing value for key: %s" % repr(key)) check(self._mt_index) for key, value in self._mt_index.items(): if (key not in self._mt_index or self._mt_index[key] is not value): raise AssertionError( "Missing or incorrect meta_type index: %s" % repr(key)) check(value) for k in value.keys(): if k not in value: raise AssertionError( "Missing values for meta_type index: %s" % repr(key)) return 1 except AssertionError: LOG.warn('Detected damage to %s. Fixing now.' % path, exc_info=sys.exc_info()) try: self._tree = OOBTree(self._tree) mt_index = OOBTree() for key, value in self._mt_index.items(): mt_index[key] = OIBTree(value) self._mt_index = mt_index except: LOG.error('Failed to fix %s.' % path, exc_info=sys.exc_info()) raise else: LOG.info('Fixed %s.' % path) return 0 def _getOb(self, id, default=_marker): """Return the named object from the folder. """ tree = self._tree if default is _marker: ob = tree[id] return ob.__of__(self) else: ob = tree.get(id, _marker) if ob is _marker: return default else: return ob.__of__(self) security.declareProtected(access_contents_information, 'get') def get(self, name, default=None): return self._getOb(name, default) def __getitem__(self, name): return self._getOb(name) def __getattr__(self, name): # Boo hoo hoo! Zope 2 prefers implicit acquisition over traversal # to subitems, and __bobo_traverse__ hooks don't work with # restrictedTraverse() unless __getattr__() is also present. # Oh well. res = self._tree.get(name) if res is None: raise AttributeError(name) return res def _setOb(self, id, object): """Store the named object in the folder. """ tree = self._tree if id in tree: raise KeyError('There is already an item named "%s".' % id) tree[id] = object self._count.change(1) # Update the meta type index. mti = self._mt_index meta_type = getattr(object, 'meta_type', None) if meta_type is not None: ids = mti.get(meta_type, None) if ids is None: ids = OIBTree() mti[meta_type] = ids ids[id] = 1 def _delOb(self, id): """Remove the named object from the folder. """ tree = self._tree meta_type = getattr(tree[id], 'meta_type', None) del tree[id] self._count.change(-1) # Update the meta type index. if meta_type is not None: mti = self._mt_index ids = mti.get(meta_type, None) if ids is not None and id in ids: del ids[id] if not ids: # Removed the last object of this meta_type. # Prune the index. del mti[meta_type] security.declareProtected(view_management_screens, 'getBatchObjectListing') def getBatchObjectListing(self, REQUEST=None): """Return a structure for a page template to show the list of objects. """ if REQUEST is None: REQUEST = {} pref_rows = int(REQUEST.get('dtpref_rows', 20)) b_start = int(REQUEST.get('b_start', 1)) b_count = int(REQUEST.get('b_count', 1000)) b_end = b_start + b_count - 1 url = self.absolute_url() + '/manage_main' idlist = self.objectIds() # Pre-sorted. count = self.objectCount() if b_end < count: next_url = url + '?b_start=%d' % (b_start + b_count) else: b_end = count next_url = '' if b_start > 1: prev_url = url + '?b_start=%d' % max(b_start - b_count, 1) else: prev_url = '' formatted = [] formatted.append(listtext0 % pref_rows) for i in range(b_start - 1, b_end): optID = escape(idlist[i]) formatted.append(listtext1 % (escape(optID, quote=1), optID)) formatted.append(listtext2) return { 'b_start': b_start, 'b_end': b_end, 'prev_batch_url': prev_url, 'next_batch_url': next_url, 'formatted_list': ''.join(formatted) } security.declareProtected(view_management_screens, 'manage_object_workspace') def manage_object_workspace(self, ids=(), REQUEST=None): '''Redirects to the workspace of the first object in the list.''' if ids and REQUEST is not None: REQUEST.RESPONSE.redirect('%s/%s/manage_workspace' % (self.absolute_url(), quote(ids[0]))) else: return self.manage_main(self, REQUEST) security.declareProtected(access_contents_information, 'tpValues') def tpValues(self): """Ensures the items don't show up in the left pane. """ return () security.declareProtected(access_contents_information, 'objectCount') def objectCount(self): """Returns the number of items in the folder.""" return self._count() def __len__(self): return self.objectCount() def __nonzero__(self): return True security.declareProtected(access_contents_information, 'has_key') def has_key(self, id): """Indicates whether the folder has an item by ID. """ return id in self._tree # backward compatibility hasObject = has_key security.declareProtected(access_contents_information, 'objectIds') def objectIds(self, spec=None): # Returns a list of subobject ids of the current object. # If 'spec' is specified, returns objects whose meta_type # matches 'spec'. if spec is None: return self._tree.keys() if isinstance(spec, str): spec = [spec] set = None mti = self._mt_index for meta_type in spec: ids = mti.get(meta_type, None) if ids is not None: set = union(set, ids) if set is None: return () else: return set.keys() security.declareProtected(access_contents_information, 'keys') def keys(self): return self._tree.keys() def __contains__(self, name): return name in self._tree def __iter__(self): return iter(self.objectIds()) security.declareProtected(access_contents_information, 'objectValues') def objectValues(self, spec=None): # Returns a list of actual subobjects of the current object. # If 'spec' is specified, returns only objects whose meta_type # match 'spec'. return LazyMap(self._getOb, self.objectIds(spec)) security.declareProtected(access_contents_information, 'values') def values(self): return LazyMap(self._getOb, self._tree.keys()) security.declareProtected(access_contents_information, 'objectItems') def objectItems(self, spec=None): # Returns a list of (id, subobject) tuples of the current object. # If 'spec' is specified, returns only objects whose meta_type match # 'spec' return LazyMap(lambda id, _getOb=self._getOb: (id, _getOb(id)), self.objectIds(spec)) security.declareProtected(access_contents_information, 'items') def items(self): return LazyMap(lambda id, _getOb=self._getOb: (id, _getOb(id)), self._tree.keys()) security.declareProtected(access_contents_information, 'objectMap') def objectMap(self): # Returns a tuple of mappings containing subobject meta-data. return LazyMap( lambda (k, v): { 'id': k, 'meta_type': getattr(v, 'meta_type', None) }, self._tree.items(), self._count()) security.declareProtected(access_contents_information, 'objectIds_d') def objectIds_d(self, t=None): ids = self.objectIds(t) res = {} for id in ids: res[id] = 1 return res security.declareProtected(access_contents_information, 'objectMap_d') def objectMap_d(self, t=None): return self.objectMap() def _checkId(self, id, allow_dup=0): if not allow_dup and id in self: raise BadRequestException('The id "%s" is invalid--' 'it is already in use.' % id) def _setObject(self, id, object, roles=None, user=None, set_owner=1, suppress_events=False): ob = object # better name, keep original function signature v = self._checkId(id) if v is not None: id = v # If an object by the given id already exists, remove it. if id in self: self._delObject(id) if not suppress_events: notify(ObjectWillBeAddedEvent(ob, self, id)) self._setOb(id, ob) ob = self._getOb(id) if set_owner: # TODO: eventify manage_fixupOwnershipAfterAdd # This will be called for a copy/clone, or a normal _setObject. ob.manage_fixupOwnershipAfterAdd() # Try to give user the local role "Owner", but only if # no local roles have been set on the object yet. if getattr(ob, '__ac_local_roles__', _marker) is None: user = getSecurityManager().getUser() if user is not None: userid = user.getId() if userid is not None: ob.manage_setLocalRoles(userid, ['Owner']) if not suppress_events: notify(ObjectAddedEvent(ob, self, id)) notifyContainerModified(self) compatibilityCall('manage_afterAdd', ob, ob, self) return id def __setitem__(self, key, value): return self._setObject(key, value) def _delObject(self, id, dp=1, suppress_events=False): ob = self._getOb(id) compatibilityCall('manage_beforeDelete', ob, ob, self) if not suppress_events: notify(ObjectWillBeRemovedEvent(ob, self, id)) self._delOb(id) if not suppress_events: notify(ObjectRemovedEvent(ob, self, id)) notifyContainerModified(self) def __delitem__(self, name): return self._delObject(id=name) # Utility for generating unique IDs. security.declareProtected(access_contents_information, 'generateId') def generateId(self, prefix='item', suffix='', rand_ceiling=999999999): """Returns an ID not used yet by this folder. The ID is unlikely to collide with other threads and clients. The IDs are sequential to optimize access to objects that are likely to have some relation. """ tree = self._tree n = self._v_nextid attempt = 0 while 1: if n % 4000 != 0 and n <= rand_ceiling: id = '%s%d%s' % (prefix, n, suffix) if id not in tree: break n = randint(1, rand_ceiling) attempt = attempt + 1 if attempt > MAX_UNIQUEID_ATTEMPTS: # Prevent denial of service raise ExhaustedUniqueIdsError self._v_nextid = n + 1 return id
class WorklistDefinition(SimpleItem): """Worklist definiton""" meta_type = 'Worklist' security = ClassSecurityInfo() security.declareObjectProtected(ManagePortal) description = '' var_matches = None # Compared with catalog when set. actbox_name = '' actbox_url = '' actbox_icon = '' actbox_category = 'global' guard = None manage_options = ( {'label': 'Properties', 'action': 'manage_properties'}, ) def __init__(self, id): self.id = id def getGuard(self): if self.guard is not None: return self.guard else: return Guard().__of__(self) # Create a temporary guard. def getGuardSummary(self): res = None if self.guard is not None: res = self.guard.getSummary() return res def getWorkflow(self): return aq_parent(aq_inner(aq_parent(aq_inner(self)))) def getAvailableCatalogVars(self): res = [] res.append(self.getWorkflow().state_var) for id, vdef in self.getWorkflow().variables.items(): if vdef.for_catalog: res.append(id) res.sort() return res def getVarMatchKeys(self): if self.var_matches: return self.var_matches.keys() else: return [] def getVarMatch(self, id): if self.var_matches: matches = self.var_matches.get(id, ()) if not isinstance(matches, (tuple, Expression)): # Old version, convert it. matches = (matches,) self.var_matches[id] = matches return matches else: return () def getVarMatchText(self, id): values = self.getVarMatch(id) if isinstance(values, Expression): return values.text return '; '.join(values) _properties_form = DTMLFile('worklist_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, actbox_name='', actbox_url='', actbox_category='global', actbox_icon='', props=None, REQUEST=None): ''' ''' if props is None: props = REQUEST self.description = str(description) for key in self.getAvailableCatalogVars(): # Populate var_matches. fieldname = 'var_match_%s' % key v = props.get(fieldname, '') if v: if not self.var_matches: self.var_matches = PersistentMapping() if tales_re.match(v).group(1): # Found a TALES prefix self.var_matches[key] = Expression(v) else: # Falling back to formatted string v = [ var.strip() for var in v.split(';') ] self.var_matches[key] = tuple(v) else: if self.var_matches and self.var_matches.has_key(key): del self.var_matches[key] self.actbox_name = str(actbox_name) self.actbox_url = str(actbox_url) self.actbox_category = str(actbox_category) self.actbox_icon = str(actbox_icon) g = Guard() if g.changeFromProperties(props or REQUEST): self.guard = g else: self.guard = None if REQUEST is not None: return self.manage_properties(REQUEST, 'Properties changed.') def search(self, info=None, **kw): """ Perform the search corresponding to this worklist Returns sequence of ZCatalog brains - info is a mapping for resolving formatted string variable references - additional keyword/value pairs may be used to restrict the query """ if not self.var_matches: return if info is None: info = {} criteria = {} for key, values in self.var_matches.items(): if isinstance(values, Expression): wf = self.getWorkflow() portal = wf._getPortalRoot() context = createExprContext(StateChangeInfo(portal, wf)) criteria[key] = values(context) else: criteria[key] = [x % info for x in values] criteria.update(kw) ctool = getUtility(ICatalogTool) return ctool.searchResults(**criteria)
class ActionsTool(UniqueObject, IFAwareObjectManager, OrderedFolder, ActionProviderBase): """ Weave together the various sources of "actions" which are apropos to the current user and context. """ id = 'portal_actions' meta_type = 'CMF Actions Tool' zmi_icon = 'fas fa-project-diagram' _product_interfaces = (IActionCategory,) action_providers = ('portal_types', 'portal_workflow', 'portal_actions') security = ClassSecurityInfo() manage_options = ((OrderedFolder.manage_options[0], ActionProviderBase.manage_options[0], {'label': 'Action Providers', 'action': 'manage_actionProviders'}, {'label': 'Overview', 'action': 'manage_overview'}) + OrderedFolder.manage_options[2:]) # # ZMI methods # security.declareProtected(ManagePortal, 'manage_overview') manage_overview = DTMLFile('explainActionsTool', _dtmldir) manage_actionProviders = DTMLFile('manageActionProviders', _dtmldir) @security.protected(ManagePortal) def manage_aproviders(self, apname='', chosen=(), add_provider=0, del_provider=0, REQUEST=None): """ Manage action providers through-the-web. """ providers = list(self.listActionProviders()) new_providers = [] if add_provider: providers.append(apname) elif del_provider: for item in providers: if item not in chosen: new_providers.append(item) providers = new_providers self.action_providers = tuple(providers) if REQUEST is not None: return self.manage_actionProviders( self, REQUEST, manage_tabs_message='Providers changed.') @security.protected(ManagePortal) def manage_editActionsForm(self, REQUEST, manage_tabs_message=None): """ Show the 'Actions' management tab. """ actions = [ai.getMapping() for ai in self._actions] # possible_permissions is in AccessControl.Role.RoleManager. pp = self.possible_permissions() return self._actions_form(self, REQUEST, actions=actions, possible_permissions=pp, management_view='Actions', manage_tabs_message=manage_tabs_message) # # ActionProvider interface # @security.private def listActions(self, info=None, object=None): """ List all the actions defined by a provider. """ oldstyle_actions = self._actions or () if oldstyle_actions: warn('Old-style actions are deprecated and will be removed in CMF ' '2.4. Use Action and Action Category objects instead.', DeprecationWarning, stacklevel=2) actions = list(oldstyle_actions) for category in self.objectValues(): actions.extend(category.listActions()) return tuple(actions) # # Programmatically manipulate the list of action providers # @security.protected(ManagePortal) def listActionProviders(self): """ List the ids of all Action Providers queried by this tool. """ return self.action_providers @security.protected(ManagePortal) def addActionProvider(self, provider_name): """ Add an Action Provider id to the providers queried by this tool. """ if getToolByName(self, provider_name, None) is None: return ap = list(self.action_providers) if provider_name not in ap: ap.append(provider_name) self.action_providers = tuple(ap) @security.protected(ManagePortal) def deleteActionProvider(self, provider_name): """ Delete an Action Provider id from providers queried by this tool. """ ap = list(self.action_providers) if provider_name in ap: ap.remove(provider_name) self.action_providers = tuple(ap) # # 'portal_actions' interface methods # @security.public def listFilteredActionsFor(self, object=None): """ List all actions available to the user. """ actions = [] # Include actions from specific tools. for provider_name in self.listActionProviders(): provider = getToolByName(self, provider_name) if IActionProvider.providedBy(provider): actions.extend(provider.listActionInfos(object=object)) # Include actions from object. if object is not None: if IActionProvider.providedBy(object): actions.extend(object.listActionInfos(object=object)) # Reorganize the actions by category. filtered_actions = {'user': [], 'folder': [], 'object': [], 'global': [], 'workflow': []} for action in actions: catlist = filtered_actions.setdefault(action['category'], []) catlist.append(action) return filtered_actions
class CookieAuthHelper(Folder, BasePlugin): """ Multi-plugin for managing details of Cookie Authentication. """ meta_type = 'Cookie Auth Helper' cookie_name = '__ginger_snap' login_path = 'login_form' security = ClassSecurityInfo() _properties = ({ 'id': 'title', 'label': 'Title', 'type': 'string', 'mode': 'w' }, { 'id': 'cookie_name', 'label': 'Cookie Name', 'type': 'string', 'mode': 'w' }, { 'id': 'login_path', 'label': 'Login Form', 'type': 'string', 'mode': 'w' }) manage_options = (BasePlugin.manage_options[:1] + Folder.manage_options[:1] + Folder.manage_options[2:]) def __init__(self, id, title=None, cookie_name=''): self._setId(id) self.title = title if cookie_name: self.cookie_name = cookie_name security.declarePrivate('extractCredentials') def extractCredentials(self, request): """ Extract credentials from cookie or 'request'. """ creds = {} cookie = request.get(self.cookie_name, '') if cookie: cookie_val = decodestring(unquote(cookie)) login, password = cookie_val.split(':') creds['login'] = login creds['password'] = password else: # Look in the request for the names coming from the login form login = request.get('__ac_name', '') password = request.get('__ac_password', '') if login: creds['login'] = login creds['password'] = password if creds: creds['remote_host'] = request.get('REMOTE_HOST', '') try: creds['remote_address'] = request.getClientAddr() except AttributeError: creds['remote_address'] = request.get('REMOTE_ADDR', '') return creds security.declarePrivate('challenge') def challenge(self, request, response, **kw): """ Challenge the user for credentials. """ return self.unauthorized() security.declarePrivate('updateCredentials') def updateCredentials(self, request, response, login, new_password): """ Respond to change of credentials (NOOP for basic auth). """ cookie_val = encodestring('%s:%s' % (login, new_password)) cookie_val = cookie_val.rstrip() response.setCookie(self.cookie_name, quote(cookie_val), path='/') security.declarePrivate('resetCredentials') def resetCredentials(self, request, response): """ Raise unauthorized to tell browser to clear credentials. """ response.expireCookie(self.cookie_name, path='/') security.declarePrivate('manage_afterAdd') def manage_afterAdd(self, item, container): """ Setup tasks upon instantiation """ login_form = ZopePageTemplate(id='login_form', text=BASIC_LOGIN_FORM) login_form.title = 'Login Form' login_form.manage_permission(view, roles=['Anonymous'], acquire=1) self._setObject('login_form', login_form, set_owner=0) security.declarePrivate('unauthorized') def unauthorized(self): req = self.REQUEST resp = req['RESPONSE'] # If we set the auth cookie before, delete it now. if resp.cookies.has_key(self.cookie_name): del resp.cookies[self.cookie_name] # Redirect if desired. url = self.getLoginURL() if url is not None: came_from = req.get('came_from', None) if came_from is None: came_from = req.get('URL', '') query = req.get('QUERY_STRING') if query: if not query.startswith('?'): query = '?' + query came_from = came_from + query else: # If came_from contains a value it means the user # must be coming through here a second time # Reasons could be typos when providing credentials # or a redirect loop (see below) req_url = req.get('URL', '') if req_url and req_url == url: # Oops... The login_form cannot be reached by the user - # it might be protected itself due to misconfiguration - # the only sane thing to do is to give up because we are # in an endless redirect loop. return 0 url = url + '?came_from=%s' % quote(came_from) resp.redirect(url, lock=1) return 1 # Could not challenge. return 0 security.declarePrivate('getLoginURL') def getLoginURL(self): """ Where to send people for logging in """ if self.login_path.startswith('/'): return self.login_path elif self.login_path != '': return '%s/%s' % (self.absolute_url(), self.login_path) else: return None security.declarePublic('login') def login(self): """ Set a cookie and redirect to the url that we tried to authenticate against originally. """ request = self.REQUEST response = request['RESPONSE'] login = request.get('__ac_name', '') password = request.get('__ac_password', '') # In order to use the CookieAuthHelper for its nice login page # facility but store and manage credentials somewhere else we need # to make sure that upon login only plugins activated as # IUpdateCredentialPlugins get their updateCredentials method # called. If the method is called on the CookieAuthHelper it will # simply set its own auth cookie, to the exclusion of any other # plugins that might want to store the credentials. pas_instance = self._getPAS() if pas_instance is not None: pas_instance.updateCredentials(request, response, login, password) came_from = request.form['came_from'] return response.redirect(came_from)
class Item( PathReprProvider, Base, Navigation, Resource, LockableItem, CopySource, Tabs, Traversable, Owned ): """A common base class for simple, non-container objects.""" zmi_icon = 'far fa-file' zmi_show_add_dialog = True security = ClassSecurityInfo() isPrincipiaFolderish = 0 isTopLevelPrincipiaApplicationObject = 0 manage_options = ({'label': 'Interfaces', 'action': 'manage_interfaces'},) def manage_afterAdd(self, item, container): pass manage_afterAdd.__five_method__ = True def manage_beforeDelete(self, item, container): pass manage_beforeDelete.__five_method__ = True def manage_afterClone(self, item): pass manage_afterClone.__five_method__ = True # Direct use of the 'id' attribute is deprecated - use getId() id = '' @security.public def getId(self): """Return the id of the object as a string. This method should be used in preference to accessing an id attribute of an object directly. The getId method is public. """ name = self.id if name is not None: return name return self.__name__ # Alias id to __name__, which will make tracebacks a good bit nicer: __name__ = ComputedAttribute(lambda self: self.id) # Meta type used for selecting all objects of a given type. meta_type = 'simple item' # Default title. title = '' # Default propertysheet info: __propsets__ = () # Attributes that must be acquired REQUEST = Acquired # Allow (reluctantly) access to unprotected attributes __allow_access_to_unprotected_subobjects__ = 1 def title_or_id(self): """Return the title if it is not blank and the id otherwise. """ title = self.title if callable(title): title = title() if title: return title return self.getId() def title_and_id(self): """Return the title if it is not blank and the id otherwise. If the title is not blank, then the id is included in parens. """ title = self.title if callable(title): title = title() id = self.getId() # Make sure we don't blindly concatenate encoded and unencoded data if title and type(id) is not type(title): if isinstance(id, bytes): id = id.decode(default_encoding) if isinstance(title, bytes): title = title.decode(default_encoding) return title and ("%s (%s)" % (title, id)) or id def this(self): # Handy way to talk to ourselves in document templates. return self def tpURL(self): # My URL as used by tree tag return self.getId() def tpValues(self): # My sub-objects as used by the tree tag return () _manage_editedDialog = DTMLFile('dtml/editedDialog', globals()) def manage_editedDialog(self, REQUEST, **args): return self._manage_editedDialog(self, REQUEST, **args) def raise_standardErrorMessage( self, client=None, REQUEST={}, error_type=None, error_value=None, tb=None, error_tb=None, error_message='', tagSearch=re.compile(r'[a-zA-Z]>').search, error_log_url='' ): try: if error_type is None: error_type = sys.exc_info()[0] if error_value is None: error_value = sys.exc_info()[1] # allow for a few different traceback options if tb is None and error_tb is None: tb = sys.exc_info()[2] if not isinstance(tb, str) and (error_tb is None): error_tb = pretty_tb(error_type, error_value, tb) elif isinstance(tb, str) and not error_tb: error_tb = tb if hasattr(self, '_v_eek'): # Stop if there is recursion. raise error_value.with_traceback(tb) self._v_eek = 1 if hasattr(error_type, '__name__'): error_name = error_type.__name__ else: error_name = 'Unknown' if not error_message: try: s = ustr(error_value) except Exception: s = error_value try: match = tagSearch(s) except TypeError: match = None if match is not None: error_message = error_value if client is None: client = self if not REQUEST: REQUEST = aq_acquire(self, 'REQUEST') try: s = aq_acquire(client, 'standard_error_message') # For backward compatibility, we pass 'error_name' as # 'error_type' here as historically this has always # been a string. kwargs = { 'error_type': error_name, 'error_value': error_value, 'error_tb': error_tb, 'error_traceback': error_tb, 'error_message': error_message, 'error_log_url': error_log_url, } if getattr(aq_base(s), 'isDocTemp', 0): v = s(client, REQUEST, **kwargs) elif callable(s): v = s(**kwargs) else: v = HTML.__call__(s, client, REQUEST, **kwargs) except Exception: logger.error( 'Exception while rendering an error message', exc_info=True ) try: strv = repr(error_value) # quotes tainted strings except Exception: strv = ('<unprintable %s object>' % str(type(error_value).__name__)) v = strv + ( (" (Also, the following error occurred while attempting " "to render the standard error message, please see the " "event log for full details: %s)") % ( html_quote(sys.exc_info()[1]), )) # If we've been asked to handle errors, just return the rendered # exception and let the ZPublisher Exception Hook deal with it. return error_type, v, tb finally: if hasattr(self, '_v_eek'): del self._v_eek tb = None def manage(self, URL1): """ """ raise Redirect("%s/manage_main" % URL1) # This keeps simple items from acquiring their parents # objectValues, etc., when used in simple tree tags. def objectValues(self, spec=None): return () objectIds = objectItems = objectValues def __len__(self): return 1 @security.protected(access_contents_information) def getParentNode(self): """The parent of this node. All nodes except Document DocumentFragment and Attr may have a parent""" return getattr(self, '__parent__', None)
class TarballImportContext(BaseContext): security = ClassSecurityInfo() def __init__(self, tool, archive_bits, encoding=None, should_purge=False): BaseContext.__init__(self, tool, encoding) self._archive_stream = cStringIO(archive_bits) self._archive = TarFile.open('foo.bar', 'r:gz', self._archive_stream) self._should_purge = bool(should_purge) def readDataFile(self, filename, subdir=None): """ See IImportContext. """ if subdir is not None: filename = '/'.join((subdir, filename)) try: file = self._archive.extractfile(filename) except KeyError: return None return file.read() def getLastModified(self, path): """ See IImportContext. """ info = self._getTarInfo(path) return info and DateTime(info.mtime) or None def isDirectory(self, path): """ See IImportContext. """ info = self._getTarInfo(path) if info is not None: return info.isdir() def listDirectory(self, path, skip=SKIPPED_FILES, skip_suffixes=SKIPPED_SUFFIXES): """ See IImportContext. """ if path is None: # root is special case: no leading '/' path = '' else: if not self.isDirectory(path): return None if not path.endswith('/'): path = path + '/' pfx_len = len(path) names = [] for info in self._archive.getmembers(): name = info.name.rstrip('/') if name == path or not name.startswith(path): continue name = name[pfx_len:] if '/' in name: # filter out items in subdirs continue if name in skip: continue if [s for s in skip_suffixes if name.endswith(s)]: continue names.append(name) return names def shouldPurge(self): """ See IImportContext. """ return self._should_purge def _getTarInfo(self, path): if path.endswith('/'): path = path[:-1] try: return self._archive.getmember(path) except KeyError: pass try: return self._archive.getmember(path + '/') except KeyError: return None
class DTMLMethod(RestrictedDTML, HTML, Implicit, RoleManager, Item_w__name__, Cacheable): """ DocumentTemplate.HTML objects that act as methods of their containers. """ meta_type = 'DTML Method' _proxy_roles = () index_html = None # Prevent accidental acquisition _cache_namespace_keys = () security = ClassSecurityInfo() security.declareObjectProtected(View) __code__ = Code() __code__.co_varnames = 'self', 'REQUEST', 'RESPONSE' __code__.co_argcount = 3 __defaults__ = None manage_options = (( { 'label': 'Edit', 'action': 'manage_main' }, { 'label': 'Proxy', 'action': 'manage_proxyForm' }, ) + RoleManager.manage_options + Item_w__name__.manage_options + Cacheable.manage_options) # More reasonable default for content-type for http HEAD requests. default_content_type = 'text/html' security.declareProtected(View, '__call__') def __call__(self, client=None, REQUEST={}, RESPONSE=None, **kw): """Render using the given client object o If client is not passed, we are being called as a sub-template: don't do any error propagation. o If supplied, use the REQUEST mapping, Response, and key word arguments. """ if not self._cache_namespace_keys: data = self.ZCacheable_get(default=_marker) if data is not _marker: if (IStreamIterator.isImplementedBy(data) and RESPONSE is not None): # This is a stream iterator and we need to set some # headers now before giving it to medusa headers_get = RESPONSE.headers.get if headers_get('content-length', None) is None: RESPONSE.setHeader('content-length', len(data)) if (headers_get('content-type', None) is None and headers_get('Content-type', None) is None): ct = (self.__dict__.get('content_type') or self.default_content_type) RESPONSE.setHeader('content-type', ct) # Return cached results. return data __traceback_supplement__ = (PathTracebackSupplement, self) kw['document_id'] = self.getId() kw['document_title'] = self.title security = getSecurityManager() security.addContext(self) if 'validate' in self.__dict__: first_time_through = 0 else: self.__dict__['validate'] = security.DTMLValidate first_time_through = 1 try: if client is None: # Called as subtemplate, so don't need error propagation! r = HTML.__call__(self, client, REQUEST, **kw) if RESPONSE is None: result = r else: result = decapitate(r, RESPONSE) if not self._cache_namespace_keys: self.ZCacheable_set(result) return result r = HTML.__call__(self, client, REQUEST, **kw) if RESPONSE is None or not isinstance(r, str): if not self._cache_namespace_keys: self.ZCacheable_set(r) return r finally: security.removeContext(self) if first_time_through: del self.__dict__['validate'] have_key = RESPONSE.headers.__contains__ if not (have_key('content-type') or have_key('Content-Type')): if 'content_type' in self.__dict__: c = self.content_type else: c, e = guess_content_type(self.getId(), r.encode('utf-8')) RESPONSE.setHeader('Content-Type', c) result = decapitate(r, RESPONSE) if not self._cache_namespace_keys: self.ZCacheable_set(result) return result def validate(self, inst, parent, name, value, md=None): return getSecurityManager().validate(inst, parent, name, value) def ZDocumentTemplate_beforeRender(self, md, default): # Tries to get a cached value. if self._cache_namespace_keys: # Use the specified keys from the namespace to identify a # cache entry. kw = {} for key in self._cache_namespace_keys: try: val = md[key] except: val = None kw[key] = val return self.ZCacheable_get(keywords=kw, default=default) return default def ZDocumentTemplate_afterRender(self, md, result): # Tries to set a cache value. if self._cache_namespace_keys: kw = {} for key in self._cache_namespace_keys: try: val = md[key] except: val = None kw[key] = val self.ZCacheable_set(result, keywords=kw) security.declareProtected(change_dtml_methods, 'ZCacheable_configHTML') ZCacheable_configHTML = DTMLFile('dtml/cacheNamespaceKeys', globals()) security.declareProtected(change_dtml_methods, 'getCacheNamespaceKeys') def getCacheNamespaceKeys(self): # Return the cacheNamespaceKeys. return self._cache_namespace_keys security.declareProtected(change_dtml_methods, 'setCacheNamespaceKeys') def setCacheNamespaceKeys(self, keys, REQUEST=None): # Set the list of names looked up to provide a cache key. ks = [] for key in keys: key = str(key).strip() if key: ks.append(key) self._cache_namespace_keys = tuple(ks) if REQUEST is not None: return self.ZCacheable_manage(self, REQUEST) security.declareProtected(View, 'get_size') def get_size(self): return len(self.raw) # deprecated; use get_size! getSize = get_size security.declareProtected(change_dtml_methods, 'manage') security.declareProtected(change_dtml_methods, 'manage_editForm') manage_editForm = DTMLFile('dtml/documentEdit', globals()) manage_editForm._setName('manage_editForm') # deprecated! manage_uploadForm = manage_editForm security.declareProtected(change_dtml_methods, 'manage_main') manage = manage_main = manage_editDocument = manage_editForm security.declareProtected(change_proxy_roles, 'manage_proxyForm') manage_proxyForm = DTMLFile('dtml/documentProxy', globals()) security.declareProtected(change_dtml_methods, 'manage_edit') def manage_edit(self, data, title, SUBMIT='Change', REQUEST=None): """ Replace contents with 'data', title with 'title'. """ self._validateProxy(REQUEST) if self.wl_isLocked(): raise ResourceLockedError('This item is locked.') self.title = str(title) if isinstance(data, TaintedString): data = data.quoted() if hasattr(data, 'read'): data = data.read() self.munge(data) self.ZCacheable_invalidate() if REQUEST: message = "Saved changes." return self.manage_main(self, REQUEST, manage_tabs_message=message) security.declareProtected(change_dtml_methods, 'manage_upload') def manage_upload(self, file='', REQUEST=None): """ Replace the contents of the document with the text in 'file'. """ self._validateProxy(REQUEST) if self.wl_isLocked(): raise ResourceLockedError('This DTML Method is locked.') if not isinstance(file, binary_type): if REQUEST and not file: raise ValueError('No file specified') file = file.read() self.munge(file) self.ZCacheable_invalidate() if REQUEST: message = "Saved changes." return self.manage_main(self, REQUEST, manage_tabs_message=message) def manage_haveProxy(self, r): return r in self._proxy_roles def _validateProxy(self, request, roles=None): if roles is None: roles = self._proxy_roles if not roles: return user = u = getSecurityManager().getUser() user = user.allowed for r in roles: if r and not user(self, (r, )): user = None break if user is not None: return raise Forbidden( 'You are not authorized to change <em>%s</em> because you ' 'do not have proxy roles.\n<!--%s, %s-->' % (self.__name__, u, roles)) security.declareProtected(change_proxy_roles, 'manage_proxy') @requestmethod('POST') def manage_proxy(self, roles=(), REQUEST=None): "Change Proxy Roles" self._validateProxy(REQUEST, roles) self._validateProxy(REQUEST) self._proxy_roles = tuple(roles) if REQUEST: message = "Saved changes." return self.manage_proxyForm(self, REQUEST, manage_tabs_message=message) security.declareProtected(view_management_screens, 'PrincipiaSearchSource') def PrincipiaSearchSource(self): # Support for searching - the document's contents are searched. return self.read() security.declareProtected(view_management_screens, 'document_src') def document_src(self, REQUEST=None, RESPONSE=None): # Return unprocessed document source. if RESPONSE is not None: RESPONSE.setHeader('Content-Type', 'text/plain') return self.read() if bbb.HAS_ZSERVER: security.declareProtected(change_dtml_methods, 'PUT') def PUT(self, REQUEST, RESPONSE): """ Handle FTP / HTTP PUT requests. """ self.dav__init(REQUEST, RESPONSE) self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1) body = REQUEST.get('BODY', '') self._validateProxy(REQUEST) self.munge(body) self.ZCacheable_invalidate() RESPONSE.setStatus(204) return RESPONSE security.declareProtected(ftp_access, 'manage_FTPstat') security.declareProtected(ftp_access, 'manage_FTPlist') security.declareProtected(ftp_access, 'manage_FTPget') def manage_FTPget(self): """ Get source for FTP download. """ return self.read()
from ZPublisher.HTTPRequest import HTTPRequest ATTEMPT_NONE = 0 # No attempt at authentication ATTEMPT_LOGIN = 1 # Attempt to log in ATTEMPT_RESUME = 2 # Attempt to resume session from base64 import standard_b64encode, standard_b64decode from DateTime import DateTime class PatchedCookieCrumbler(CookieCrumbler): """ This class is only for backward compatibility. """ pass security = ClassSecurityInfo() def getLoginURL(self): ''' Redirects to the login page. ''' if self.auto_login_page: req = self.REQUEST resp = req['RESPONSE'] iself = getattr(self, 'aq_inner', self) parent = getattr(iself, 'aq_parent', None) page = getattr(parent, self.auto_login_page, None) if page is not None: retry = getattr(resp, '_auth', 0) and '1' or '' came_from = req.get('came_from', None) if came_from is None:
class ImportStepRegistry(BaseStepRegistry): """ Manage knowledge about steps to create / configure site. o Steps are composed together to define a site profile. """ implements(IImportStepRegistry) security = ClassSecurityInfo() RegistryParser = _ImportStepRegistryParser security.declareProtected(ManagePortal, 'sortSteps') def sortSteps(self): """ Return a sequence of registered step IDs o Sequence is sorted topologically by dependency, with the dependent steps *after* the steps they depend on. """ return self._computeTopologicalSort() security.declareProtected(ManagePortal, 'checkComplete') def checkComplete(self): """ Return a sequence of ( node, edge ) tuples for unsatisifed deps. """ result = [] seen = {} graph = self._computeTopologicalSort() for node in graph: dependencies = self.getStepMetadata(node)['dependencies'] for dependency in dependencies: if seen.get(dependency) is None: result.append((node, dependency)) seen[node] = 1 return result security.declarePrivate('registerStep') def registerStep(self, id, version=None, handler=None, dependencies=(), title=None, description=None): """ Register a setup step. o 'id' is a unique name for this step, o 'version' is a string for comparing versions, it is preferred to be a yyyy/mm/dd-ii formatted string (date plus two-digit ordinal). when comparing two version strings, the version with the lower sort order is considered the older version. - Newer versions of a step supplant older ones. - Attempting to register an older one after a newer one results in a KeyError. o 'handler' is the dottoed name of a handler which should implement IImportPlugin. o 'dependencies' is a tuple of step ids which have to run before this step in order to be able to run at all. Registration of steps that have unmet dependencies are deferred until the dependencies have been registered. o 'title' is a one-line UI description for this step. If None, the first line of the documentation string of the handler is used, or the id if no docstring can be found. o 'description' is a one-line UI description for this step. If None, the remaining line of the documentation string of the handler is used, or default to ''. """ already = self.getStepMetadata(id) if handler is None: raise ValueError('No handler specified') if already and already['version'] > version: raise KeyError('Existing registration for step %s, version %s' % (id, already['version'])) if not isinstance(handler, str): handler = _getDottedName(handler) if title is None or description is None: method = _resolveDottedName(handler) if method is None: t, d = id, '' else: t, d = _extractDocstring(method, id, '') title = title or t description = description or d info = { 'id': id, 'version': version, 'handler': handler, 'dependencies': dependencies, 'title': title, 'description': description } self._registered[id] = info # # Helper methods # security.declarePrivate('_computeTopologicalSort') def _computeTopologicalSort(self): return _computeTopologicalSort(self._registered.values()) security.declarePrivate('_exportTemplate') _exportTemplate = PageTemplateFile('isrExport.xml', _xmldir)