Exemplo n.º 1
0
class MimeTypeRegexPredicate(SimpleItem):
    """
        Predicate matching only on 'typ', using regex matching for
        string patterns (other objects conforming to 'match' can
        also be passed).
    """

    implements(IContentTypeRegistryPredicate)
    __implements__ = z2IContentTypeRegistryPredicate

    pattern = None
    PREDICATE_TYPE = 'mimetype_regex'

    security = ClassSecurityInfo()

    def __init__(self, id):
        self.id = id

    security.declareProtected(ManagePortal, 'getPatternStr')

    def getPatternStr(self):
        if self.pattern is None:
            return 'None'
        return self.pattern.pattern

    security.declareProtected(ManagePortal, 'edit')

    def edit(self, pattern):
        if pattern == 'None':
            pattern = None
        if type(pattern) is type(''):
            pattern = re.compile(pattern)
        self.pattern = pattern

    #
    #   ContentTypeRegistryPredicate interface
    #
    security.declareObjectPublic()

    def __call__(self, name, typ, body):
        """
            Return true if the rule matches, else false.
        """
        if self.pattern is None:
            return 0

        return self.pattern.match(typ)

    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 = DTMLResource('dtml/patternWidget', globals())
Exemplo n.º 2
0
class FSDTMLMethod(RestrictedDTML, RoleManager, FSObject, HTML):
    """FSDTMLMethods act like DTML methods but are not directly
    modifiable from the management interface."""

    meta_type = 'Filesystem DTML Method'

    manage_options = ((
        {
            'label': 'Customize',
            'action': 'manage_main'
        },
        {
            'label': 'View',
            'action': '',
            'help': ('OFSP', 'DTML-DocumentOrMethod_View.stx')
        },
        {
            'label': 'Proxy',
            'action': 'manage_proxyForm',
            'help': ('OFSP', 'DTML-DocumentOrMethod_Proxy.stx')
        },
    ) + Cacheable.manage_options)

    _proxy_roles = ()
    _cache_namespace_keys = ()

    # Use declarative security
    security = ClassSecurityInfo()
    security.declareObjectProtected(View)

    security.declareProtected(ViewManagementScreens, 'manage_main')
    manage_main = DTMLResource('dtml/custdtml', globals())

    _reading = 0

    def __init__(self,
                 id,
                 package=None,
                 entry_subpath=None,
                 filepath=None,
                 fullname=None,
                 properties=None):
        FSObject.__init__(self, id, package, entry_subpath, filepath, fullname,
                          properties)
        # Normally called via HTML.__init__ but we don't need the rest that
        # happens there.
        self.initvars(None, {})

    def _createZODBClone(self):
        """Create a ZODB (editable) equivalent of this object."""
        return DTMLMethod(self.read(), __name__=self.getId())

    def _readFile(self, reparse):
        self.raw = self._readFileAsResourceOrDirect()
        if reparse:
            self._reading = 1  # Avoid infinite recursion
            try:
                self.cook()
            finally:
                self._reading = 0

    # Hook up chances to reload in debug mode
    security.declarePrivate('read_raw')

    def read_raw(self):
        if not self._reading:
            self._updateFromFS()
        return HTML.read_raw(self)

    #### The following is mainly taken from OFS/DTMLMethod.py ###

    index_html = None  # Prevent accidental acquisition

    # Documents masquerade as functions:
    func_code = DTMLMethod.func_code

    default_content_type = 'text/html'

    def __call__(self, client=None, REQUEST={}, RESPONSE=None, **kw):
        """Render the document given a client object, REQUEST mapping,
        Response, and key word arguments."""

        self._updateFromFS()

        if not self._cache_namespace_keys:
            data = self.ZCacheable_get(default=_marker)
            if data is not _marker:
                # Return cached results.
                return data

        kw['document_id'] = self.getId()
        kw['document_title'] = self.title

        __traceback_info__ = self._filepath
        security = getSecurityManager()
        security.addContext(self)
        try:
            r = HTML.__call__(self, client, REQUEST, **kw)

            if client is None:
                # Called as subtemplate, so don't need error propagation!
                if RESPONSE is None: result = r
                else: result = decapitate(r, RESPONSE)
                if not self._cache_namespace_keys:
                    self.ZCacheable_set(result)
                return result

            if not isinstance(r, basestring) or RESPONSE is None:
                if not self._cache_namespace_keys:
                    self.ZCacheable_set(r)
                return r

        finally:
            security.removeContext(self)

        have_key = RESPONSE.headers.has_key
        if not (have_key('content-type') or have_key('Content-Type')):
            if self.__dict__.has_key('content_type'):
                c = self.content_type
            else:
                c, e = guess_content_type(self.getId(), r)
            RESPONSE.setHeader('Content-Type', c)
        if RESPONSE is not None:
            # caching policy manager hook
            _setCacheHeaders(self, {})
        result = decapitate(r, RESPONSE)
        if not self._cache_namespace_keys:
            self.ZCacheable_set(result)
        return result

    def getCacheNamespaceKeys(self):
        '''
        Returns the cacheNamespaceKeys.
        '''
        return self._cache_namespace_keys

    def setCacheNamespaceKeys(self, keys, REQUEST=None):
        '''
        Sets the list of names that should be looked up in the
        namespace to provide a cache key.
        '''
        ks = []
        for key in keys:
            key = strip(str(key))
            if key:
                ks.append(key)
        self._cache_namespace_keys = tuple(ks)
        if REQUEST is not None:
            return self.ZCacheable_manage(self, REQUEST)

    # Zope 2.3.x way:
    def validate(self, inst, parent, name, value, md=None):
        return getSecurityManager().validate(inst, parent, name, value)

    security.declareProtected(FTPAccess, 'manage_FTPget')
    manage_FTPget = DTMLMethod.manage_FTPget.im_func

    security.declareProtected(ViewManagementScreens, 'PrincipiaSearchSource')
    PrincipiaSearchSource = DTMLMethod.PrincipiaSearchSource.im_func

    security.declareProtected(ViewManagementScreens, 'document_src')
    document_src = DTMLMethod.document_src.im_func

    security.declareProtected(ViewManagementScreens, 'manage_haveProxy')
    manage_haveProxy = DTMLMethod.manage_haveProxy.im_func
Exemplo n.º 3
0
class CatalogTool(UniqueObject, ZCatalog, ActionProviderBase):
    """ This is a ZCatalog that filters catalog queries.
    """

    implements(ICatalogTool)
    __implements__ = (z2ICatalogTool, ZCatalog.__implements__,
                      ActionProviderBase.__implements__)

    id = 'portal_catalog'
    meta_type = 'CMF Catalog'

    security = ClassSecurityInfo()

    manage_options = (ZCatalog.manage_options +
                      ActionProviderBase.manage_options +
                      ({
                          'label': 'Overview',
                          'action': 'manage_overview'
                      }, ))

    def __init__(self):
        ZCatalog.__init__(self, self.getId())

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource('dtml/explainCatalogTool', globals())

    #
    #   'portal_catalog' interface methods
    #

    def _listAllowedRolesAndUsers(self, user):
        result = list(user.getRoles())
        result.append('Anonymous')
        result.append('user:%s' % user.getId())
        return result

    def _convertQuery(self, kw):
        # Convert query to modern syntax
        for k in 'effective', 'expires':
            kusage = k + '_usage'
            if not kw.has_key(kusage):
                continue
            usage = kw[kusage]
            if not usage.startswith('range:'):
                raise ValueError("Incorrect usage %s" % ` usage `)
            kw[k] = {'query': kw[k], 'range': usage[6:]}
            del kw[kusage]

    # searchResults has inherited security assertions.
    def searchResults(self, REQUEST=None, **kw):
        """
            Calls ZCatalog.searchResults with extra arguments that
            limit the results to what the user is allowed to see.
        """
        user = _getAuthenticatedUser(self)
        kw['allowedRolesAndUsers'] = self._listAllowedRolesAndUsers(user)

        if not _checkPermission(AccessInactivePortalContent, self):
            now = DateTime()

            self._convertQuery(kw)

            # Intersect query restrictions with those implicit to the tool
            for k in 'effective', 'expires':
                if kw.has_key(k):
                    range = kw[k]['range'] or ''
                    query = kw[k]['query']
                    if not isinstance(query, (tuple, list)):
                        query = (query, )
                else:
                    range = ''
                    query = None
                if range.find('min') > -1:
                    lo = min(query)
                else:
                    lo = None
                if range.find('max') > -1:
                    hi = max(query)
                else:
                    hi = None
                if k == 'effective':
                    if hi is None or hi > now:
                        hi = now
                    if lo is not None and hi < lo:
                        return ()
                else:  # 'expires':
                    if lo is None or lo < now:
                        lo = now
                    if hi is not None and hi < lo:
                        return ()
                # Rebuild a query
                if lo is None:
                    query = hi
                    range = 'max'
                elif hi is None:
                    query = lo
                    range = 'min'
                else:
                    query = (lo, hi)
                    range = 'min:max'
                kw[k] = {'query': query, 'range': range}

        return ZCatalog.searchResults(self, REQUEST, **kw)

    __call__ = searchResults

    security.declarePrivate('unrestrictedSearchResults')

    def unrestrictedSearchResults(self, REQUEST=None, **kw):
        """Calls ZCatalog.searchResults directly without restrictions.

        This method returns every also not yet effective and already expired
        objects regardless of the roles the caller has.

        CAUTION: Care must be taken not to open security holes by
        exposing the results of this method to non authorized callers!

        If you're in doubt if you should use this method or
        'searchResults' use the latter.
        """
        return ZCatalog.searchResults(self, REQUEST, **kw)

    def __url(self, ob):
        return '/'.join(ob.getPhysicalPath())

    manage_catalogFind = DTMLResource('dtml/catalogFind', globals())

    def catalog_object(self,
                       obj,
                       uid=None,
                       idxs=None,
                       update_metadata=1,
                       pghandler=None):
        # Wraps the object with workflow and accessibility
        # information just before cataloging.
        wftool = getToolByName(self, 'portal_workflow', None)
        if wftool is not None:
            vars = wftool.getCatalogVariablesFor(obj)
        else:
            vars = {}
        w = IndexableObjectWrapper(vars, obj)
        ZCatalog.catalog_object(self, w, uid, idxs, update_metadata, pghandler)

    security.declarePrivate('indexObject')

    def indexObject(self, object):
        """Add to catalog.
        """
        url = self.__url(object)
        self.catalog_object(object, url)

    security.declarePrivate('unindexObject')

    def unindexObject(self, object):
        """Remove from catalog.
        """
        url = self.__url(object)
        self.uncatalog_object(url)

    security.declarePrivate('reindexObject')

    def reindexObject(self, object, idxs=[], update_metadata=1, uid=None):
        """Update catalog after object data has changed.

        The optional idxs argument is a list of specific indexes
        to update (all of them by default).

        The update_metadata flag controls whether the object's
        metadata record is updated as well.

        If a non-None uid is passed, it will be used as the catalog uid
        for the object instead of its physical path.
        """
        if uid is None:
            uid = self.__url(object)
        if idxs != []:
            # Filter out invalid indexes.
            valid_indexes = self._catalog.indexes.keys()
            idxs = [i for i in idxs if i in valid_indexes]
        self.catalog_object(object, uid, idxs, update_metadata)
Exemplo n.º 4
0
class MemberDataTool(UniqueObject, SimpleItem, PropertyManager,
                     ActionProviderBase):
    """ This tool wraps user objects, making them act as Member objects.
    """

    implements(IMemberDataTool)
    __implements__ = (z2IMemberDataTool, ActionProviderBase.__implements__)

    id = 'portal_memberdata'
    meta_type = 'CMF Member Data Tool'
    _v_temps = None
    _properties = ()

    security = ClassSecurityInfo()

    manage_options = (ActionProviderBase.manage_options +
                      ({
                          'label': 'Overview',
                          'action': 'manage_overview'
                      }, {
                          'label': 'Contents',
                          'action': 'manage_showContents'
                      }) + PropertyManager.manage_options +
                      SimpleItem.manage_options)

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource('dtml/explainMemberDataTool', globals())

    security.declareProtected(ViewManagementScreens, 'manage_showContents')
    manage_showContents = DTMLResource('dtml/memberdataContents', globals())

    def __init__(self):
        self._members = OOBTree()
        # Create the default properties.
        self._setProperty('email', '', 'string')
        self._setProperty('portal_skin', '', 'string')
        self._setProperty('listed', '', 'boolean')
        self._setProperty('login_time', '2000/01/01', 'date')
        self._setProperty('last_login_time', '2000/01/01', 'date')

    #
    #   'portal_memberdata' interface methods
    #
    security.declarePrivate('getMemberDataContents')

    def getMemberDataContents(self):
        '''
        Return the number of members stored in the _members
        BTree and some other useful info
        '''
        membertool = getToolByName(self, 'portal_membership')
        members = self._members
        user_list = membertool.listMemberIds()
        member_list = members.keys()
        member_count = len(members)
        orphan_count = 0

        for member in member_list:
            if member not in user_list:
                orphan_count = orphan_count + 1

        return [{'member_count': member_count, 'orphan_count': orphan_count}]

    security.declarePrivate('searchMemberData')

    def searchMemberData(self, search_param, search_term, attributes=()):
        """ Search members. """
        res = []

        if not search_param:
            return res

        membership = getToolByName(self, 'portal_membership')

        if len(attributes) == 0:
            attributes = ('id', 'email')

        if search_param == 'username':
            search_param = 'id'

        for user_id in self._members.keys():
            u = membership.getMemberById(user_id)

            if u is not None:
                memberProperty = u.getProperty
                searched = memberProperty(search_param, None)

                if searched is not None and searched.find(search_term) != -1:
                    user_data = {}

                    for desired in attributes:
                        if desired == 'id':
                            user_data['username'] = memberProperty(desired, '')
                        else:
                            user_data[desired] = memberProperty(desired, '')

                    res.append(user_data)

        return res

    security.declarePrivate('searchMemberDataContents')

    def searchMemberDataContents(self, search_param, search_term):
        """ Search members. This method will be deprecated soon. """
        res = []

        if search_param == 'username':
            search_param = 'id'

        mtool = getToolByName(self, 'portal_membership')

        for member_id in self._members.keys():

            user_wrapper = mtool.getMemberById(member_id)

            if user_wrapper is not None:
                memberProperty = user_wrapper.getProperty
                searched = memberProperty(search_param, None)

                if searched is not None and searched.find(search_term) != -1:

                    res.append({
                        'username': memberProperty('id'),
                        'email': memberProperty('email', '')
                    })
        return res

    security.declarePrivate('pruneMemberDataContents')

    def pruneMemberDataContents(self):
        """ Delete data contents of all members not listet in acl_users.
        """
        membertool = getToolByName(self, 'portal_membership')
        members = self._members
        user_list = membertool.listMemberIds()

        for member_id in list(members.keys()):
            if member_id not in user_list:
                del members[member_id]

    security.declarePrivate('wrapUser')

    def wrapUser(self, u):
        '''
        If possible, returns the Member object that corresponds
        to the given User object.
        '''
        id = u.getId()
        members = self._members
        if not members.has_key(id):
            # Get a temporary member that might be
            # registered later via registerMemberData().
            temps = self._v_temps
            if temps is not None and temps.has_key(id):
                m = temps[id]
            else:
                base = aq_base(self)
                m = MemberData(base, id)
                if temps is None:
                    self._v_temps = {id: m}
                    if hasattr(self, 'REQUEST'):
                        # No REQUEST during tests.
                        self.REQUEST._hold(CleanupTemp(self))
                else:
                    temps[id] = m
        else:
            m = members[id]
        # Return a wrapper with self as containment and
        # the user as context.
        return m.__of__(self).__of__(u)

    security.declarePrivate('registerMemberData')

    def registerMemberData(self, m, id):
        """ Add the given member data to the _members btree.
        """
        self._members[id] = aq_base(m)

    security.declarePrivate('deleteMemberData')

    def deleteMemberData(self, member_id):
        """ Delete member data of specified member.
        """
        members = self._members
        if members.has_key(member_id):
            del members[member_id]
            return 1
        else:
            return 0
Exemplo n.º 5
0
        """
        Converts Subject string into a List for content filter view.
        """
        for sub in obj.Subject():
            if sub in self.filterSubject:
                return 1
        return 0

    def __call__(self, content):

        for predicate in self.predicates:

            try:
                if not predicate(content):
                    return 0
            except (AttributeError, KeyError, IndexError, ValueError):
                # predicates are *not* allowed to throw exceptions
                return 0

        return 1

    def __str__(self):
        """
            Return a stringified description of the filter.
        """
        return '; '.join(self.description)


manage_addPortalFolder = PortalFolder.manage_addPortalFolder.im_func
manage_addPortalFolderForm = DTMLResource('folderAdd', globals())
Exemplo n.º 6
0
class ActionsTool(UniqueObject, IFAwareObjectManager, OrderedFolder,
                  ActionProviderBase):
    """
        Weave together the various sources of "actions" which are apropos
        to the current user and context.
    """

    implements(IActionsTool)
    __implements__ = (z2IActionsTool, OrderedFolder.__implements__,
                      ActionProviderBase.__implements__)

    id = 'portal_actions'
    meta_type = 'CMF Actions Tool'
    _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 = DTMLResource('dtml/explainActionsTool', globals())
    manage_actionProviders = DTMLResource('dtml/manageActionProviders',
                                          globals())

    security.declareProtected(ManagePortal, 'manage_aproviders')

    def manage_aproviders(self,
                          apname='',
                          chosen=(),
                          add_provider=0,
                          del_provider=0,
                          REQUEST=None):
        """
        Manage action providers through-the-web.
        """
        providers = list(self.listActionProviders())
        new_providers = []
        if add_provider:
            providers.append(apname)
        elif del_provider:
            for item in providers:
                if item not in chosen:
                    new_providers.append(item)
            providers = new_providers
        self.action_providers = tuple(providers)
        if REQUEST is not None:
            return self.manage_actionProviders(
                self, REQUEST, manage_tabs_message='Providers changed.')

    security.declareProtected(ManagePortal, 'manage_editActionsForm')

    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.declarePrivate('listActions')

    def listActions(self, info=None, object=None):
        """ List all the actions defined by a provider.
        """
        actions = list(self._actions)
        for category in self.objectValues():
            actions.extend(category.listActions())
        return tuple(actions)

    #
    #   Programmatically manipulate the list of action providers
    #
    security.declareProtected(ManagePortal, 'listActionProviders')

    def listActionProviders(self):
        """ List the ids of all Action Providers queried by this tool.
        """
        return self.action_providers

    security.declareProtected(ManagePortal, 'addActionProvider')

    def addActionProvider(self, provider_name):
        """ Add an Action Provider id to the providers queried by this tool.
        """
        ap = list(self.action_providers)
        if hasattr(self, provider_name) and provider_name not in ap:
            ap.append(provider_name)
            self.action_providers = tuple(ap)

    security.declareProtected(ManagePortal, 'deleteActionProvider')

    def deleteActionProvider(self, provider_name):
        """ Delete an Action Provider id from providers queried by this tool.
        """
        ap = list(self.action_providers)
        if provider_name in ap:
            ap.remove(provider_name)
            self.action_providers = tuple(ap)

    #
    #   'portal_actions' interface methods
    #
    security.declarePublic('listFilteredActionsFor')

    def listFilteredActionsFor(self, object=None):
        """ List all actions available to the user.
        """
        actions = []

        # Include actions from specific tools.
        for provider_name in self.listActionProviders():
            provider = getattr(self, provider_name)
            if IActionProvider.providedBy(provider) or \
                    z2IActionProvider.isImplementedBy(provider):
                actions.extend(provider.listActionInfos(object=object))

        # Include actions from object.
        if object is not None:
            if IActionProvider.providedBy(object) or \
                    z2IActionProvider.isImplementedBy(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
Exemplo n.º 7
0
class FSPropertiesObject(FSObject, PropertyManager):
    """FSPropertiesObjects simply hold properties."""

    meta_type = 'Filesystem Properties Object'

    manage_options = ({'label': 'Customize', 'action': 'manage_main'}, )

    security = ClassSecurityInfo()

    security.declareProtected(ViewManagementScreens, 'manage_main')
    manage_main = DTMLResource('dtml/custprops', globals())

    # Declare all (inherited) mutating methods private.
    security.declarePrivate('manage_addProperty')
    security.declarePrivate('manage_editProperties')
    security.declarePrivate('manage_delProperties')
    security.declarePrivate('manage_changeProperties')
    security.declarePrivate('manage_propertiesForm')
    security.declarePrivate('manage_propertyTypeForm')
    security.declarePrivate('manage_changePropertyTypes')

    security.declareProtected(ViewManagementScreens, 'manage_doCustomize')

    def manage_doCustomize(self, folder_path, RESPONSE=None):
        """Makes a ZODB Based clone with the same data.

        Calls _createZODBClone for the actual work.
        """
        # Overridden here to provide a different redirect target.

        FSObject.manage_doCustomize(self, folder_path, RESPONSE)

        if RESPONSE is not None:
            fpath = tuple(folder_path.split('/'))
            folder = self.restrictedTraverse(fpath)
            RESPONSE.redirect('%s/%s/manage_propertiesForm' %
                              (folder.absolute_url(), self.getId()))

    def _createZODBClone(self):
        """Create a ZODB (editable) equivalent of this object."""
        # Create a Folder to hold the properties.
        obj = Folder()
        obj.id = self.getId()
        map = []
        for p in self._properties:
            # This should be secure since the properties come
            # from the filesystem.
            setattr(obj, p['id'], getattr(self, p['id']))
            map.append({
                'id': p['id'],
                'type': p['type'],
                'mode': 'wd',
            })
        obj._properties = tuple(map)

        return obj

    def _readFile(self, reparse):
        """Read the data from the filesystem.

        Read the file (indicated by exandpath(self._filepath), and parse the
        data if necessary.
        """
        data = self._readFileAsResourceOrDirect()
        lines = data.splitlines()

        map = []
        lino = 0

        for line in lines:

            lino = lino + 1
            line = line.strip()

            if not line or line[0] == '#':
                continue

            try:
                propname, proptv = line.split(':', 1)
                #XXX multi-line properties?
                proptype, propvstr = proptv.split('=', 1)
                propname = propname.strip()
                proptype = proptype.strip()
                propvstr = propvstr.strip()
                converter = get_converter(proptype, lambda x: x)
                propvalue = converter(propvstr)
                # Should be safe since we're loading from
                # the filesystem.
                setattr(self, propname, propvalue)
                map.append({
                    'id': propname,
                    'type': proptype,
                    'mode': '',
                    'default_value': propvalue,
                })
            except:
                raise ValueError, ('Error processing line %s of %s:\n%s' %
                                   (lino, fp, line))
        self._properties = tuple(map)

    if DevelopmentMode:
        # Provide an opportunity to update the properties.
        def __of__(self, parent):
            self = ImplicitAcquisitionWrapper(self, parent)
            self._updateFromFS()
            return self
Exemplo n.º 8
0
class FiveActionsTool(UniqueObject, SimpleItem, ActionProviderBase):
    """Five actions tool.

    Provides a bridge that makes Zope 3 menus available as CMF actions.
    """

    __implements__ = ActionProviderBase.__implements__

    id = 'portal_fiveactions'
    meta_type = 'CMF Five Actions Tool'

    security = ClassSecurityInfo()

    manage_options = (({
        'label': 'Overview',
        'action': 'manage_overview'
    }, ) + SimpleItem.manage_options)

    #
    # ZMI methods
    #

    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource('dtml/explainFiveActionsTool', globals())

    #
    # ActionProvider
    #

    security.declarePrivate('listActions')

    def listActions(self, info=None, object=None):
        """ List all the actions defined by a provider.
        """
        if object is None and info is not None:
            # BBB (according to the interface)
            object = info.content
        if object is None:
            # The tool itself doesn't provide any action
            return ()

        actions = []
        for mid in globalBrowserMenuService._registry.keys():
            menu = getMenu(mid, object, self.REQUEST)
            for entry in menu:
                # The action needs a unique name, so we'll build one
                # from the object_id and the action url. That is sure
                # to be unique.
                action = str(entry['action'])
                if object is None:
                    act_id = 'action_%s' % action
                else:
                    act_id = 'action_%s_%s' % (object.getId(), action)

                if entry['filter'] is None:
                    filter = None
                else:
                    filter = Expression(text=str(entry['filter']))

                act = ActionInformation(id=act_id,
                                        title=str(entry['title']),
                                        action=Expression(text='string:%s' %
                                                          action),
                                        condition=filter,
                                        category=str(mid),
                                        visible=1)
                actions.append(act)
        return tuple(actions)
Exemplo n.º 9
0
class UndoTool(UniqueObject, SimpleItem, ActionProviderBase):
    """ This tool is used to undo changes.
    """

    implements(IUndoTool)
    __implements__ = (z2IUndoTool, ActionProviderBase.__implements__)

    id = 'portal_undo'
    meta_type = 'CMF Undo Tool'

    security = ClassSecurityInfo()

    manage_options = (ActionProviderBase.manage_options +
                      SimpleItem.manage_options + ({
                          'label': 'Overview',
                          'action': 'manage_overview'
                      }, ))
    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource('dtml/explainUndoTool', globals())

    #
    #   'portal_undo' interface methods
    #
    security.declareProtected(ListUndoableChanges,
                              'listUndoableTransactionsFor')

    def listUndoableTransactionsFor(self,
                                    object,
                                    first_transaction=None,
                                    last_transaction=None,
                                    PrincipiaUndoBatchSize=None):
        '''Lists all transaction IDs the user is allowed to undo.
        '''
        # arg list for undoable_transactions() changed in Zope 2.2.
        portal = self.aq_inner.aq_parent
        transactions = portal.undoable_transactions(
            first_transaction=first_transaction,
            last_transaction=last_transaction,
            PrincipiaUndoBatchSize=PrincipiaUndoBatchSize)
        for t in transactions:
            # Ensure transaction ids don't have embedded LF.
            t['id'] = t['id'].replace('\n', '')
        if not _checkPermission(ManagePortal, portal):
            # Filter out transactions done by other members of the portal.
            user_id = _getAuthenticatedUser(self).getId()
            transactions = filter(lambda record, user_id=user_id: record[
                'user_name'].split()[-1] == user_id,
                                  transactions)
        return transactions

    security.declarePublic('undo')

    def undo(self, object, transaction_info):
        """
            Undo the list of transactions passed in 'transaction_info',
            first verifying that the current user is allowed to undo them.
        """
        # Belt and suspenders:  make sure that the user is actually
        # allowed to undo the transation(s) in transaction_info.

        xids = {}  # set of allowed transaction IDs

        allowed = self.listUndoableTransactionsFor(object)

        for xid in map(lambda x: x['id'], allowed):
            xids[xid] = 1

        if type(transaction_info) == type(''):
            transaction_info = [transaction_info]

        for tinfo in transaction_info:
            if not xids.get(tinfo, None):
                raise AccessControl_Unauthorized

        object.manage_undo_transactions(transaction_info)
Exemplo n.º 10
0
class ActionProviderBase:
    """ Provide ActionTabs and management methods for ActionProviders
    """

    implements(IActionProvider)
    __implements__ = z2IActionProvider

    security = ClassSecurityInfo()

    _actions = ()

    _actions_form = DTMLResource('dtml/editToolsActions', globals())

    manage_options = ({
        'label': 'Actions',
        'action': 'manage_editActionsForm',
        'help': ('CMFCore', 'Actions.stx')
    }, )

    #
    #   ActionProvider interface
    #
    security.declarePrivate('listActions')

    def listActions(self, info=None, object=None):
        """ List all the actions defined by a provider.
        """
        return self._actions or ()

    security.declarePrivate('getActionObject')

    def getActionObject(self, action):
        """Return the actions object or None if action doesn't exist.
        """
        # separate cataegory and id from action
        sep = action.rfind('/')
        if sep == -1:
            raise ValueError('Actions must have the format <category>/<id>.')
        category, id = action[:sep], action[sep + 1:]

        # search for action and return first one found
        for ai in self.listActions():
            if id == ai.getId() and category == ai.getCategory():
                return ai

        # no action found
        return None

    security.declarePublic('listActionInfos')

    def listActionInfos(self,
                        action_chain=None,
                        object=None,
                        check_visibility=1,
                        check_permissions=1,
                        check_condition=1,
                        max=-1):
        # List ActionInfo objects.
        # (method is without docstring to disable publishing)
        #
        ec = self._getExprContext(object)
        actions = self.listActions(object=object)
        actions = [ActionInfo(action, ec) for action in actions]

        if action_chain:
            filtered_actions = []
            if isinstance(action_chain, basestring):
                action_chain = (action_chain, )
            for action_ident in action_chain:
                sep = action_ident.rfind('/')
                category, id = action_ident[:sep], action_ident[sep + 1:]
                for ai in actions:
                    if id == ai['id'] and category == ai['category']:
                        filtered_actions.append(ai)
            actions = filtered_actions

        action_infos = []
        for ai in actions:
            if check_visibility and not ai['visible']:
                continue
            if check_permissions and not ai['allowed']:
                continue
            if check_condition and not ai['available']:
                continue
            action_infos.append(ai)
            if max + 1 and len(action_infos) >= max:
                break
        return action_infos

    security.declarePublic('getActionInfo')

    def getActionInfo(self,
                      action_chain,
                      object=None,
                      check_visibility=0,
                      check_condition=0):
        """ Get an ActionInfo object specified by a chain of actions.
        """
        action_infos = self.listActionInfos(action_chain,
                                            object,
                                            check_visibility=check_visibility,
                                            check_permissions=False,
                                            check_condition=check_condition)
        if not action_infos:
            if object is None:
                provider = self
            else:
                provider = object
            msg = 'Action "%s" not available for %s' % (action_chain, '/'.join(
                provider.getPhysicalPath()))
            raise ValueError(msg)
        for ai in action_infos:
            if ai['allowed']:
                return ai
        raise AccessControl_Unauthorized('You are not allowed to access any '
                                         'of the specified Actions.')

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_editActionsForm')

    def manage_editActionsForm(self, REQUEST, manage_tabs_message=None):
        """ Show the 'Actions' management tab.
        """
        actions = [ai.getMapping() for ai in self.listActions()]

        # 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)

    security.declareProtected(ManagePortal, 'addAction')

    def addAction(self,
                  id,
                  name,
                  action,
                  condition,
                  permission,
                  category,
                  visible=1,
                  REQUEST=None):
        """ Add an action to our list.
        """
        if not name:
            raise ValueError('A name is required.')

        action = action and str(action) or ''
        condition = condition and str(condition) or ''

        if not isinstance(permission, tuple):
            permission = (str(permission), )

        new_actions = self._cloneActions()

        new_action = ActionInformation(id=str(id),
                                       title=str(name),
                                       category=str(category),
                                       condition=condition,
                                       permissions=permission,
                                       visible=bool(visible),
                                       action=action)

        new_actions.append(new_action)
        self._actions = tuple(new_actions)

        if REQUEST is not None:
            return self.manage_editActionsForm(REQUEST,
                                               manage_tabs_message='Added.')

    security.declareProtected(ManagePortal, 'changeActions')

    def changeActions(self, properties=None, REQUEST=None):
        """ Update our list of actions.
        """
        if properties is None:
            properties = REQUEST

        actions = []

        for index in range(len(self._actions)):
            actions.append(self._extractAction(properties, index))

        self._actions = tuple(actions)

        if REQUEST is not None:
            return self.manage_editActionsForm(
                REQUEST, manage_tabs_message='Actions changed.')

    security.declareProtected(ManagePortal, 'deleteActions')

    def deleteActions(self, selections=(), REQUEST=None):
        """ Delete actions indicated by indexes in 'selections'.
        """
        sels = list(map(int, selections))  # Convert to a list of integers.

        old_actions = self._cloneActions()
        new_actions = []

        for index in range(len(old_actions)):
            if index not in sels:
                new_actions.append(old_actions[index])

        self._actions = tuple(new_actions)

        if REQUEST is not None:
            return self.manage_editActionsForm(
                REQUEST,
                manage_tabs_message=('Deleted %d action(s).' % len(sels)))

    security.declareProtected(ManagePortal, 'moveUpActions')

    def moveUpActions(self, selections=(), REQUEST=None):
        """ Move the specified actions up one slot in our list.
        """
        sels = list(map(int, selections))  # Convert to a list of integers.
        sels.sort()

        new_actions = self._cloneActions()

        for idx in sels:
            idx2 = idx - 1
            if idx2 < 0:
                # Wrap to the bottom.
                idx2 = len(new_actions) - 1
            # Swap.
            a = new_actions[idx2]
            new_actions[idx2] = new_actions[idx]
            new_actions[idx] = a

        self._actions = tuple(new_actions)

        if REQUEST is not None:
            return self.manage_editActionsForm(
                REQUEST,
                manage_tabs_message=('Moved up %d action(s).' % len(sels)))

    security.declareProtected(ManagePortal, 'moveDownActions')

    def moveDownActions(self, selections=(), REQUEST=None):
        """ Move the specified actions down one slot in our list.
        """
        sels = list(map(int, selections))  # Convert to a list of integers.
        sels.sort()
        sels.reverse()

        new_actions = self._cloneActions()

        for idx in sels:
            idx2 = idx + 1
            if idx2 >= len(new_actions):
                # Wrap to the top.
                idx2 = 0
            # Swap.
            a = new_actions[idx2]
            new_actions[idx2] = new_actions[idx]
            new_actions[idx] = a

        self._actions = tuple(new_actions)

        if REQUEST is not None:
            return self.manage_editActionsForm(
                REQUEST,
                manage_tabs_message=('Moved down %d action(s).' % len(sels)))

    #
    #   Helper methods
    #
    security.declarePrivate('_cloneActions')

    def _cloneActions(self):
        """ Return a list of actions, cloned from our current list.
        """
        return map(lambda x: x.clone(), list(self._actions))

    security.declarePrivate('_extractAction')

    def _extractAction(self, properties, index):
        """ Extract an ActionInformation from the funky form properties.
        """
        id = str(properties.get('id_%d' % index, ''))
        title = str(properties.get('name_%d' % index, ''))
        action = str(properties.get('action_%d' % index, ''))
        condition = str(properties.get('condition_%d' % index, ''))
        category = str(properties.get('category_%d' % index, ''))
        visible = bool(properties.get('visible_%d' % index, False))
        permissions = properties.get('permission_%d' % index, ())

        if not title:
            raise ValueError('A title is required.')

        if category == '':
            category = 'object'

        if isinstance(permissions, basestring):
            permissions = (permissions, )

        return ActionInformation(id=id,
                                 title=title,
                                 action=action,
                                 condition=condition,
                                 permissions=permissions,
                                 category=category,
                                 visible=visible)

    def _getOAI(self, object):
        return getOAI(self, object)

    def _getExprContext(self, object):
        return getExprContext(self, object)
Exemplo n.º 11
0
class FSFile(FSObject):
    """FSFiles act like images but are not directly
    modifiable from the management interface."""
    # Note that OFS.Image.File is not a base class because it is mutable.

    meta_type = 'Filesystem File'

    manage_options = ({
        'label': 'Customize',
        'action': 'manage_main'
    }, ) + Cacheable.manage_options

    security = ClassSecurityInfo()
    security.declareObjectProtected(View)

    def __init__(self,
                 id,
                 package=None,
                 entry_subpath=None,
                 filepath=None,
                 fullname=None,
                 properties=None):
        if fullname:
            id = fullname  # Use the whole filename.
        FSObject.__init__(self, id, package, entry_subpath, filepath, fullname,
                          properties)

    security.declareProtected(ViewManagementScreens, 'manage_main')
    manage_main = DTMLResource('dtml/custfile', globals())
    content_type = 'unknown/unknown'

    def _createZODBClone(self):
        return File(self.getId(), '', self._readFile(1))

    def _get_content_type(self, filename, body, id, content_type=None):
        # Consult self.content_type first, this is either
        # the default (unknown/unknown) or it got a value from a
        # .metadata file
        default_type = 'unknown/unknown'
        if getattr(self, 'content_type', default_type) != default_type:
            return self.content_type

        # Use the (imperfect) content type guessing
        # mechanism from OFS.Image, which ultimately uses the
        # Python mimetypes module.
        if not isinstance(body, basestring):
            body = body.data

        content_type, enc = guess_content_type(filename, body, content_type)

        return content_type

    def _getFilename(self):
        path = self._filepath or self._entry_subpath
        dir, fn = os.path.split(path)
        return fn

    def _readFile(self, reparse):
        data = self._readFileAsResourceOrDirect()
        if reparse or self.content_type == 'unknown/unknown':
            self.ZCacheable_invalidate()
            filename = self._getFilename()
            self.content_type = self._get_content_type(filename, data, self.id)
        return data

    #### The following is mainly taken from OFS/File.py ###

    def __str__(self):
        self._updateFromFS()
        return str(self._readFile(0))

    security.declareProtected(View, 'index_html')

    def index_html(self, REQUEST, RESPONSE):
        """
        The default view of the contents of a File or Image.

        Returns the contents of the file or image.  Also, sets the
        Content-Type HTTP header to the objects content type.
        """
        self._updateFromFS()
        data = self._readFile(0)
        data_len = len(data)
        last_mod = self._file_mod_time
        status = 200
        # HTTP If-Modified-Since header handling.
        header = REQUEST.get_header('If-Modified-Since', None)
        if header is not None:
            header = header.split(';')[0]
            # Some proxies seem to send invalid date strings for this
            # header. If the date string is not valid, we ignore it
            # rather than raise an error to be generally consistent
            # with common servers such as Apache (which can usually
            # understand the screwy date string as a lucky side effect
            # of the way they parse it).
            try:
                mod_since = long(DateTime(header).timeTime())
            except:
                mod_since = None

            if mod_since is not None:
                if last_mod > 0 and last_mod <= mod_since:
                    status = 304
                    data = ''

        #Last-Modified will get stomped on by a cache policy it there is
        #one set....
        RESPONSE.setStatus(status)
        RESPONSE.setHeader('Last-Modified', rfc1123_date(last_mod))
        RESPONSE.setHeader('Content-Type', self.content_type)

        if status != 304:
            # Avoid setting content-length for a 304. See RFC 2616.
            # Zope might still, for better or for worse, set a
            # content-length header with value "0".
            RESPONSE.setHeader('Content-Length', data_len)

        #There are 2 Cache Managers which can be in play....
        #need to decide which to use to determine where the cache headers
        #are decided on.
        if self.ZCacheable_getManager() is not None:
            self.ZCacheable_set(None)
        else:
            _setCacheHeaders(_ViewEmulator().__of__(self), extra_context={})
        return data

    security.declareProtected(View, 'getContentType')

    def getContentType(self):
        """Get the content type of a file or image.

        Returns the content type (MIME type) of a file or image.
        """
        self._updateFromFS()
        return self.content_type

    security.declareProtected(FTPAccess, 'manage_FTPget')
    manage_FTPget = index_html
Exemplo n.º 12
0
class DirectoryViewSurrogate (Folder):
    """ Folderish DirectoryView.
    """

    meta_type = 'Filesystem Directory View'
    all_meta_types = ()
    _isDirectoryView = 1

    security = ClassSecurityInfo()

    def __init__(self, real, data, objects):
        d = self.__dict__
        d.update(data)
        d.update(real.__dict__)
        d['_real'] = real
        d['_objects'] = objects

    def __setattr__(self, name, value):
        d = self.__dict__
        d[name] = value
        setattr(d['_real'], name, value)

    def __delattr__(self, name):
        d = self.__dict__
        del d[name]
        delattr(d['_real'], name)

    security.declareProtected(ManagePortal, 'manage_propertiesForm')
    manage_propertiesForm = DTMLResource( 'dtml/dirview_properties'
                                        , globals() )

    security.declareProtected(ManagePortal, 'manage_properties')
    def manage_properties( self, dirpath, REQUEST=None ):
        """ Update the directory path of the DirectoryView.
        """
        self.__dict__['_real']._dirpath = _normalizeDirPath(dirpath)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect( '%s/manage_propertiesForm'
                                        % self.absolute_url() )

    security.declareProtected(AccessContentsInformation, 'getCustomizableObject')
    def getCustomizableObject(self):
        ob = aq_parent(aq_inner(self))
        while getattr(ob, '_isDirectoryView', 0):
            ob = aq_parent(aq_inner(ob))
        return ob

    security.declareProtected(AccessContentsInformation, 'listCustFolderPaths')
    def listCustFolderPaths(self, adding_meta_type=None):
        """ List possible customization folders as key, value pairs.
        """
        rval = []
        ob = self.getCustomizableObject()
        listFolderHierarchy(ob, '', rval, adding_meta_type)
        rval.sort()
        return rval

    security.declareProtected(AccessContentsInformation, 'getDirPath')
    def getDirPath(self):
        return self.__dict__['_real']._dirpath

    security.declarePublic('getId')
    def getId(self):
        return self.id
Exemplo n.º 13
0
        rval.sort()
        return rval

    security.declareProtected(AccessContentsInformation, 'getDirPath')
    def getDirPath(self):
        return self.__dict__['_real']._dirpath

    security.declarePublic('getId')
    def getId(self):
        return self.id

InitializeClass(DirectoryViewSurrogate)


#manage_addDirectoryViewForm = HTMLFile('dtml/addFSDirView', globals())
manage_addDirectoryViewForm = DTMLResource('dtml/addFSDirView', globals())

def createDirectoryView(parent, minimal_fp, id=None):
    """ Add either a DirectoryView or a derivative object.
    """
    info = _dirreg.getDirectoryInfo(minimal_fp)
    if info is None:    # maybe old data
        minimal_fp = _normalizeDirPath(minimal_fp)
        info = _dirreg.getDirectoryInfo(minimal_fp)
    if info is None:
        raise ValueError('Not a registered directory: %s' % minimal_fp)
    if not id:
        id = minimal_fp.split('/')[-1]
    else:
        id = str(id)
    ob = DirectoryView(id, minimal_fp)
Exemplo n.º 14
0
class RegistrationTool(UniqueObject, SimpleItem, ActionProviderBase):
    """ Create and modify users by making calls to portal_membership.
    """

    implements(IRegistrationTool)
    __implements__ = (z2IRegistrationTool, ActionProviderBase.__implements__)

    id = 'portal_registration'
    meta_type = 'CMF Registration Tool'
    member_id_pattern = ''
    default_member_id_pattern = "^[A-Za-z][A-Za-z0-9_]*$"
    _ALLOWED_MEMBER_ID_PATTERN = re.compile(default_member_id_pattern)

    security = ClassSecurityInfo()

    manage_options = (ActionProviderBase.manage_options +
                      ({
                          'label': 'Overview',
                          'action': 'manage_overview'
                      }, {
                          'label': 'Configure',
                          'action': 'manage_configuration'
                      }) + SimpleItem.manage_options)

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource('dtml/explainRegistrationTool', globals())

    security.declareProtected(ManagePortal, 'manage_configuration')
    manage_configuration = DTMLResource('dtml/configureRegistrationTool',
                                        globals())

    security.declareProtected(ManagePortal, 'manage_editIDPattern')

    def manage_editIDPattern(self, pattern, REQUEST=None):
        """Edit the allowable member ID pattern TTW"""
        pattern.strip()

        if len(pattern) > 0:
            self.member_id_pattern = pattern
            self._ALLOWED_MEMBER_ID_PATTERN = re.compile(pattern)
        else:
            self.member_id_pattern = ''
            self._ALLOWED_MEMBER_ID_PATTERN = re.compile(
                self.default_member_id_pattern)

        if REQUEST is not None:
            msg = 'Member ID Pattern changed'
            return self.manage_configuration(manage_tabs_message=msg)

    security.declareProtected(ManagePortal, 'getIDPattern')

    def getIDPattern(self):
        """ Return the currently-used member ID pattern """
        return self.member_id_pattern

    security.declareProtected(ManagePortal, 'getDefaultIDPattern')

    def getDefaultIDPattern(self):
        """ Return the currently-used member ID pattern """
        return self.default_member_id_pattern

    #
    #   'portal_registration' interface methods
    #
    security.declarePublic('isRegistrationAllowed')

    def isRegistrationAllowed(self, REQUEST):
        '''Returns a boolean value indicating whether the user
        is allowed to add a member to the portal.
        '''
        return _checkPermission(AddPortalMember, self.aq_inner.aq_parent)

    security.declarePublic('testPasswordValidity')

    def testPasswordValidity(self, password, confirm=None):
        '''If the password is valid, returns None.  If not, returns
        a string explaining why.
        '''
        return None

    security.declarePublic('testPropertiesValidity')

    def testPropertiesValidity(self, new_properties, member=None):
        '''If the properties are valid, returns None.  If not, returns
        a string explaining why.
        '''
        return None

    security.declarePublic('generatePassword')

    def generatePassword(self):
        """ Generate a valid password.
        """
        # we don't use these to avoid typos: OQ0Il1
        chars = 'ABCDEFGHJKLMNPRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789'
        return ''.join([choice(chars) for i in range(6)])

    security.declareProtected(AddPortalMember, 'addMember')

    def addMember(self,
                  id,
                  password,
                  roles=('Member', ),
                  domains='',
                  properties=None):
        '''Creates a PortalMember and returns it. The properties argument
        can be a mapping with additional member properties. Raises an
        exception if the given id already exists, the password does not
        comply with the policy in effect, or the authenticated user is not
        allowed to grant one of the roles listed (where Member is a special
        role that can always be granted); these conditions should be
        detected before the fact so that a cleaner message can be printed.
        '''
        if not self.isMemberIdAllowed(id):
            raise ValueError(
                _('The login name you selected is already in '
                  'use or is not valid. Please choose another.'))

        failMessage = self.testPasswordValidity(password)
        if failMessage is not None:
            raise ValueError(failMessage)

        if properties is not None:
            failMessage = self.testPropertiesValidity(properties)
            if failMessage is not None:
                raise ValueError(failMessage)

        # Limit the granted roles.
        # Anyone is always allowed to grant the 'Member' role.
        _limitGrantedRoles(roles, self, ('Member', ))

        membership = getToolByName(self, 'portal_membership')
        membership.addMember(id, password, roles, domains, properties)

        member = membership.getMemberById(id)
        self.afterAdd(member, id, password, properties)
        return member

    security.declareProtected(AddPortalMember, 'isMemberIdAllowed')

    def isMemberIdAllowed(self, id):
        '''Returns 1 if the ID is not in use and is not reserved.
        '''
        if len(id) < 1 or id == 'Anonymous User':
            return 0
        if not self._ALLOWED_MEMBER_ID_PATTERN.match(id):
            return 0
        membership = getToolByName(self, 'portal_membership')
        if membership.getMemberById(id) is not None:
            return 0
        return 1

    security.declarePublic('afterAdd')

    def afterAdd(self, member, id, password, properties):
        '''Called by portal_registration.addMember()
        after a member has been added successfully.'''
        pass

    security.declareProtected(MailForgottenPassword, 'mailPassword')

    def mailPassword(self, forgotten_userid, REQUEST):
        '''Email a forgotten password to a member.  Raises an exception
        if user ID is not found.
        '''
        raise NotImplementedError
Exemplo n.º 15
0
class ContentTypeRegistry(SimpleItem):
    """
        Registry for rules which map PUT args to a CMF Type Object.
    """

    implements(IContentTypeRegistry)
    __implements__ = z2IContentTypeRegistry

    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 = DTMLResource('dtml/registryPredList', globals())

    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 = DTMLResource('dtml/registryTest', globals())

    security.declareProtected(ManagePortal, 'doTestRegistry')

    def doTestRegistry(self, name, content_type, body, REQUEST):
        """
        """
        typeName = self.findTypeName(name, content_type, body)
        if typeName is None:
            typeName = '<unknown>'
        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):
        """
            Return a sequence of tuples,
            '( id, ( predicate, typeObjectName ) )'
            for all predicates in the registry
        """
        result = []
        for predicate_id in self.predicate_ids:
            result.append((predicate_id, self.predicates[predicate_id]))
        return tuple(result)

    security.declarePublic('getTypeObjectName')

    def getTypeObjectName(self, predicate_id):
        """
            Find the predicate whose id is 'id';  return the name of
            the type object, if found, or else None.
        """
        return self.predicates.get(predicate_id, (None, None))[1]

    security.declareProtected(ManagePortal, 'addPredicate')

    def addPredicate(self, predicate_id, predicate_type):
        """
            Add a predicate to this element of type 'typ' to the registry.
        """
        if predicate_id in self.predicate_ids:
            raise ValueError, "Existing predicate: %s" % predicate_id

        klass = None
        for key, value in _predicate_types:
            if key == predicate_type:
                klass = value

        if klass is None:
            raise ValueError, "Unknown predicate type: %s" % predicate_type

        self.predicates[predicate_id] = (klass(predicate_id), None)
        self.predicate_ids = self.predicate_ids + (predicate_id, )

    security.declareProtected(ManagePortal, '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
Exemplo n.º 16
0
class MajorMinorPredicate(SimpleItem):
    """
        Predicate matching on 'major/minor' content types.
        Empty major or minor implies wildcard (all match).
    """

    implements(IContentTypeRegistryPredicate)
    __implements__ = z2IContentTypeRegistryPredicate

    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 = DTMLResource('dtml/majorMinorWidget', globals())
Exemplo n.º 17
0
class TypesTool(UniqueObject, IFAwareObjectManager, Folder,
                ActionProviderBase):
    """
        Provides a configurable registry of portal content types.
    """

    implements(ITypesTool)
    __implements__ = (z2ITypesTool, ActionProviderBase.__implements__)

    id = 'portal_types'
    meta_type = 'CMF Types Tool'
    _product_interfaces = (ITypeInformation, )

    security = ClassSecurityInfo()

    manage_options = (Folder.manage_options[:1] + ({
        'label': 'Aliases',
        'action': 'manage_aliases'
    }, ) + ActionProviderBase.manage_options + ({
        'label': 'Overview',
        'action': 'manage_overview'
    }, ) + Folder.manage_options[1:])

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource('dtml/explainTypesTool', globals())

    security.declareProtected(ManagePortal, 'manage_aliases')
    manage_aliases = PageTemplateResource('typesAliases.zpt', globals())

    #
    #   ObjectManager methods
    #
    def all_meta_types(self):
        # this is a workaround and should be removed again if allowedTypes
        # have an interface we can use in _product_interfaces
        all = TypesTool.inheritedAttribute('all_meta_types')(self)
        others = [
            mt for mt in Products.meta_types if mt['name'] in allowedTypes
        ]
        return tuple(all) + tuple(others)

    #
    #   other methods
    #
    security.declareProtected(ManagePortal, 'manage_addTypeInformation')

    def manage_addTypeInformation(self,
                                  add_meta_type,
                                  id=None,
                                  typeinfo_name=None,
                                  RESPONSE=None):
        """Create a TypeInformation in self.
        """
        # BBB: typeinfo_name is ignored
        if not id:
            raise BadRequest('An id is required.')
        for mt in Products.meta_types:
            if mt['name'] == add_meta_type:
                klass = mt['instance']
                break
        else:
            raise ValueError, ('Meta type %s is not a type class.' %
                               add_meta_type)
        id = str(id)
        ob = klass(id)
        self._setObject(id, ob)
        if RESPONSE is not None:
            RESPONSE.redirect('%s/manage_main' % self.absolute_url())

    security.declareProtected(ManagePortal, 'manage_setTIMethodAliases')

    def manage_setTIMethodAliases(self, REQUEST):
        """ Config method aliases.
        """
        form = REQUEST.form
        aliases = {}
        for k, v in form['aliases'].items():
            v = v.strip()
            if v:
                aliases[k] = v

        for ti in self.listTypeInfo():
            _dict = {}
            for k, v in form[ti.getId()].items():
                if aliases.has_key(k):
                    _dict[aliases[k]] = v
            ti.setMethodAliases(_dict)
        REQUEST.RESPONSE.redirect('%s/manage_aliases' % self.absolute_url())

    security.declareProtected(AccessContentsInformation, 'getTypeInfo')

    def getTypeInfo(self, contentType):
        """
            Return an instance which implements the
            TypeInformation interface, corresponding to
            the specified 'contentType'.  If contentType is actually
            an object, rather than a string, attempt to look up
            the appropriate type info using its portal_type.
        """
        if not isinstance(contentType, basestring):
            if hasattr(aq_base(contentType), 'getPortalTypeName'):
                contentType = contentType.getPortalTypeName()
                if contentType is None:
                    return None
            else:
                return None
        ob = getattr(self, contentType, None)
        if getattr(aq_base(ob), '_isTypeInformation', 0):
            return ob
        else:
            return None

    security.declareProtected(AccessContentsInformation, 'listTypeInfo')

    def listTypeInfo(self, container=None):
        """
            Return a sequence of instances which implement the
            TypeInformation interface, one for each content
            type registered in the portal.
        """
        rval = []
        for t in self.objectValues():
            # Filter out things that aren't TypeInformation and
            # types for which the user does not have adequate permission.
            if not getattr(aq_base(t), '_isTypeInformation', 0):
                continue
            if not t.getId():
                # XXX What's this used for ?
                # Not ready.
                continue
            # check we're allowed to access the type object
            if container is not None:
                if not t.isConstructionAllowed(container):
                    continue
            rval.append(t)
        return rval

    security.declareProtected(AccessContentsInformation, 'listContentTypes')

    def listContentTypes(self, container=None, by_metatype=0):
        """ List type info IDs.

        Passing 'by_metatype' is deprecated (type information may not
        correspond 1:1 to an underlying meta_type). This argument will be
        removed when CMFCore/dtml/catalogFind.dtml doesn't need it anymore.
        """
        typenames = {}
        for t in self.listTypeInfo(container):

            if by_metatype:
                warn(
                    'TypeInformation.listContentTypes(by_metatype=1) is '
                    'deprecated.', DeprecationWarning)
                name = t.Metatype()
            else:
                name = t.getId()

            if name:
                typenames[name] = None

        result = typenames.keys()
        result.sort()
        return result

    security.declarePublic('constructContent')

    def constructContent(self,
                         type_name,
                         container,
                         id,
                         RESPONSE=None,
                         *args,
                         **kw):
        """
            Build an instance of the appropriate content class in
            'container', using 'id'.
        """
        info = self.getTypeInfo(type_name)
        if info is None:
            raise ValueError('No such content type: %s' % type_name)

        ob = info.constructInstance(container, id, *args, **kw)

        if RESPONSE is not None:
            immediate_url = '%s/%s' % (ob.absolute_url(), info.immediate_view)
            RESPONSE.redirect(immediate_url)

        return ob.getId()

    security.declarePrivate('listActions')

    def listActions(self, info=None, object=None):
        """ List all the actions defined by a provider.
        """
        actions = list(self._actions)

        if object is None and info is not None:
            object = info.object
        if object is not None:
            type_info = self.getTypeInfo(object)
            if type_info is not None:
                actions.extend(type_info.listActions())

        return actions

    security.declareProtected(ManagePortal, 'listMethodAliasKeys')

    def listMethodAliasKeys(self):
        """ List all defined method alias names.
        """
        _dict = {}
        for ti in self.listTypeInfo():
            aliases = ti.getMethodAliases()
            for k, v in aliases.items():
                _dict[k] = 1
        rval = _dict.keys()
        rval.sort()
        return rval
Exemplo n.º 18
0
class SkinsTool(UniqueObject, SkinsContainer, Folder, ActionProviderBase):
    """ This tool is used to supply skins to a portal.
    """

    implements(ISkinsTool)
    __implements__ = (z2ISkinsTool, SkinsContainer.__implements__,
                      ActionProviderBase.__implements__)

    id = 'portal_skins'
    meta_type = 'CMF Skins Tool'
    allow_any = 0
    cookie_persistence = 0
    default_skin = ''
    request_varname = 'portal_skin'
    selections = None

    security = ClassSecurityInfo()

    manage_options = (modifiedOptions() + ({
        'label': 'Overview',
        'action': 'manage_overview'
    }, ) + ActionProviderBase.manage_options)

    def __init__(self):
        self.selections = PersistentMapping()

    def _getSelections(self):
        sels = self.selections
        if sels is None:
            # Backward compatibility.
            self.selections = sels = PersistentMapping()
        return sels

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource('dtml/explainSkinsTool', globals())

    security.declareProtected(ManagePortal, 'manage_propertiesForm')
    manage_propertiesForm = DTMLResource('dtml/skinProps', globals())

    # the following two methods override those in FindSupport, to
    # support marking of objects used in specific skins
    security.declareProtected(ManagePortal, 'manage_findResult')
    manage_findResult = DTMLResource('dtml/findResult',
                                     globals(),
                                     management_view='Find')

    security.declareProtected(ManagePortal, 'manage_findForm')
    manage_findForm = DTMLResource('dtml/findForm',
                                   globals(),
                                   management_view='Find')

    security.declareProtected(ManagePortal, 'manage_skinLayers')

    def manage_skinLayers(self,
                          chosen=(),
                          add_skin=0,
                          del_skin=0,
                          skinname='',
                          skinpath='',
                          REQUEST=None):
        """ Change the skinLayers.
        """
        sels = self._getSelections()
        if del_skin:
            for name in chosen:
                del sels[name]

        if REQUEST is not None:
            for key in sels.keys():
                fname = 'skinpath_%s' % key
                val = REQUEST[fname]

                # if val is a list from the new lines field
                # then munge it back into a comma delimited list
                # for hysterical reasons
                if isinstance(val, list):
                    val = ','.join([layer.strip() for layer in val])

                if sels[key] != val:
                    self.testSkinPath(val)
                    sels[key] = val

        if add_skin:
            skinpath = ','.join([layer.strip() for layer in skinpath])
            self.testSkinPath(skinpath)
            sels[str(skinname)] = skinpath

        if REQUEST is not None:
            return self.manage_propertiesForm(
                self,
                REQUEST,
                management_view='Properties',
                manage_tabs_message='Skins changed.')

    security.declareProtected(ManagePortal, 'isFirstInSkin')

    def isFirstInSkin(self, template_path, skin=None):
        """ Is the specified template the one that would get returned
            from the current skin?
        """
        if skin is None or skin == 'None':
            skin = self.getDefaultSkin()
        template = self.restrictedTraverse(template_path)
        name = template.getId()
        skin_path = self.getSkinPath(skin)
        if not skin_path:
            return 0
        parts = list(skin_path.split(","))
        found = ""
        for part in parts:
            part = part.strip()
            if part[0] == "_":
                continue
            partob = getattr(self, part, None)
            if partob:
                skin_template = getattr(partob.aq_base, name, None)
                if skin_template:
                    found = skin_template
                    break
        if found == template:
            return 1
        else:
            return 0

    security.declareProtected(ManagePortal, 'manage_properties')

    def manage_properties(self,
                          default_skin='',
                          request_varname='',
                          allow_any=0,
                          chosen=(),
                          add_skin=0,
                          del_skin=0,
                          skinname='',
                          skinpath='',
                          cookie_persistence=0,
                          REQUEST=None):
        """ Changes portal_skin properties. """
        self.default_skin = str(default_skin)
        self.request_varname = str(request_varname)
        self.allow_any = allow_any and 1 or 0
        self.cookie_persistence = cookie_persistence and 1 or 0
        if REQUEST is not None:
            return self.manage_propertiesForm(
                self,
                REQUEST,
                management_view='Properties',
                manage_tabs_message='Properties changed.')

    security.declarePrivate('PUT_factory')

    def PUT_factory(self, name, typ, body):
        """
            Dispatcher for PUT requests to non-existent IDs.  Returns
            an object of the appropriate type (or None, if we don't
            know what to do).
        """
        major, minor = typ.split('/', 1)

        if major == 'image':
            return Image(id=name, title='', file='', content_type=typ)

        if major == 'text':

            if minor == 'x-python':
                return PythonScript(id=name)

            if minor in ('html', 'xml'):
                return ZopePageTemplate(name)

            return DTMLMethod(__name__=name)

        return None

    # Make the PUT_factory replaceable
    PUT_factory__replaceable__ = REPLACEABLE

    security.declarePrivate('testSkinPath')

    def testSkinPath(self, p):
        """ Calls SkinsContainer.getSkinByPath().
        """
        self.getSkinByPath(p, raise_exc=1)

    #
    #   'SkinsContainer' interface methods
    #
    security.declareProtected(AccessContentsInformation, 'getSkinPath')

    def getSkinPath(self, name):
        """ Convert a skin name to a skin path.
        """
        sels = self._getSelections()
        p = sels.get(name, None)
        if p is None:
            if self.allow_any:
                return name
        return p  # Can be None

    security.declareProtected(AccessContentsInformation, 'getDefaultSkin')

    def getDefaultSkin(self):
        """ Get the default skin name.
        """
        return self.default_skin

    security.declareProtected(AccessContentsInformation, 'getRequestVarname')

    def getRequestVarname(self):
        """ Get the variable name to look for in the REQUEST.
        """
        return self.request_varname

    #
    #   UI methods
    #
    security.declareProtected(AccessContentsInformation, 'getAllowAny')

    def getAllowAny(self):
        '''
        Used by the management UI.  Returns a flag indicating whether
        users are allowed to use arbitrary skin paths.
        '''
        return self.allow_any

    security.declareProtected(AccessContentsInformation,
                              'getCookiePersistence')

    def getCookiePersistence(self):
        '''
        Used by the management UI.  Returns a flag indicating whether
        the skins cookie is persistent or not.
        '''
        return self.cookie_persistence

    security.declareProtected(AccessContentsInformation, 'getSkinPaths')

    def getSkinPaths(self):
        '''
        Used by the management UI.  Returns the list of skin name to
        skin path mappings as a sorted list of tuples.
        '''
        sels = self._getSelections()
        rval = []
        for key, value in sels.items():
            rval.append((key, value))
        rval.sort()
        return rval

    #
    #   'portal_skins' interface methods
    #
    security.declarePublic('getSkinSelections')

    def getSkinSelections(self):
        """ Get the sorted list of available skin names.
        """
        sels = self._getSelections()
        rval = list(sels.keys())
        rval.sort()
        return rval

    security.declareProtected(View, 'updateSkinCookie')

    def updateSkinCookie(self):
        """ If needed, updates the skin cookie based on the member preference.
        """
        mtool = getToolByName(self, 'portal_membership')
        utool = getToolByName(self, 'portal_url')
        member = mtool.getAuthenticatedMember()
        if hasattr(aq_base(member), 'portal_skin'):
            mskin = member.portal_skin
            if mskin:
                req = self.REQUEST
                cookie = req.cookies.get(self.request_varname, None)
                if cookie != mskin:
                    resp = req.RESPONSE
                    portal_path = req['BASEPATH1'] + '/' + utool(1)

                    if not self.cookie_persistence:
                        # *Don't* make the cookie persistent!
                        resp.setCookie(self.request_varname,
                                       mskin,
                                       path=portal_path)
                    else:
                        expires = (DateTime('GMT') + 365).rfc822()
                        resp.setCookie(self.request_varname,
                                       mskin,
                                       path=portal_path,
                                       expires=expires)
                    # Ensure updateSkinCookie() doesn't try again
                    # within this request.
                    req.cookies[self.request_varname] = mskin
                    req[self.request_varname] = mskin
                    return 1
        return 0

    security.declareProtected(View, 'clearSkinCookie')

    def clearSkinCookie(self):
        """ Expire the skin cookie.
        """
        req = self.REQUEST
        resp = req.RESPONSE
        utool = getToolByName(self, 'portal_url')
        portal_path = req['BASEPATH1'] + '/' + utool(1)
        resp.expireCookie(self.request_varname, path=portal_path)

    security.declareProtected(ManagePortal, 'addSkinSelection')

    def addSkinSelection(self, skinname, skinpath, test=0, make_default=0):
        '''
        Adds a skin selection.
        '''
        sels = self._getSelections()
        skinpath = str(skinpath)

        # Basic precaution to make sure the stuff we want to ignore in
        # DirectoryViews gets prevented from ending up in a skin path
        path_elems = [x.strip() for x in skinpath.split(',')]
        ignored = base_ignore + ignore

        for elem in path_elems[:]:
            if elem in ignored or ignore_re.match(elem):
                path_elems.remove(elem)

        skinpath = ','.join(path_elems)

        if test:
            self.testSkinPath(skinpath)
        sels[str(skinname)] = skinpath
        if make_default:
            self.default_skin = skinname
Exemplo n.º 19
0
class FSPageTemplate(FSObject, Script, PageTemplate):
    """Wrapper for Page Template.
    """

    meta_type = 'Filesystem Page Template'

    _owner = None  # Unowned

    manage_options = ((
        {
            'label': 'Customize',
            'action': 'manage_main'
        },
        {
            'label': 'Test',
            'action': 'ZScriptHTML_tryForm'
        },
    ) + Cacheable.manage_options)

    security = ClassSecurityInfo()
    security.declareObjectProtected(View)

    security.declareProtected(ViewManagementScreens, 'manage_main')
    manage_main = DTMLResource('dtml/custpt', globals())

    # Declare security for unprotected PageTemplate methods.
    security.declarePrivate('pt_edit', 'write')

    def __init__(self,
                 id,
                 package=None,
                 entry_subpath=None,
                 filepath=None,
                 fullname=None,
                 properties=None):
        FSObject.__init__(self, id, package, entry_subpath, filepath, fullname,
                          properties)
        self.ZBindings_edit(self._default_bindings)

    def _createZODBClone(self):
        """Create a ZODB (editable) equivalent of this object."""
        obj = ZopePageTemplate(self.getId(), self._text, self.content_type)
        obj.expand = 0
        obj.write(self.read())
        return obj


#    def ZCacheable_isCachingEnabled(self):
#        return 0

    def _readFile(self, reparse):
        data = self._readFileAsResourceOrDirect()

        if reparse:
            # If we already have a content_type set it must come from a
            # .metadata file and we should always honor that. The content
            # type is initialized as text/html by default, so we only
            # attempt further detection if the default is encountered.
            # One previous misbehavior remains: It is not possible to
            # force a text./html type if parsing detects it as XML.
            if getattr(self, 'content_type', 'text/html') == 'text/html':
                xml_info = xml_detect_re.match(data)
                if xml_info:
                    # Smells like xml
                    # set "content_type" from the XML declaration
                    encoding = xml_info.group(1) or 'utf-8'
                    self.content_type = 'text/xml; charset=%s' % encoding

        self.write(data)

    security.declarePrivate('read')

    def read(self):
        # Tie in on an opportunity to auto-update
        self._updateFromFS()
        return FSPageTemplate.inheritedAttribute('read')(self)

    ### The following is mainly taken from ZopePageTemplate.py ###

    expand = 0

    func_defaults = None
    func_code = ZopePageTemplate.func_code
    _default_bindings = ZopePageTemplate._default_bindings

    security.declareProtected(View, '__call__')

    def pt_macros(self):
        # Tie in on an opportunity to auto-reload
        self._updateFromFS()
        return FSPageTemplate.inheritedAttribute('pt_macros')(self)

    def pt_render(self, source=0, extra_context={}):
        self._updateFromFS()  # Make sure the template has been loaded.

        if not source:
            # If we have a conditional get, set status 304 and return
            # no content
            if _checkConditionalGET(self, extra_context):
                return ''

        result = FSPageTemplate.inheritedAttribute('pt_render')(self, source,
                                                                extra_context)
        if not source:
            _setCacheHeaders(self, extra_context)
        return result

    security.declareProtected(ViewManagementScreens, 'pt_source_file')

    def pt_source_file(self):
        """ Return a file name to be compiled into the TAL code.
        """
        return 'file:%s' % self._filepath

    security.declarePrivate('_ZPT_exec')
    _ZPT_exec = ZopePageTemplate._exec.im_func

    security.declarePrivate('_exec')

    def _exec(self, bound_names, args, kw):
        """Call a FSPageTemplate"""
        try:
            response = self.REQUEST.RESPONSE
        except AttributeError:
            response = None
        # Read file first to get a correct content_type default value.
        self._updateFromFS()

        if not kw.has_key('args'):
            kw['args'] = args
        bound_names['options'] = kw

        try:
            response = self.REQUEST.RESPONSE
            if not response.headers.has_key('content-type'):
                response.setHeader('content-type', self.content_type)
        except AttributeError:
            pass

        security = getSecurityManager()
        bound_names['user'] = security.getUser()

        # Retrieve the value from the cache.
        keyset = None
        if self.ZCacheable_isCachingEnabled():
            # Prepare a cache key.
            keyset = {
                # Why oh why?
                # All this code is cut and paste
                # here to make sure that we
                # dont call _getContext and hence can't cache
                # Annoying huh?
                'here': self.aq_parent.getPhysicalPath(),
                'bound_names': bound_names
            }
            result = self.ZCacheable_get(keywords=keyset)
            if result is not None:
                # Got a cached value.
                return result

        # Execute the template in a new security context.
        security.addContext(self)
        try:
            result = self.pt_render(extra_context=bound_names)
            if keyset is not None:
                # Store the result in the cache.
                self.ZCacheable_set(result, keywords=keyset)
            return result
        finally:
            security.removeContext(self)

        return result

    # Copy over more methods
    security.declareProtected(FTPAccess, 'manage_FTPget')
    manage_FTPget = ZopePageTemplate.manage_FTPget.im_func

    security.declareProtected(View, 'get_size')
    get_size = ZopePageTemplate.get_size.im_func
    getSize = get_size

    security.declareProtected(ViewManagementScreens, 'PrincipiaSearchSource')
    PrincipiaSearchSource = ZopePageTemplate.PrincipiaSearchSource.im_func

    security.declareProtected(ViewManagementScreens, 'document_src')
    document_src = ZopePageTemplate.document_src.im_func

    pt_getContext = ZopePageTemplate.pt_getContext.im_func

    ZScriptHTML_tryParams = ZopePageTemplate.ZScriptHTML_tryParams.im_func

    source_dot_xml = Src()
Exemplo n.º 20
0
class FSPythonScript (FSObject, Script):
    """FSPythonScripts act like Python Scripts but are not directly
    modifiable from the management interface."""

    meta_type = 'Filesystem Script (Python)'
    _params = _body = ''
    _v_f = None
    _proxy_roles = ()

    _owner = None  # Unowned

    manage_options=(
        (
            {'label':'Customize', 'action':'manage_main'},
            {'label':'Test',
             'action':'ZScriptHTML_tryForm',
             'help': ('PythonScripts', 'PythonScript_test.stx')},
            )
            + Cacheable.manage_options
        )

    # Use declarative security
    security = ClassSecurityInfo()
    security.declareObjectProtected(View)
    security.declareProtected(View, 'index_html',)
    # Prevent the bindings from being edited TTW
    security.declarePrivate('ZBindings_edit','ZBindingsHTML_editForm',
                            'ZBindingsHTML_editAction')

    security.declareProtected(ViewManagementScreens, 'manage_main')
    manage_main = DTMLResource('dtml/custpy', globals())

    def _createZODBClone(self):
        """Create a ZODB (editable) equivalent of this object."""
        obj = PythonScript(self.getId())
        obj.write(self.read())
        return obj

    def _readFile(self, reparse):
        """Read the data from the filesystem.

        Read the file (indicated by exandpath(self._filepath), and parse the
        data if necessary.
        """
        data = self._readFileAsResourceOrDirect()
        self._write(data, reparse)

    def _validateProxy(self, roles=None):
        pass

    def __render_with_namespace__(self, namespace):
        '''Calls the script.'''
        self._updateFromFS()
        return Script.__render_with_namespace__(self, namespace)

    def __call__(self, *args, **kw):
        '''Calls the script.'''
        self._updateFromFS()
        return Script.__call__(self, *args, **kw)

    #### The following is mainly taken from PythonScript.py ###

    def _exec(self, bound_names, args, kw):
        """Call a Python Script

        Calling a Python Script is an actual function invocation.
        """
        # do caching
        keyset = None
        if self.ZCacheable_isCachingEnabled():
            # Prepare a cache key.
            keyset = kw.copy()
            asgns = self.getBindingAssignments()
            name_context = asgns.getAssignedName('name_context', None)
            if name_context:
                keyset[name_context] = self.aq_parent.getPhysicalPath()
            name_subpath = asgns.getAssignedName('name_subpath', None)
            if name_subpath:
                keyset[name_subpath] = self._getTraverseSubpath()
            # Note: perhaps we should cache based on name_ns also.
            keyset['*'] = args
            result = self.ZCacheable_get(keywords=keyset, default=_marker)
            if result is not _marker:
                # Got a cached value.
                return result

        # Prepare the function.
        f = self._v_f
        if f is None:
            # The script has errors.
            __traceback_supplement__ = (
                FSPythonScriptTracebackSupplement, self, 0)
            raise RuntimeError, '%s has errors.' % self._filepath

        # Updating func_globals directly is not thread safe here.
        # In normal PythonScripts, every thread has its own
        # copy of the function.  But in FSPythonScripts
        # there is only one copy.  So here's another way.
        new_globals = f.func_globals.copy()
        new_globals['__traceback_supplement__'] = (
            FSPythonScriptTracebackSupplement, self)
        if bound_names:
            new_globals.update(bound_names)
        if f.func_defaults:
            f = new.function(f.func_code, new_globals, f.func_name,
                             f.func_defaults)
        else:
            f = new.function(f.func_code, new_globals, f.func_name)

        # Execute the function in a new security context.
        security=getSecurityManager()
        security.addContext(self)
        try:
            result = f(*args, **kw)
            if keyset is not None:
                # Store the result in the cache.
                self.ZCacheable_set(result, keywords=keyset)
            return result
        finally:
            security.removeContext(self)

    security.declareProtected(ViewManagementScreens, 'getModTime')
    # getModTime defined in FSObject

    security.declareProtected(ViewManagementScreens, 'ZScriptHTML_tryForm')
    # ZScriptHTML_tryForm defined in Shared.DC.Scripts.Script.Script

    def ZScriptHTML_tryParams(self):
        """Parameters to test the script with."""
        param_names = []
        for name in self._params.split(','):
            name = name.strip()
            if name and name[0] != '*':
                param_names.append( name.split('=', 1)[0] )
        return param_names

    security.declareProtected(ViewManagementScreens, 'read')
    def read(self):
        self._updateFromFS()
        return self._source

    security.declareProtected(ViewManagementScreens, 'document_src')
    def document_src(self, REQUEST=None, RESPONSE=None):
        """Return unprocessed document source."""

        if RESPONSE is not None:
            RESPONSE.setHeader('Content-Type', 'text/plain')
        return self._source

    security.declareProtected(ViewManagementScreens, 'PrincipiaSearchSource')
    def PrincipiaSearchSource(self):
        "Support for searching - the document's contents are searched."
        return "%s\n%s" % (self._params, self._body)

    security.declareProtected(ViewManagementScreens, 'params')
    def params(self): return self._params

    security.declareProtected(ViewManagementScreens, 'manage_haveProxy')
    manage_haveProxy = PythonScript.manage_haveProxy.im_func

    security.declareProtected(ViewManagementScreens, 'body')
    def body(self): return self._body

    security.declareProtected(ViewManagementScreens, 'get_size')
    def get_size(self): return len(self.read())

    security.declareProtected(FTPAccess, 'manage_FTPget')
    def manage_FTPget(self):
        "Get source for FTP download"
        self.REQUEST.RESPONSE.setHeader('Content-Type', 'text/plain')
        return self.read()

    def _write(self, text, compile):
        '''
        Parses the source, storing the body, params, title, bindings,
        and source in self.  If compile is set, compiles the
        function.
        '''
        ps = PythonScript(self.id)
        ps.write(text)
        if compile:
            ps._makeFunction(1)
            self._v_f = f = ps._v_f
            if f is not None:
                self.func_code = f.func_code
                self.func_defaults = f.func_defaults
            else:
                # There were errors in the compile.
                # No signature.
                self.func_code = bad_func_code()
                self.func_defaults = None
        self._body = ps._body
        self._params = ps._params
        if not self.title:
            self.title = ps.title
        self._setupBindings(ps.getBindingAssignments().getAssignedNames())
        self._source = ps.read()  # Find out what the script sees.

    def func_defaults(self):
        # This ensures func_code and func_defaults are
        # set when the code hasn't been compiled yet,
        # just in time for mapply().  Truly odd, but so is mapply(). :P
        self._updateFromFS()
        return self.__dict__.get('func_defaults', None)
    func_defaults = ComputedAttribute(func_defaults, 1)

    def func_code(self):
        # See func_defaults.
        self._updateFromFS()
        return self.__dict__.get('func_code', None)
    func_code = ComputedAttribute(func_code, 1)

    def title(self):
        # See func_defaults.
        self._updateFromFS()
        return self.__dict__.get('title', None)
    title = ComputedAttribute(title, 1)

    def getBindingAssignments(self):
        # Override of the version in Bindings.py.
        # This version ensures that bindings get loaded on demand.
        if not hasattr(self, '_bind_names'):
            # Set a default first to avoid recursion
            self._setupBindings()
            # Now do it for real
            self._updateFromFS()
        return self._bind_names
Exemplo n.º 21
0
class MembershipTool(UniqueObject, Folder, ActionProviderBase):

    """ This tool accesses member data through an acl_users object.

    It can be replaced with something that accesses member data in a
    different way.
    """

    implements(IMembershipTool)
    __implements__ = (z2IMembershipTool, ActionProviderBase.__implements__)

    id = 'portal_membership'
    meta_type = 'CMF Membership Tool'
    memberareaCreationFlag = 1

    security = ClassSecurityInfo()

    manage_options=( ({ 'label' : 'Configuration'
                     , 'action' : 'manage_mapRoles'
                     },) +
                     ActionProviderBase.manage_options +
                   ( { 'label' : 'Overview'
                     , 'action' : 'manage_overview'
                     },
                   ) + Folder.manage_options)

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource( 'dtml/explainMembershipTool', globals() )

    #
    #   'portal_membership' interface methods
    #
    security.declareProtected(ManagePortal, 'manage_mapRoles')
    manage_mapRoles = DTMLResource('dtml/membershipRolemapping', globals() )

    security.declareProtected(SetOwnPassword, 'setPassword')
    def setPassword(self, password, domains=None):
        '''Allows the authenticated member to set his/her own password.
        '''
        registration = getToolByName(self, 'portal_registration', None)
        if not self.isAnonymousUser():
            member = self.getAuthenticatedMember()
            if registration:
                failMessage = registration.testPasswordValidity(password)
                if failMessage is not None:
                    raise BadRequest(failMessage)
            member.setSecurityProfile(password=password, domains=domains)
        else:
            raise BadRequest('Not logged in.')

    security.declarePublic('getAuthenticatedMember')
    def getAuthenticatedMember(self):
        '''
        Returns the currently authenticated member object
        or the Anonymous User.  Never returns None.
        '''
        u = _getAuthenticatedUser(self)
        if u is None:
            u = nobody
        return self.wrapUser(u)

    security.declarePrivate('wrapUser')
    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 = getToolByName(self, 'portal_memberdata', None)
        if mdtool is not None:
            try:
                u = mdtool.wrapUser(u)
            except ConflictError:
                raise
            except:
                from zLOG import LOG, ERROR
                import sys
                LOG('CMFCore.MembershipTool',
                    ERROR,
                    'Error during wrapUser',
                    error=sys.exc_info(),
                    )
        return u

    security.declareProtected(ManagePortal, 'getPortalRoles')
    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.declareProtected(ManagePortal, 'setRoleMapping')
    def setRoleMapping(self, portal_role, userfolder_role):
        """
        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.declareProtected(ManagePortal, 'getMappedRole')
    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.declarePublic('getMembersFolder')
    def getMembersFolder(self):
        """ Get the members folder object.
        """
        parent = aq_parent( aq_inner(self) )
        members = getattr(parent, 'Members', None)
        return members

    security.declareProtected(ManagePortal, 'getMemberareaCreationFlag')
    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.declareProtected(ManagePortal, 'setMemberareaCreationFlag')
    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.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 not members:
            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
        else:
            f_title = "%s's Home" % member_id
            members.manage_addPortalFolder( id=member_id, title=f_title )
            f=getattr(members, member_id)

            f.manage_permission(View,
                                ['Owner','Manager','Reviewer'], 0)
            f.manage_permission(AccessContentsInformation,
                                ['Owner','Manager','Reviewer'], 0)

            # Grant Ownership and Owner role to Member
            f.changeOwnership(member)
            f.__ac_local_roles__ = None
            f.manage_setLocalRoles(member_id, ['Owner'])
        return f

    security.declarePublic('createMemberarea')
    createMemberarea = createMemberArea

    security.declareProtected(ManageUsers, 'deleteMemberArea')
    def deleteMemberArea(self, member_id):
        """ 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.declarePublic('isAnonymousUser')
    def isAnonymousUser(self):
        '''
        Returns 1 if the user is not logged in.
        '''
        u = _getAuthenticatedUser(self)
        if u is None or u.getUserName() == 'Anonymous User':
            return 1
        return 0

    security.declarePublic('checkPermission')
    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.declarePublic('credentialsChanged')
    def credentialsChanged(self, password):
        '''
        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():
            acl_users = self.acl_users
            user = _getAuthenticatedUser(self)
            name = user.getUserName()
            # this really does need to be the user name, and not the user id,
            # because we're dealing with authentication credentials
            if hasattr(acl_users.aq_base, 'credentialsChanged'):
                # Use an interface provided by LoginManager.
                acl_users.credentialsChanged(user, name, password)
            else:
                req = self.REQUEST
                p = getattr(req, '_credentials_changed_path', None)
                if p is not None:
                    # Use an interface provided by CookieCrumbler.
                    change = self.restrictedTraverse(p)
                    change(user, name, password)

    security.declareProtected(ManageUsers, 'getMemberById')
    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 _huntUser(self, username, context):
        """Find user in the hierarchy starting from bottom level 'start'.
        """
        uf = context.acl_users
        while uf is not None:
            user = uf.getUserById(username)
            if user is not None:
                return user
            container = aq_parent(aq_inner(uf))
            parent = aq_parent(aq_inner(container))
            uf = getattr(parent, 'acl_users', None)
        return None

    def __getPUS(self):
        # Gets something we can call getUsers() and getUserNames() on.
        acl_users = self.acl_users
        if hasattr(acl_users, 'getUsers'):
            return acl_users
        else:
            # This hack works around the absence of getUsers() in LoginManager.
            # Gets the PersistentUserSource object that stores our users
            for us in acl_users.UserSourcesGroup.objectValues():
                if us.meta_type == 'Persistent User Source':
                    return us.__of__(acl_users)

    security.declareProtected(ManageUsers, 'listMemberIds')
    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.__getPUS()
        return [ x.getId() for x in user_folder.getUsers() ]

    security.declareProtected(ManageUsers, 'listMembers')
    def listMembers(self):
        '''Gets the list of all members.
        '''
        return map(self.wrapUser, self.__getPUS().getUsers())

    security.declareProtected(ListPortalMembers, 'searchMembers')
    def searchMembers( self, search_param, search_term ):
        """ Search the membership """
        md = getToolByName( self, 'portal_memberdata' )

        return md.searchMemberData( search_param, search_term )

    security.declareProtected(View, 'getCandidateLocalRoles')
    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.declareProtected(View, 'setLocalRoles')
    def setLocalRoles(self, obj, member_ids, member_role, reindex=1):
        """ 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:
            # It is assumed that all objects have the method
            # reindexObjectSecurity, which is in CMFCatalogAware and
            # thus PortalContent and PortalFolder.
            obj.reindexObjectSecurity()

    security.declareProtected(View, 'deleteLocalRoles')
    def deleteLocalRoles(self, obj, member_ids, reindex=1, recursive=0):
        """ 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:
            # reindexObjectSecurity is always recursive
            obj.reindexObjectSecurity()

    security.declarePrivate('addMember')
    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.
        '''
        acl_users = self.acl_users
        if hasattr(acl_users, '_doAddUser'):
            acl_users._doAddUser(id, password, roles, domains)
        else:
            # The acl_users folder is a LoginManager.  Search for a UserSource
            # with the needed support.
            for source in acl_users.UserSourcesGroup.objectValues():
                if hasattr(source, 'addUser'):
                    source.__of__(self).addUser(id, password, roles, domains)
            raise "Can't add Member", "No supported UserSources"

        if properties is not None:
            member = self.getMemberById(id)
            member.setMemberProperties(properties)

    security.declareProtected(ManageUsers, 'deleteMembers')
    def deleteMembers(self, member_ids, delete_memberareas=1,
                      delete_localroles=1):
        """ 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 (NotImplementedError, 'NotImplemented'):
                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 = getToolByName(self, 'portal_memberdata', None)
        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:
            utool = getToolByName(self, 'portal_url', None)
            self.deleteLocalRoles( utool.getPortalObject(), member_ids,
                                   reindex=1, recursive=1 )

        return tuple(member_ids)

    security.declarePublic('getHomeFolder')
    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.declarePublic('getHomeUrl')
    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
Exemplo n.º 22
0
class URLTool(UniqueObject, SimpleItem, ActionProviderBase):
    """ CMF URL Tool.
    """

    implements(IURLTool)
    __implements__ = (z2IURLTool, ActionProviderBase.__implements__)

    id = 'portal_url'
    meta_type = 'CMF URL Tool'

    security = ClassSecurityInfo()
    security.declareObjectProtected(View)

    manage_options = (ActionProviderBase.manage_options +
                      ({
                          'label': 'Overview',
                          'action': 'manage_overview'
                      }, ) + SimpleItem.manage_options)

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource('dtml/explainURLTool', globals())

    #
    #   'portal_url' interface methods
    #
    security.declarePublic('__call__')

    def __call__(self, relative=0, *args, **kw):
        """ Get by default the absolute URL of the portal.
        """
        return self.getPortalObject().absolute_url(relative=relative)

    security.declarePublic('getPortalObject')

    def getPortalObject(self):
        """ Get the portal object itself.
        """
        return aq_parent(aq_inner(self))

    security.declarePublic('getRelativeContentPath')

    def getRelativeContentPath(self, content):
        """ Get the path for an object, relative to the portal root.
        """
        portal_path_length = len(self.getPortalObject().getPhysicalPath())
        content_path = content.getPhysicalPath()
        return content_path[portal_path_length:]

    security.declarePublic('getRelativeContentURL')

    def getRelativeContentURL(self, content):
        """ Get the URL for an object, relative to the portal root.
        """
        return '/'.join(self.getRelativeContentPath(content))

    security.declarePublic('getRelativeUrl')
    getRelativeUrl = getRelativeContentURL

    security.declarePublic('getPortalPath')

    def getPortalPath(self):
        """ Get the portal object's URL without the server URL component.
        """
        return '/'.join(self.getPortalObject().getPhysicalPath())
Exemplo n.º 23
0
class CMFCatalogAware(Base):
    """Mix-in for notifying portal_catalog and portal_workflow
    """

    security = ClassSecurityInfo()

    # The following methods can be overriden using inheritence so that
    # it's possible to specifiy another catalog tool or workflow tool
    # for a given content type

    def _getCatalogTool(self):
        return getToolByName(self, 'portal_catalog', None)

    def _getWorkflowTool(self):
        return getToolByName(self, 'portal_workflow', None)

    # Cataloging methods
    # ------------------

    security.declareProtected(ModifyPortalContent, 'indexObject')

    def indexObject(self):
        """
            Index the object in the portal catalog.
        """
        catalog = self._getCatalogTool()
        if catalog is not None:
            catalog.indexObject(self)

    security.declareProtected(ModifyPortalContent, 'unindexObject')

    def unindexObject(self):
        """
            Unindex the object from the portal catalog.
        """
        catalog = self._getCatalogTool()
        if catalog is not None:
            catalog.unindexObject(self)

    security.declareProtected(ModifyPortalContent, 'reindexObject')

    def reindexObject(self, idxs=[]):
        """
            Reindex the object in the portal catalog.
            If idxs is present, only those indexes are reindexed.
            The metadata is always updated.

            Also update the modification date of the object,
            unless specific indexes were requested.
        """
        if idxs == []:
            # Update the modification date.
            if hasattr(aq_base(self), 'notifyModified'):
                self.notifyModified()
        catalog = self._getCatalogTool()
        if catalog is not None:
            catalog.reindexObject(self, idxs=idxs)

    _cmf_security_indexes = ('allowedRolesAndUsers', )

    security.declareProtected(ModifyPortalContent, 'reindexObjectSecurity')

    def reindexObjectSecurity(self, skip_self=False):
        """Reindex security-related indexes on the object.

        Recurses in the children to reindex them too.

        If skip_self is True, only the children will be reindexed. This
        is a useful optimization if the object itself has just been
        fully reindexed, as there's no need to reindex its security twice.
        """
        catalog = self._getCatalogTool()
        if catalog is None:
            return
        path = '/'.join(self.getPhysicalPath())

        # XXX if _getCatalogTool() is overriden we will have to change
        # this method for the sub-objects.
        for brain in catalog.unrestrictedSearchResults(path=path):
            brain_path = brain.getPath()
            if brain_path == path and skip_self:
                continue
            # Get the object
            ob = brain._unrestrictedGetObject()
            if ob is None:
                # BBB: Ignore old references to deleted objects.
                # Can happen only when using
                # catalog-getObject-raises off in Zope 2.8
                LOG('reindexObjectSecurity', PROBLEM,
                    "Cannot get %s from catalog" % brain_path)
                continue
            # Recatalog with the same catalog uid.
            s = getattr(ob, '_p_changed', 0)
            catalog.reindexObject(ob,
                                  idxs=self._cmf_security_indexes,
                                  update_metadata=0,
                                  uid=brain_path)
            if s is None: ob._p_deactivate()

    # Workflow methods
    # ----------------

    security.declarePrivate('notifyWorkflowCreated')

    def notifyWorkflowCreated(self):
        """
            Notify the workflow that self was just created.
        """
        wftool = self._getWorkflowTool()
        if wftool is not None:
            wftool.notifyCreated(self)

    # Opaque subitems
    # ---------------

    security.declareProtected(AccessContentsInformation, 'opaqueItems')

    def opaqueItems(self):
        """
            Return opaque items (subelements that are contained
            using something that is not an ObjectManager).
        """
        items = []

        # Call 'talkback' knowing that it is an opaque item.
        # This will remain here as long as the discussion item does
        # not implement ICallableOpaqueItem (backwards compatibility).
        if hasattr(aq_base(self), 'talkback'):
            talkback = self.talkback
            if talkback is not None:
                items.append((talkback.id, talkback))

        # Other opaque items than 'talkback' may have callable
        # manage_after* and manage_before* hooks.
        # Loop over all attributes and add those to 'items'
        # implementing 'ICallableOpaqueItem'.
        self_base = aq_base(self)
        for name in self_base.__dict__.keys():
            obj = getattr(self_base, name)
            if ICallableOpaqueItem.providedBy(obj) \
                    or z2ICallableOpaqueItem.isImplementedBy(obj):
                items.append((obj.getId(), obj))

        return tuple(items)

    security.declareProtected(AccessContentsInformation, 'opaqueIds')

    def opaqueIds(self):
        """
            Return opaque ids (subelements that are contained
            using something that is not an ObjectManager).
        """
        return [t[0] for t in self.opaqueItems()]

    security.declareProtected(AccessContentsInformation, 'opaqueValues')

    def opaqueValues(self):
        """
            Return opaque values (subelements that are contained
            using something that is not an ObjectManager).
        """
        return [t[1] for t in self.opaqueItems()]

    # Hooks
    # -----

    def manage_afterAdd(self, item, container):
        """
            Add self to the catalog.
            (Called when the object is created or moved.)
        """
        self.indexObject()
        self.__recurse('manage_afterAdd', item, container)

    def manage_afterClone(self, item):
        """
            Add self to the workflow.
            (Called when the object is cloned.)
        """
        self.notifyWorkflowCreated()
        self.__recurse('manage_afterClone', item)

        # Make sure owner local role is set after pasting
        # The standard Zope mechanisms take care of executable ownership
        current_user = _getAuthenticatedUser(self)
        if current_user is not None:
            local_role_holders = [x[0] for x in self.get_local_roles()]
            self.manage_delLocalRoles(local_role_holders)
            self.manage_setLocalRoles(current_user.getId(), ['Owner'])

    def manage_beforeDelete(self, item, container):
        """
            Remove self from the catalog.
            (Called when the object is deleted or moved.)
        """
        self.__recurse('manage_beforeDelete', item, container)
        self.unindexObject()

    def __recurse(self, name, *args):
        """
            Recurse in both normal and opaque subobjects.
        """
        values = self.objectValues()
        opaque_values = self.opaqueValues()
        for subobjects in values, opaque_values:
            for ob in subobjects:
                s = getattr(ob, '_p_changed', 0)
                if hasattr(aq_base(ob), name):
                    getattr(ob, name)(*args)
                if s is None: ob._p_deactivate()

    # ZMI
    # ---

    manage_options = ({
        'label': 'Workflows',
        'action': 'manage_workflowsTab',
    }, )

    _manage_workflowsTab = DTMLResource('dtml/zmi_workflows', globals())

    security.declareProtected(ManagePortal, 'manage_workflowsTab')

    def manage_workflowsTab(self, REQUEST, manage_tabs_message=None):
        """
            Tab displaying the current workflows for the content object.
        """
        ob = self
        wftool = self._getWorkflowTool()
        # XXX None ?
        if wftool is not None:
            wf_ids = wftool.getChainFor(ob)
            states = {}
            chain = []
            for wf_id in wf_ids:
                wf = wftool.getWorkflowById(wf_id)
                if wf is not None:
                    # XXX a standard API would be nice
                    if hasattr(wf, 'getReviewStateOf'):
                        # Default Workflow
                        state = wf.getReviewStateOf(ob)
                    elif hasattr(wf, '_getWorkflowStateOf'):
                        # DCWorkflow
                        state = wf._getWorkflowStateOf(ob, id_only=1)
                    else:
                        state = '(Unknown)'
                    states[wf_id] = state
                    chain.append(wf_id)
        return self._manage_workflowsTab(
            REQUEST,
            chain=chain,
            states=states,
            management_view='Workflows',
            manage_tabs_message=manage_tabs_message)
Exemplo n.º 24
0
class DiscussionTool(UniqueObject, SimpleItem, ActionProviderBase):

    implements(IOldstyleDiscussionTool)
    __implements__ = (z2IOldstyleDiscussionTool,
                      ActionProviderBase.__implements__)

    id = 'portal_discussion'
    meta_type = 'Oldstyle CMF Discussion Tool'
    # This tool is used to find the discussion for a given content object.

    security = ClassSecurityInfo()

    manage_options = ({
        'label': 'Overview',
        'action': 'manage_overview'
    }, ) + SimpleItem.manage_options

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLResource('dtml/explainDiscussionTool', globals())

    #
    #   'portal_discussion' interface methods
    #
    security.declarePublic('getDiscussionFor')

    def getDiscussionFor(self, content):
        '''Gets the PortalDiscussion object that applies to content.
        '''
        return OldDiscussable(content).__of__(content)

    security.declarePublic('isDiscussionAllowedFor')

    def isDiscussionAllowedFor(self, content):
        '''
            Returns a boolean indicating whether a discussion is
            allowed for the specified content.
        '''
        if hasattr(content, 'allow_discussion'):
            return content.allow_discussion
        typeInfo = getToolByName(self, 'portal_types').getTypeInfo(content)
        if typeInfo:
            return typeInfo.allowDiscussion()
        return 0

    security.declarePrivate('listActions')

    def listActions(self, info=None, object=None):
        # Return actions for reply and show replies
        if object is not None or info is None:
            info = self._getOAI(object)
        content = info.object
        if content is None or not self.isDiscussionAllowedFor(content):
            return ()

        discussion = self.getDiscussionFor(content)
        if discussion.aq_base == content.aq_base:
            discussion_url = info.object_url
        else:
            discussion_url = discussion.absolute_url()

        actions = ({
            'name': 'Reply',
            'url': discussion_url + '/discussion_reply_form',
            'permissions': [ReplyToItem],
            'category': 'object'
        }, )

        return actions
Exemplo n.º 25
0
class FSSTXMethod( FSObject ):
    """
        A chunk of StructuredText, rendered as a skin method of a
        CMFSite.
    """

    meta_type = 'Filesystem STX Method'

    manage_options=( { 'label'      : 'Customize'
                     , 'action'     : 'manage_main'
                     }
                   , { 'label'      : 'View'
                     , 'action'     : ''
                     , 'help'       : ('OFSP'
                                      ,'DTML-DocumentOrMethod_View.stx'
                                      )
                     }
                   )

    security = ClassSecurityInfo()
    security.declareObjectProtected( View )

    security.declareProtected( ViewManagementScreens, 'manage_main')
    manage_main = DTMLResource( 'dtml/custstx', globals() )

    #
    #   FSObject interface
    #
    def _createZODBClone(self):
        """
            Create a ZODB (editable) equivalent of this object.
        """
        raise NotImplementedError, "See next week's model."

    def _readFile( self, reparse ):

        self.raw = self._readFileAsResourceOrDirect()
        if reparse:
            self.cook()

    #
    #   "Wesleyan" interface (we need to be "methodish").
    #
    class func_code:
        pass

    func_code=func_code()
    func_code.co_varnames= ()
    func_code.co_argcount=0
    func_code.__roles__=()

    func_defaults__roles__=()
    func_defaults=()

    index_html = None   # No accidental acquisition

    default_content_type = 'text/html'

    def cook( self ):
        if not hasattr( self, '_v_cooked' ):
            self._v_cooked = HTML(self.raw, level=1, header=0)
        return self._v_cooked

    _default_template = HTML( """\
<dtml-var standard_html_header>
<div class="Desktop">
<dtml-var cooked>
</div>
<dtml-var standard_html_footer>""" )

    def __call__( self, REQUEST={}, RESPONSE=None, **kw ):
        """
            Return our rendered StructuredText.
        """
        self._updateFromFS()

        if RESPONSE is not None:
            RESPONSE.setHeader( 'Content-Type', 'text/html' )
        return self._render(REQUEST, RESPONSE, **kw)

    security.declarePrivate( '_render' )
    def _render( self, REQUEST={}, RESPONSE=None, **kw ):
        """
            Find the appropriate rendering template and use it to
            render us.
        """
        template = getattr( self, 'stxmethod_view', self._default_template )

        if getattr( template, 'isDocTemp', 0 ):
            posargs = ( self, REQUEST, RESPONSE )
        else:
            posargs = ()

        return template(*posargs, **{ 'cooked' : self.cook() } )

    security.declareProtected( FTPAccess, 'manage_FTPget' )
    def manage_FTPget( self ):
        """
            Fetch our source for delivery via FTP.
        """
        return self.raw

    security.declareProtected( ViewManagementScreens, 'PrincipiaSearchSource' )
    def PrincipiaSearchSource( self ):
        """
            Fetch our source for indexing in a catalog.
        """
        return self.raw

    security.declareProtected( ViewManagementScreens, 'document_src' )
    def document_src( self ):
        """
            Fetch our source for indexing in a catalog.
        """
        return self.raw
Exemplo n.º 26
0
class WorkflowTool(UniqueObject, Folder, ActionProviderBase):

    """ Mediator tool, mapping workflow objects
    """

    implements(IWorkflowTool)
    __implements__ = (z2IWorkflowTool, ActionProviderBase.__implements__)

    id = 'portal_workflow'
    meta_type = 'CMF Workflow Tool'

    _chains_by_type = None  # PersistentMapping
    _default_chain = ('default_workflow',)
    _default_cataloging = 1

    security = ClassSecurityInfo()

    manage_options = ( { 'label' : 'Workflows'
                       , 'action' : 'manage_selectWorkflows'
                       }
                     , { 'label' : 'Overview', 'action' : 'manage_overview' }
                     ) + Folder.manage_options

    #
    #   ZMI methods
    #
    security.declareProtected( ManagePortal, 'manage_overview' )
    manage_overview = DTMLResource( 'dtml/explainWorkflowTool', globals() )

    _manage_addWorkflowForm = DTMLResource('dtml/addWorkflow', globals())

    security.declareProtected( ManagePortal, 'manage_addWorkflowForm')
    def manage_addWorkflowForm(self, REQUEST):

        """ Form for adding workflows.
        """
        wft = []
        for key in _workflow_factories.keys():
            wft.append(key)
        wft.sort()
        return self._manage_addWorkflowForm(REQUEST, workflow_types=wft)

    security.declareProtected( ManagePortal, 'manage_addWorkflow')
    def manage_addWorkflow(self, workflow_type, id, RESPONSE=None):

        """ Adds a workflow from the registered types.
        """
        factory = _workflow_factories[workflow_type]
        ob = factory(id)
        self._setObject(id, ob)
        if RESPONSE is not None:
            RESPONSE.redirect(self.absolute_url() +
                              '/manage_main?management_view=Contents')

    def all_meta_types(self):
        return (
            {'name': 'Workflow',
             'action': 'manage_addWorkflowForm',
             'permission': ManagePortal },)

    _manage_selectWorkflows = DTMLResource('dtml/selectWorkflows', globals())

    security.declareProtected( ManagePortal, 'manage_selectWorkflows')
    def manage_selectWorkflows(self, REQUEST, manage_tabs_message=None):

        """ Show a management screen for changing type to workflow connections.
        """
        cbt = self._chains_by_type
        ti = self._listTypeInfo()
        types_info = []
        for t in ti:
            id = t.getId()
            title = t.Title()
            if title == id:
                title = None
            if cbt is not None and cbt.has_key(id):
                chain = ', '.join(cbt[id])
            else:
                chain = '(Default)'
            types_info.append({'id': id,
                               'title': title,
                               'chain': chain})
        return self._manage_selectWorkflows(
            REQUEST,
            default_chain=', '.join(self._default_chain),
            types_info=types_info,
            management_view='Workflows',
            manage_tabs_message=manage_tabs_message)

    security.declareProtected( ManagePortal, 'manage_changeWorkflows')
    def manage_changeWorkflows(self, default_chain, props=None, REQUEST=None):

        """ Changes which workflows apply to objects of which type.
        """
        if props is None:
            props = REQUEST
        cbt = self._chains_by_type
        if cbt is None:
            self._chains_by_type = cbt = PersistentMapping()
        ti = self._listTypeInfo()
        # Set up the chains by type.
        if not (props is None):
            for t in ti:
                id = t.getId()
                field_name = 'chain_%s' % id
                chain = props.get(field_name, '(Default)').strip()
                if chain == '(Default)':
                    # Remove from cbt.
                    if cbt.has_key(id):
                        del cbt[id]
                else:
                    chain = chain.replace(',', ' ')
                    ids = []
                    for wf_id in chain.split(' '):
                        if wf_id:
                            if not self.getWorkflowById(wf_id):
                                raise ValueError, (
                                    '"%s" is not a workflow ID.' % wf_id)
                            ids.append(wf_id)
                    cbt[id] = tuple(ids)
        # Set up the default chain.
        default_chain = default_chain.replace(',', ' ')
        ids = []
        for wf_id in default_chain.split(' '):
            if wf_id:
                if not self.getWorkflowById(wf_id):
                    raise ValueError, (
                        '"%s" is not a workflow ID.' % wf_id)
                ids.append(wf_id)
        self._default_chain = tuple(ids)
        if REQUEST is not None:
            return self.manage_selectWorkflows(REQUEST,
                            manage_tabs_message='Changed.')

    #
    #   portal_workflow implementation.
    #
    security.declarePrivate('getCatalogVariablesFor')
    def getCatalogVariablesFor(self, ob):

        """ Returns a mapping of the catalog variables that apply to ob.

        o Invoked by portal_catalog.

        o Allows workflows to add variables to the catalog based on
          workflow status, making it possible to implement queues.
        """
        wfs = self.getWorkflowsFor(ob)
        if wfs is None:
            return None
        # Iterate through the workflows backwards so that
        # earlier workflows can override later workflows.
        wfs.reverse()
        vars = {}
        for wf in wfs:
            v = wf.getCatalogVariablesFor(ob)
            if v is not None:
                vars.update(v)
        return vars

    security.declarePrivate('listActions')
    def listActions(self, info=None, object=None):

        """ Returns a list of actions to be displayed to the user.

        o Invoked by the portal_actions tool.

        o Allows workflows to include actions to be displayed in the
          actions box.

        o Object actions are supplied by workflows that apply to the object.

        o Global actions are supplied by all workflows.
        """
        if object is not None or info is None:
            info = self._getOAI(object)
        chain = self.getChainFor(info.object)
        did = {}
        actions = []

        for wf_id in chain:
            did[wf_id] = 1
            wf = self.getWorkflowById(wf_id)
            if wf is not None:
                a = wf.listObjectActions(info)
                if a is not None:
                    actions.extend(a)
                a = wf.listGlobalActions(info)
                if a is not None:
                    actions.extend(a)

        wf_ids = self.getWorkflowIds()
        for wf_id in wf_ids:
            if not did.has_key(wf_id):
                wf = self.getWorkflowById(wf_id)
                if wf is not None:
                    a = wf.listGlobalActions(info)
                    if a is not None:
                        actions.extend(a)
        return actions

    security.declarePublic('getActionsFor')
    def getActionsFor(self, ob):

        """ Return a list of action dictionaries for 'ob', just as though
            queried via 'ActionsTool.listFilteredActionsFor'.
        """
        warn('getActionsFor() is deprecated and will be removed in CMF 1.7. '
             'Please use listActionInfos() instead.',
             DeprecationWarning)
        return self.listActions( WorkflowInformation( ob ) )

    security.declarePublic('doActionFor')
    def doActionFor(self, ob, action, wf_id=None, *args, **kw):

        """ Execute the given workflow action for the object.

        o Invoked by user interface code.

        o Allows the user to request a workflow action.

        o The workflow object must perform its own security checks.
        """
        wfs = self.getWorkflowsFor(ob)
        if wfs is None:
            wfs = ()
        if wf_id is None:
            if not wfs:
                raise WorkflowException('No workflows found.')
            found = 0
            for wf in wfs:
                if wf.isActionSupported(ob, action, **kw):
                    found = 1
                    break
            if not found:
                raise WorkflowException(
                    'No workflow provides the "%s" action.' % action)
        else:
            wf = self.getWorkflowById(wf_id)
            if wf is None:
                raise WorkflowException(
                    'Requested workflow definition not found.')
        return self._invokeWithNotification(
            wfs, ob, action, wf.doActionFor, (ob, action) + args, kw)

    security.declarePublic('getInfoFor')
    def getInfoFor(self, ob, name, default=_marker, wf_id=None, *args, **kw):

        """ Return a given workflow-specific property for an object.

        o Invoked by user interface code.

        o Allows the user to request information provided by the workflow.

        o The workflow object must perform its own security checks.
        """
        if wf_id is None:
            wfs = self.getWorkflowsFor(ob)
            if wfs is None:
                if default is _marker:
                    raise WorkflowException('No workflows found.')
                else:
                    return default
            found = 0
            for wf in wfs:
                if wf.isInfoSupported(ob, name):
                    found = 1
                    break
            if not found:
                if default is _marker:
                    raise WorkflowException(
                        'No workflow provides "%s" information.' % name)
                else:
                    return default
        else:
            wf = self.getWorkflowById(wf_id)
            if wf is None:
                if default is _marker:
                    raise WorkflowException(
                        'Requested workflow definition not found.')
                else:
                    return default
        res = wf.getInfoFor(ob, name, default, *args, **kw)
        if res is _marker:
            raise WorkflowException('Could not get info: %s' % name)
        return res

    security.declarePrivate('notifyCreated')
    def notifyCreated(self, ob):

        """ Notify all applicable workflows that an object has been created
            and put in its new place.
        """
        wfs = self.getWorkflowsFor(ob)
        for wf in wfs:
            wf.notifyCreated(ob)
        self._reindexWorkflowVariables(ob)

    security.declarePrivate('notifyBefore')
    def notifyBefore(self, ob, action):

        """ Notifies all applicable workflows of an action before it
            happens, allowing veto by exception.

        o Unless an exception is thrown, either a notifySuccess() or
          notifyException() can be expected later on.

        o The action usually corresponds to a method name.
        """
        wfs = self.getWorkflowsFor(ob)
        for wf in wfs:
            wf.notifyBefore(ob, action)

    security.declarePrivate('notifySuccess')
    def notifySuccess(self, ob, action, result=None):

        """ Notify all applicable workflows that an action has taken place.
        """
        wfs = self.getWorkflowsFor(ob)
        for wf in wfs:
            wf.notifySuccess(ob, action, result)

    security.declarePrivate('notifyException')
    def notifyException(self, ob, action, exc):

        """ Notify all applicable workflows that an action failed.
        """
        wfs = self.getWorkflowsFor(ob)
        for wf in wfs:
            wf.notifyException(ob, action, exc)

    security.declarePrivate('getHistoryOf')
    def getHistoryOf(self, wf_id, ob):

        """ Return the history of an object.

        o Invoked by workflow definitions.
        """
        if hasattr(aq_base(ob), 'workflow_history'):
            wfh = ob.workflow_history
            return wfh.get(wf_id, None)
        return ()

    security.declarePrivate('getStatusOf')
    def getStatusOf(self, wf_id, ob):

        """ Return the last entry of a workflow history.

        o Invoked by workflow definitions.
        """
        wfh = self.getHistoryOf(wf_id, ob)
        if wfh:
            return wfh[-1]
        return None

    security.declarePrivate('setStatusOf')
    def setStatusOf(self, wf_id, ob, status):

        """ Append an entry to the workflow history.

        o Invoked by workflow definitions.
        """
        wfh = None
        has_history = 0
        if hasattr(aq_base(ob), 'workflow_history'):
            history = ob.workflow_history
            if history is not None:
                has_history = 1
                wfh = history.get(wf_id, None)
                if wfh is not None:
                    wfh = list(wfh)
        if not wfh:
            wfh = []
        wfh.append(status)
        if not has_history:
            ob.workflow_history = PersistentMapping()
        ob.workflow_history[wf_id] = tuple(wfh)

    #
    #   Administration methods
    #
    security.declareProtected( ManagePortal, 'setDefaultChain')
    def setDefaultChain(self, default_chain):

        """ Set the default chain for this tool
        """
        default_chain = default_chain.replace(',', ' ')
        ids = []
        for wf_id in default_chain.split(' '):
            if wf_id:
                if not self.getWorkflowById(wf_id):
                    raise ValueError, ( '"%s" is not a workflow ID.' % wf_id)
                ids.append(wf_id)

        self._default_chain = tuple(ids)

    security.declareProtected( ManagePortal, 'setChainForPortalTypes')
    def setChainForPortalTypes(self, pt_names, chain):

        """ Set a chain for a specific portal type.
        """
        cbt = self._chains_by_type
        if cbt is None:
            self._chains_by_type = cbt = PersistentMapping()

        if isinstance(chain, basestring):
            chain = [ wf.strip() for wf in chain.split(',') if wf.strip() ]

        ti = self._listTypeInfo()
        for t in ti:
            id = t.getId()
            if id in pt_names:
                cbt[id] = tuple(chain)


    security.declareProtected( ManagePortal, 'updateRoleMappings')
    def updateRoleMappings(self, REQUEST=None):

        """ Allow workflows to update the role-permission mappings.
        """
        wfs = {}
        for id in self.objectIds():
            wf = self.getWorkflowById(id)
            if hasattr(aq_base(wf), 'updateRoleMappingsFor'):
                wfs[id] = wf
        portal = aq_parent(aq_inner(self))
        count = self._recursiveUpdateRoleMappings(portal, wfs)
        if REQUEST is not None:
            return self.manage_selectWorkflows(REQUEST, manage_tabs_message=
                                               '%d object(s) updated.' % count)
        else:
            return count

    security.declarePrivate('getWorkflowById')
    def getWorkflowById(self, wf_id):

        """ Retrieve a given workflow.
        """
        wf = getattr(self, wf_id, None)
        if getattr(wf, '_isAWorkflow', 0):
            return wf
        else:
            return None

    security.declarePrivate('getDefaultChainFor')
    def getDefaultChainFor(self, ob):

        """ Return the default chain, if applicable, for ob.
        """
        types_tool = getToolByName( self, 'portal_types', None )
        if ( types_tool is not None
            and types_tool.getTypeInfo( ob ) is not None ):
            return self._default_chain

        return ()

    security.declarePrivate('getChainFor')
    def getChainFor(self, ob):

        """ Returns the chain that applies to the given object.
            If we get a string as the ob parameter, use it as
            the portal_type.
        """
        cbt = self._chains_by_type
        if isinstance(ob, basestring):
            pt = ob
        elif hasattr(aq_base(ob), 'getPortalTypeName'):
            pt = ob.getPortalTypeName()
        else:
            pt = None

        if pt is None:
            return ()

        chain = None
        if cbt is not None:
            chain = cbt.get(pt, None)
            # Note that if chain is not in cbt or has a value of
            # None, we use a default chain.
        if chain is None:
            chain = self.getDefaultChainFor(ob)
            if chain is None:
                return ()
        return chain

    security.declarePrivate('getWorkflowIds')
    def getWorkflowIds(self):

        """ Return the list of workflow ids.
        """
        wf_ids = []

        for obj_name, obj in self.objectItems():
            if getattr(obj, '_isAWorkflow', 0):
                wf_ids.append(obj_name)

        return tuple(wf_ids)

    security.declareProtected(ManagePortal, 'getWorkflowsFor')
    def getWorkflowsFor(self, ob):

        """ Find the workflows for the type of the given object.
        """
        res = []
        for wf_id in self.getChainFor(ob):
            wf = self.getWorkflowById(wf_id)
            if wf is not None:
                res.append(wf)
        return res

    #
    #   Helper methods
    #
    security.declarePrivate( '_listTypeInfo' )
    def _listTypeInfo(self):

        """ List the portal types which are available.
        """
        pt = getToolByName(self, 'portal_types', None)
        if pt is None:
            return ()
        else:
            return pt.listTypeInfo()

    security.declarePrivate( '_invokeWithNotification' )
    def _invokeWithNotification(self, wfs, ob, action, func, args, kw):

        """ Private utility method:  call 'func', and deal with exceptions
            indicating that the object has been deleted or moved.
        """
        reindex = 1
        for w in wfs:
            w.notifyBefore(ob, action)
        try:
            res = func(*args, **kw)
        except ObjectDeleted, ex:
            res = ex.getResult()
            reindex = 0
        except ObjectMoved, ex:
            res = ex.getResult()
            ob = ex.getNewObject()
Exemplo n.º 27
0
class ExtensionPredicate(SimpleItem):
    """
        Predicate matching on filename extensions.
    """

    implements(IContentTypeRegistryPredicate)
    __implements__ = z2IContentTypeRegistryPredicate

    extensions = None
    PREDICATE_TYPE = 'extension'

    security = ClassSecurityInfo()

    def __init__(self, id):
        self.id = id

    security.declareProtected(ManagePortal, 'getExtensions')

    def getExtensions(self):
        """ Get filename extensions.
        """
        if self.extensions is None:
            return 'None'
        return ' '.join(self.extensions)

    security.declareProtected(ManagePortal, 'edit')

    def edit(self, extensions, COMMA_SPLIT=re.compile(r'[, ]')):

        if extensions == 'None':
            extensions = None
        if type(extensions) is type(''):
            extensions = filter(None, COMMA_SPLIT.split(extensions))

        self.extensions = extensions

    #
    #   ContentTypeRegistryPredicate interface
    #
    security.declareObjectPublic()

    def __call__(self, name, typ, body):
        """
            Return true if the rule matches, else false.
        """
        if self.extensions is None:
            return 0

        base, ext = os.path.splitext(name)
        if ext and ext[0] == '.':
            ext = ext[1:]

        return ext in self.extensions

    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 = DTMLResource('dtml/extensionWidget', globals())
Exemplo n.º 28
0
class CachingPolicyManager(SimpleItem):
    """
        Manage the set of CachingPolicy objects for the site;  dispatch
        to them from skin methods.
    """

    implements(ICachingPolicyManager)
    __implements__ = z2ICachingPolicyManager

    id = 'caching_policy_manager'
    meta_type = 'CMF Caching Policy Manager'

    security = ClassSecurityInfo()

    def __init__(self):
        self._policy_ids = ()
        self._policies = PersistentMapping()

    #
    #   ZMI
    #
    manage_options = (({
        'label': 'Policies',
        'action': 'manage_cachingPolicies',
        'help': ('CMFCore', 'CPMPolicies.stx')
    }, ) + SimpleItem.manage_options)

    security.declareProtected(ManagePortal, 'manage_cachingPolicies')
    manage_cachingPolicies = DTMLResource('dtml/cachingPolicies', globals())

    security.declarePublic('listPolicies')

    def listPolicies(self):
        """
            Return a sequence of tuples,
            '( policy_id, ( policy, typeObjectName ) )'
            for all policies in the registry 
        """
        result = []
        for policy_id in self._policy_ids:
            result.append((policy_id, self._policies[policy_id]))
        return tuple(result)

    security.declareProtected(ManagePortal, 'addPolicy')

    def addPolicy(
            self,
            policy_id,
            predicate  # TALES expr (def. 'python:1')
        ,
            mtime_func  # TALES expr (def. 'object/modified')
        ,
            max_age_secs  # integer, seconds (def. 0)
        ,
            no_cache  # boolean (def. 0)
        ,
            no_store  # boolean (def. 0)
        ,
            must_revalidate  # boolean (def. 0)
        ,
            vary  # string value
        ,
            etag_func  # TALES expr (def. '')
        ,
            REQUEST=None,
            s_max_age_secs=None  # integer, seconds (def. None)
        ,
            proxy_revalidate=0  # boolean (def. 0)
        ,
            public=0  # boolean (def. 0)
        ,
            private=0  # boolean (def. 0)
        ,
            no_transform=0  # boolean (def. 0)
        ,
            enable_304s=0  # boolean (def. 0)
        ,
            last_modified=1  # boolean (def. 1)
        ,
            pre_check=None  # integer, default None
        ,
            post_check=None  # integer, default None
    ):
        """
            Add a caching policy.
        """
        if max_age_secs is None or str(max_age_secs).strip() == '':
            max_age_secs = None
        else:
            max_age_secs = int(max_age_secs)

        if s_max_age_secs is None or str(s_max_age_secs).strip() == '':
            s_max_age_secs = None
        else:
            s_max_age_secs = int(s_max_age_secs)

        if pre_check is None or str(pre_check).strip() == '':
            pre_check = None
        else:
            pre_check = int(pre_check)

        if post_check is None or str(post_check).strip() == '':
            post_check = None
        else:
            post_check = int(post_check)

        self._addPolicy(policy_id, predicate, mtime_func, max_age_secs,
                        no_cache, no_store, must_revalidate, vary, etag_func,
                        s_max_age_secs, proxy_revalidate, public, private,
                        no_transform, enable_304s, last_modified, pre_check,
                        post_check)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                         '/manage_cachingPolicies' +
                                         '?manage_tabs_message=' +
                                         'Policy+added.')

    security.declareProtected(ManagePortal, 'updatePolicy')

    def updatePolicy(
            self,
            policy_id,
            predicate  # TALES expr (def. 'python:1')
        ,
            mtime_func  # TALES expr (def. 'object/modified')
        ,
            max_age_secs  # integer, seconds (def. 0)
        ,
            no_cache  # boolean (def. 0)
        ,
            no_store  # boolean (def. 0)
        ,
            must_revalidate  # boolean (def. 0)
        ,
            vary  # string value
        ,
            etag_func  # TALES expr (def. '')
        ,
            REQUEST=None,
            s_max_age_secs=None  # integer, seconds (def. 0)
        ,
            proxy_revalidate=0  # boolean (def. 0)
        ,
            public=0  # boolean (def. 0)
        ,
            private=0  # boolean (def. 0)
        ,
            no_transform=0  # boolean (def. 0)
        ,
            enable_304s=0  # boolean (def. 0)
        ,
            last_modified=1  # boolean (def. 1)
        ,
            pre_check=0  # integer, default=None
        ,
            post_check=0  # integer, default=None
    ):
        """
            Update a caching policy.
        """
        if max_age_secs is None or str(max_age_secs).strip() == '':
            max_age_secs = None
        else:
            max_age_secs = int(max_age_secs)

        if s_max_age_secs is None or str(s_max_age_secs).strip() == '':
            s_max_age_secs = None
        else:
            s_max_age_secs = int(s_max_age_secs)

        if pre_check is None or str(pre_check).strip() == '':
            pre_check = None
        else:
            pre_check = int(pre_check)

        if post_check is None or str(post_check).strip() == '':
            post_check = None
        else:
            post_check = int(post_check)

        self._updatePolicy(policy_id, predicate, mtime_func, max_age_secs,
                           no_cache, no_store, must_revalidate, vary,
                           etag_func, s_max_age_secs, proxy_revalidate, public,
                           private, no_transform, enable_304s, last_modified,
                           pre_check, post_check)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                         '/manage_cachingPolicies' +
                                         '?manage_tabs_message=' +
                                         'Policy+updated.')

    security.declareProtected(ManagePortal, 'movePolicyUp')

    def movePolicyUp(self, policy_id, REQUEST=None):
        """
            Move a caching policy up in the list.
        """
        policy_ids = list(self._policy_ids)
        ndx = policy_ids.index(policy_id)
        if ndx == 0:
            msg = "Policy+already+first."
        else:
            self._reorderPolicy(policy_id, ndx - 1)
            msg = "Policy+moved."
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                         '/manage_cachingPolicies' +
                                         '?manage_tabs_message=%s' % msg)

    security.declareProtected(ManagePortal, 'movePolicyDown')

    def movePolicyDown(self, policy_id, REQUEST=None):
        """
            Move a caching policy down in the list.
        """
        policy_ids = list(self._policy_ids)
        ndx = policy_ids.index(policy_id)
        if ndx == len(policy_ids) - 1:
            msg = "Policy+already+last."
        else:
            self._reorderPolicy(policy_id, ndx + 1)
            msg = "Policy+moved."
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                         '/manage_cachingPolicies' +
                                         '?manage_tabs_message=%s' % msg)

    security.declareProtected(ManagePortal, 'removePolicy')

    def removePolicy(self, policy_id, REQUEST=None):
        """
            Remove a caching policy.
        """
        self._removePolicy(policy_id)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(
                self.absolute_url() + '/manage_cachingPolicies' +
                '?manage_tabs_message=Policy+removed.')

    #
    #   Policy manipulation methods.
    #
    security.declarePrivate('_addPolicy')

    def _addPolicy(self,
                   policy_id,
                   predicate,
                   mtime_func,
                   max_age_secs,
                   no_cache,
                   no_store,
                   must_revalidate,
                   vary,
                   etag_func,
                   s_max_age_secs=None,
                   proxy_revalidate=0,
                   public=0,
                   private=0,
                   no_transform=0,
                   enable_304s=0,
                   last_modified=1,
                   pre_check=None,
                   post_check=None):
        """
            Add a policy to our registry.
        """
        policy_id = str(policy_id).strip()

        if not policy_id:
            raise ValueError, "Policy ID is required!"

        if policy_id in self._policy_ids:
            raise KeyError, "Policy %s already exists!" % policy_id

        self._policies[policy_id] = CachingPolicy(
            policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store,
            must_revalidate, vary, etag_func, s_max_age_secs, proxy_revalidate,
            public, private, no_transform, enable_304s, last_modified,
            pre_check, post_check)
        idlist = list(self._policy_ids)
        idlist.append(policy_id)
        self._policy_ids = tuple(idlist)

    security.declarePrivate('_updatePolicy')

    def _updatePolicy(self,
                      policy_id,
                      predicate,
                      mtime_func,
                      max_age_secs,
                      no_cache,
                      no_store,
                      must_revalidate,
                      vary,
                      etag_func,
                      s_max_age_secs=None,
                      proxy_revalidate=0,
                      public=0,
                      private=0,
                      no_transform=0,
                      enable_304s=0,
                      last_modified=1,
                      pre_check=None,
                      post_check=None):
        """
            Update a policy in our registry.
        """
        if policy_id not in self._policy_ids:
            raise KeyError, "Policy %s does not exist!" % policy_id

        self._policies[policy_id] = CachingPolicy(
            policy_id, predicate, mtime_func, max_age_secs, no_cache, no_store,
            must_revalidate, vary, etag_func, s_max_age_secs, proxy_revalidate,
            public, private, no_transform, enable_304s, last_modified,
            pre_check, post_check)

    security.declarePrivate('_reorderPolicy')

    def _reorderPolicy(self, policy_id, newIndex):
        """
            Reorder a policy in our registry.
        """
        if policy_id not in self._policy_ids:
            raise KeyError, "Policy %s does not exist!" % policy_id

        idlist = list(self._policy_ids)
        ndx = idlist.index(policy_id)
        pred = idlist[ndx]
        idlist = idlist[:ndx] + idlist[ndx + 1:]
        idlist.insert(newIndex, pred)
        self._policy_ids = tuple(idlist)

    security.declarePrivate('_removePolicy')

    def _removePolicy(self, policy_id):
        """
            Remove a policy from our registry.
        """
        if policy_id not in self._policy_ids:
            raise KeyError, "Policy %s does not exist!" % policy_id

        del self._policies[policy_id]
        idlist = list(self._policy_ids)
        ndx = idlist.index(policy_id)
        idlist = idlist[:ndx] + idlist[ndx + 1:]
        self._policy_ids = tuple(idlist)

    #
    #   'portal_caching' interface methods
    #
    security.declareProtected(View, 'getHTTPCachingHeaders')

    def getHTTPCachingHeaders(self, content, view_method, keywords, time=None):
        """
            Return a list of HTTP caching headers based on 'content',
            'view_method', and 'keywords'.
        """
        context = createCPContext(content, view_method, keywords, time=time)
        for policy_id, policy in self.listPolicies():

            headers = policy.getHeaders(context)
            if headers:
                return headers

        return ()

    security.declareProtected(View, 'getModTimeAndETag')

    def getModTimeAndETag(self, content, view_method, keywords, time=None):
        """ Return the modification time and ETag for the content object,
            view method, and keywords as the tuple (modification_time, etag,
            set_last_modified_header), where modification_time is a DateTime,
            or None.
        """
        context = createCPContext(content, view_method, keywords, time=time)
        for policy_id, policy in self.listPolicies():
            if policy.getEnable304s() and policy.testPredicate(context):

                last_modified = policy._mtime_func(context)
                if type(last_modified) is type(''):
                    last_modified = DateTime(last_modified)

                content_etag = None
                if policy.getETagFunc():
                    content_etag = policy._etag_func(context)

                return (last_modified, content_etag, policy.getLastModified())

        return None
Exemplo n.º 29
0
class FSImage(FSObject):
    """FSImages act like images but are not directly
    modifiable from the management interface."""
    # Note that OFS.Image.Image is not a base class because it is mutable.

    meta_type = 'Filesystem Image'

    _data = None

    manage_options = ({
        'label': 'Customize',
        'action': 'manage_main'
    }, ) + Cacheable.manage_options

    security = ClassSecurityInfo()
    security.declareObjectProtected(View)

    def __init__(self,
                 id,
                 package=None,
                 entry_subpath=None,
                 filepath=None,
                 fullname=None,
                 properties=None):
        id = fullname or id  # Use the whole filename.
        FSObject.__init__(self, id, package, entry_subpath, filepath, fullname,
                          properties)

    security.declareProtected(ViewManagementScreens, 'manage_main')
    manage_main = DTMLResource('dtml/custimage', globals())
    content_type = 'unknown/unknown'

    def _createZODBClone(self):
        return Image(self.getId(), '', self._readFile(1))

    def _readFile(self, reparse):
        data = self._data = self._readFileAsResourceOrDirect()
        if reparse or self.content_type == 'unknown/unknown':
            self.ZCacheable_invalidate()
            ct, width, height = getImageInfo(data)
            self.content_type = ct
            self.width = width
            self.height = height
        return data

    #### The following is mainly taken from OFS/Image.py ###

    __str__ = Image.__str__.im_func

    _image_tag = Image.tag.im_func
    security.declareProtected(View, 'tag')

    def tag(self, *args, **kw):
        # Hook into an opportunity to reload metadata.
        self._updateFromFS()
        return self._image_tag(*args, **kw)

    security.declareProtected(View, 'index_html')

    def index_html(self, REQUEST, RESPONSE):
        """
        The default view of the contents of a File or Image.

        Returns the contents of the file or image.  Also, sets the
        Content-Type HTTP header to the objects content type.
        """
        self._updateFromFS()
        data = self._data
        data_len = len(data)
        last_mod = self._file_mod_time
        status = 200
        # HTTP If-Modified-Since header handling.
        header = REQUEST.get_header('If-Modified-Since', None)
        if header is not None:
            header = header.split(';')[0]
            # Some proxies seem to send invalid date strings for this
            # header. If the date string is not valid, we ignore it
            # rather than raise an error to be generally consistent
            # with common servers such as Apache (which can usually
            # understand the screwy date string as a lucky side effect
            # of the way they parse it).
            try:
                mod_since = long(DateTime(header).timeTime())
            except:
                mod_since = None

            if mod_since is not None:
                if last_mod > 0 and last_mod <= mod_since:
                    status = 304
                    data = ''

        #Last-Modified will get stomped on by a cache policy it there is
        #one set....
        RESPONSE.setStatus(status)
        RESPONSE.setHeader('Last-Modified', rfc1123_date(last_mod))
        RESPONSE.setHeader('Content-Type', self.content_type)

        if status != 304:
            # Avoid setting content-length for a 304. See RFC 2616.
            # Zope might still, for better or for worse, set a
            # content-length header with value "0".
            RESPONSE.setHeader('Content-Length', data_len)

        #There are 2 Cache Managers which can be in play....
        #need to decide which to use to determine where the cache headers
        #are decided on.
        if self.ZCacheable_getManager() is not None:
            self.ZCacheable_set(None)
        else:
            _setCacheHeaders(_ViewEmulator().__of__(self), extra_context={})
        return data

    security.declareProtected(View, 'getContentType')

    def getContentType(self):
        """Get the content type of a file or image.

        Returns the content type (MIME type) of a file or image.
        """
        self._updateFromFS()
        return self.content_type

    security.declareProtected(View, 'get_size')

    def get_size(self):
        """
            Return the size of the image.
        """
        self._updateFromFS()
        return self._data and len(self._data) or 0

    security.declareProtected(FTPAccess, 'manage_FTPget')
    manage_FTPget = index_html