Example #1
0
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
Example #2
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
Example #3
0
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
Example #4
0
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,
Example #5
0
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
Example #6
0
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
Example #7
0
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 ""
Example #8
0
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)
Example #9
0
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
Example #10
0
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 )
Example #11
0
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.')
Example #12
0
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()
Example #13
0
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')
Example #14
0
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 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
Example #16
0
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
Example #17
0
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
Example #18
0
class misc_:
    "Miscellaneous product information"
    security = ClassSecurityInfo()
    security.declareObjectPublic()
Example #19
0
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]
Example #20
0
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))
Example #21
0
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
Example #22
0
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()
Example #23
0
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
Example #24
0
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)
Example #25
0
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
Example #26
0
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)
Example #27
0
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)
Example #28
0
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
Example #29
0
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()
Example #30
0
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:
Example #31
0
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)