ILoginPasswordHostExtractionPlugin
from Products.PluggableAuthService.interfaces.plugins import \
        IChallengePlugin
from Products.PluggableAuthService.interfaces.plugins import \
        ICredentialsUpdatePlugin
from Products.PluggableAuthService.interfaces.plugins import \
        ICredentialsResetPlugin
from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
from Products.PluggableAuthService.utils import classImplements

class IInlineAuthHelper(Interface):
    """ Marker interface.
    """


manage_addInlineAuthHelperForm = PageTemplateFile(
    'www/iaAdd', globals(), __name__='manage_addInlineAuthHelperForm')


def addInlineAuthHelper( dispatcher
                       , id
                       , title=None
                       , REQUEST=None
                       ):
    """ Add an Inline Auth Helper to a Pluggable Auth Service. """
    iah = InlineAuthHelper(id, title)
    dispatcher._setObject(iah.getId(), iah)

    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect( '%s/manage_workspace'
                                      '?manage_tabs_message='
                                      'InlineAuthHelper+added.'
Beispiel #2
0
class Reference(Referenceable, SimpleItem):
    ## Added base level support for referencing References
    ## They respond to the UUID protocols, but are not
    ## catalog aware. This means that you can't move/rename
    ## reference objects and expect them to work, but you can't
    ## do this anyway. However they should fine the correct
    ## events when they are added/deleted, etc

    implements(IReference)

    security = ClassSecurityInfo()
    portal_type = 'Reference'
    meta_type = 'Reference'

    # XXX FIXME more security

    manage_options = (({
        'label': 'View',
        'action': 'manage_view'
    }, ) + SimpleItem.manage_options)

    security.declareProtected(permissions.ManagePortal, 'manage_view')
    manage_view = PageTemplateFile('view_reference', _www)

    def __init__(self, id, sid, tid, relationship, **kwargs):
        self.id = id
        setattr(self, UUID_ATTR, id)

        self.sourceUID = sid
        self.targetUID = tid
        self.relationship = relationship

        self.__dict__.update(kwargs)

    def __repr__(self):
        return "<Reference sid:%s tid:%s rel:%s>" % (
            self.sourceUID, self.targetUID, self.relationship)

    def UID(self):
        # the uid method for compat.
        return IUUID(self, None)

    # Convenience methods

    def getSourceObject(self):
        return self._optimizedGetObject(self.sourceUID)

    def getTargetObject(self):
        return self._optimizedGetObject(self.targetUID)

    # Catalog support

    def targetId(self):
        target = self.getTargetObject()
        if target is not None:
            return target.getId()
        return ''

    def targetTitle(self):
        target = self.getTargetObject()
        if target is not None:
            return target.Title()
        return ''

    def Type(self):
        return self.__class__.__name__

    ###
    # Policy hooks, subclass away
    def addHook(self, tool, sourceObject=None, targetObject=None):
        #to reject the reference being added raise a ReferenceException
        pass

    def delHook(self, tool, sourceObject=None, targetObject=None):
        #to reject the delete raise a ReferenceException
        pass

    ###
    # OFS Operations Policy Hooks
    # These Hooks are experimental and subject to change
    def beforeTargetDeleteInformSource(self):
        # Called before target object is deleted so
        # the source can have a say.
        pass

    def beforeSourceDeleteInformTarget(self):
        # Called when the refering source Object is
        # about to be deleted.
        pass

    def manage_afterAdd(self, item, container):
        Referenceable.manage_afterAdd(self, item, container)

        # when copying a full site containe is the container of the plone site
        # and item is the plone site (at least for objects in portal root)
        base = container
        rc = getToolByName(container, REFERENCE_CATALOG)
        url = getRelURL(base, self.getPhysicalPath())
        rc.catalog_object(self, url)

    def manage_beforeDelete(self, item, container):
        Referenceable.manage_beforeDelete(self, item, container)
        rc = getToolByName(container, REFERENCE_CATALOG)
        url = getRelURL(container, self.getPhysicalPath())
        rc.uncatalog_object(url)
class PluggableAuthService(Folder, Cacheable):
    """ All-singing, all-dancing user folder.
    """
    security = ClassSecurityInfo()

    meta_type = 'Pluggable Auth Service'

    _id = id = 'acl_users'

    _emergency_user = emergency_user
    _nobody = nobody

    maxlistusers = -1  # Don't allow local role form to try to list us!

    def getId(self):

        return self._id

    #
    #   IUserFolder implementation
    #
    security.declareProtected(ManageUsers, 'getUser')

    def getUser(self, name):
        """ See IUserFolder.
        """
        plugins = self._getOb('plugins')

        user_info = self._verifyUser(plugins, login=name)

        if not user_info:
            return None

        return self._findUser(plugins, user_info['id'], user_info['login'])

    security.declareProtected(ManageUsers, 'getUserById')

    def getUserById(self, id, default=None):
        """ See IUserFolder.
        """
        plugins = self._getOb('plugins')

        user_info = self._verifyUser(plugins, user_id=id)

        if not user_info:
            return default

        return self._findUser(plugins, user_info['id'], user_info['login'])

    security.declarePublic('validate')  # XXX: public?

    def validate(self, request, auth='', roles=_noroles):
        """ See IUserFolder.
        """
        plugins = self._getOb('plugins')
        is_top = self._isTop()

        user_ids = self._extractUserIds(request, plugins)
        (accessed, container, name,
         value) = self._getObjectContext(request['PUBLISHED'], request)

        for user_id, login in user_ids:

            user = self._findUser(plugins, user_id, login, request=request)

            if aq_base(user) is emergency_user:

                if is_top:
                    return user
                else:
                    return None

            if self._authorizeUser(user, accessed, container, name, value,
                                   roles):
                return user

        if not is_top:
            return None

        #
        #   No other user folder above us can satisfy, and we have no user;
        #   return a constructed anonymous only if anonymous is authorized.
        #
        anonymous = self._createAnonymousUser(plugins)
        if self._authorizeUser(anonymous, accessed, container, name, value,
                               roles):
            return anonymous

        return None

    security.declareProtected(SearchPrincipals, 'searchUsers')

    def searchUsers(self, **kw):
        """ Search for users
        """
        search_id = kw.get('id', None)
        search_name = kw.get('name', None)

        result = []
        max_results = kw.get('max_results', '')
        sort_by = kw.get('sort_by', '')

        # We apply sorting and slicing here across all sets, so don't
        # make the plugin do it
        if sort_by:
            del kw['sort_by']
        if max_results:
            del kw['max_results']
        if search_name:
            if kw.get('id') is not None:
                del kw['id']  # don't even bother searching by id
            kw['login'] = kw['name']

        plugins = self._getOb('plugins')
        enumerators = plugins.listPlugins(IUserEnumerationPlugin)

        for enumerator_id, enum in enumerators:
            try:
                user_list = enum.enumerateUsers(**kw)
                for user_info in user_list:
                    info = {}
                    info.update(user_info)
                    info['userid'] = info['id']
                    info['principal_type'] = 'user'
                    if not info.has_key('title'):
                        info['title'] = info['login']
                    result.append(info)

            except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
                reraise(enum)
                logger.debug('UserEnumerationPlugin %s error' % enumerator_id,
                             exc_info=True)

        if sort_by:
            result.sort(lambda a, b: cmp(
                a.get(sort_by, '').lower(),
                b.get(sort_by, '').lower()))

        if max_results:
            try:
                max_results = int(max_results)
                result = result[:max_results]
            except ValueError:
                pass

        return tuple(result)

    security.declareProtected(SearchPrincipals, 'searchGroups')

    def searchGroups(self, **kw):
        """ Search for groups
        """
        search_id = kw.get('id', None)
        search_name = kw.get('name', None)

        result = []
        max_results = kw.get('max_results', '')
        sort_by = kw.get('sort_by', '')

        # We apply sorting and slicing here across all sets, so don't
        # make the plugin do it
        if sort_by:
            del kw['sort_by']
        if max_results:
            del kw['max_results']
        if search_name:
            if kw.get('id') is not None:
                del kw['id']
            if not kw.has_key('title'):
                kw['title'] = kw['name']

        plugins = self._getOb('plugins')
        enumerators = plugins.listPlugins(IGroupEnumerationPlugin)

        for enumerator_id, enum in enumerators:
            try:
                group_list = enum.enumerateGroups(**kw)
                for group_info in group_list:
                    info = {}
                    info.update(group_info)
                    info['groupid'] = info['id']
                    info['principal_type'] = 'group'
                    if not info.has_key('title'):
                        info['title'] = "(Group) %s" % info['groupid']
                    result.append(info)
            except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
                reraise(enum)
                logger.debug('GroupEnumerationPlugin %s error' % enumerator_id,
                             exc_info=True)

        if sort_by:
            result.sort(lambda a, b: cmp(
                a.get(sort_by, '').lower(),
                b.get(sort_by, '').lower()))

        if max_results:
            try:
                max_results = int(max_results)
                result = result[:max_results + 1]
            except ValueError:
                pass

        return tuple(result)

    security.declareProtected(SearchPrincipals, 'searchPrincipals')

    def searchPrincipals(self, groups_first=False, **kw):
        """ Search for principals (users, groups, or both)
        """
        max_results = kw.get('max_results', '')

        search_id = kw.get('id', None)
        search_name = kw.get('name', None)
        if search_name:
            if not kw.has_key('title'):
                kw['title'] = search_name
            kw['login'] = search_name

        users = [d.copy() for d in self.searchUsers(**kw)]
        groups = [d.copy() for d in self.searchGroups(**kw)]

        if groups_first:
            result = groups + users
        else:
            result = users + groups

        if max_results:
            try:
                max_results = int(max_results)
                result = result[:max_results + 1]
            except ValueError:
                pass

        return tuple(result)

    security.declarePrivate('__creatable_by_emergency_user__')

    def __creatable_by_emergency_user__(self):
        return 1

    security.declarePrivate('_setObject')

    def _setObject(self, id, object, roles=None, user=None, set_owner=0):
        #
        #   Override ObjectManager's version to change the default for
        #   'set_owner' (we don't want to enforce ownership on contained
        #   objects).
        Folder._setObject(self, id, object, roles, user, set_owner)

    security.declarePrivate('_delOb')

    def _delOb(self, id):
        #
        #   Override ObjectManager's version to clean up any plugin
        #   registrations for the deleted object
        #
        plugins = self._getOb('plugins', None)

        if plugins is not None:
            plugins.removePluginById(id)

        Folder._delOb(self, id)

    #
    # ZMI stuff
    #
    arrow_right_gif = ImageFile('www/arrow-right.gif', globals())
    arrow_left_gif = ImageFile('www/arrow-left.gif', globals())
    arrow_up_gif = ImageFile('www/arrow-up.gif', globals())
    arrow_down_gif = ImageFile('www/arrow-down.gif', globals())

    security.declareProtected(ManageUsers, 'manage_search')
    manage_search = PageTemplateFile('www/pasSearch', globals())

    manage_options = (Folder.manage_options[:1] + ({
        'label': 'Search',
        'action': 'manage_search'
    }, ) + Folder.manage_options[2:] + Cacheable.manage_options)

    security.declareProtected(ManageUsers, 'resultsBatch')

    def resultsBatch(self, results, REQUEST, size=20, orphan=2, overlap=0):
        """ ZMI helper for getting batching for displaying search results
        """
        try:
            start_val = REQUEST.get('batch_start', '0')
            start = int(start_val)
            size = int(REQUEST.get('batch_size', size))
        except ValueError:
            start = 0

        batch = Batch(results, size, start, 0, orphan, overlap)

        if batch.end < len(results):
            qs = self._getBatchLink(REQUEST.get('QUERY_STRING', ''), start,
                                    batch.end)
            REQUEST.set('next_batch_url', '%s?%s' % (REQUEST.get('URL'), qs))

        if start > 0:
            new_start = start - size - 1

            if new_start < 0:
                new_start = 0

            qs = self._getBatchLink(REQUEST.get('QUERY_STRING', ''), start,
                                    new_start)
            REQUEST.set('previous_batch_url',
                        '%s?%s' % (REQUEST.get('URL'), qs))

        return batch

    security.declarePrivate('_getBatchLink')

    def _getBatchLink(self, qs, old_start, new_start):
        """ Internal helper to generate correct query strings
        """
        if new_start is not None:
            if not qs:
                qs = 'batch_start=%d' % new_start
            elif qs.startswith('batch_start='):
                qs = qs.replace('batch_start=%d' % old_start,
                                'batch_start=%d' % new_start)
            elif qs.find('&batch_start=') != -1:
                qs = qs.replace('&batch_start=%d' % old_start,
                                '&batch_start=%d' % new_start)
            else:
                qs = '%s&batch_start=%d' % (qs, new_start)

        return qs

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

    def _extractUserIds(self, request, plugins):
        """ request -> [ validated_user_id ]

        o For each set of extracted credentials, try to authenticate
          a user;  accumulate a list of the IDs of such users over all
          our authentication and extraction plugins.
        """
        try:
            extractors = plugins.listPlugins(IExtractionPlugin)
        except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
            logger.debug('Extractor plugin listing error', exc_info=True)
            extractors = ()

        if not extractors:
            extractors = (('default', DumbHTTPExtractor()), )

        try:
            authenticators = plugins.listPlugins(IAuthenticationPlugin)
        except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
            logger.debug('Authenticator plugin listing error', exc_info=True)
            authenticators = ()

        result = []

        for extractor_id, extractor in extractors:

            try:
                credentials = extractor.extractCredentials(request)
            except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
                reraise(extractor)
                logger.debug('ExtractionPlugin %s error' % extractor_id,
                             exc_info=True)
                continue

            if credentials:

                try:
                    credentials['extractor'] = extractor_id  # XXX: in key?
                    # Test if ObjectCacheEntries.aggregateIndex would work
                    items = credentials.items()
                    items.sort()
                except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
                    # XXX: would reraise be good here, and which plugin to ask
                    # whether not to swallow the exception - the extractor?
                    logger.debug('Credentials error: %s' % credentials,
                                 exc_info=True)
                    continue

                # First try to authenticate against the emergency
                # user and return immediately if authenticated
                user_id, name = self._tryEmergencyUserAuthentication(
                    credentials)

                if user_id is not None:
                    return [(user_id, name)]

                # Now see if the user ids can be retrieved from the cache
                view_name = createViewName('_extractUserIds',
                                           credentials.get('login'))
                keywords = createKeywords(**credentials)
                user_ids = self.ZCacheable_get(view_name=view_name,
                                               keywords=keywords,
                                               default=None)
                if user_ids is None:
                    user_ids = []

                    for authenticator_id, auth in authenticators:

                        try:
                            # Masquerading: Authenticate auth_user
                            auth_user_credentials = credentials.copy()

                            login = credentials.get('login', '')

                            auth_user_login, role_user_login = splitmasq(login)

                            if role_user_login is not None:
                                auth_user_credentials[
                                    'login'] = auth_user_login

                            uid_and_info = auth.authenticateCredentials(
                                auth_user_credentials)

                            if uid_and_info is None:
                                continue

                            user_id, info = uid_and_info

                            if role_user_login is not None:

                                # Masquerading: Check if auth_user is allowed to masquerade
                                if self._canMasquerade(plugins, user_id, info,
                                                       request):
                                    logger.info('Masquerading allowed: %s',
                                                login)
                                else:
                                    logger.warn('Masquerading denied: %s',
                                                login)
                                    continue

                                # Masquerading: Return role_user
                                role_user_info = self._verifyUser(
                                    plugins, login=role_user_login)

                                if role_user_info is None:
                                    continue

                                user_id, info = role_user_info[
                                    'id'], role_user_info['login']

                        except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
                            reraise(auth)
                            msg = 'AuthenticationPlugin %s error' % (
                                authenticator_id, )
                            logger.debug(msg, exc_info=True)
                            continue

                        if user_id is not None:
                            user_ids.append((user_id, info))

                    if user_ids:
                        self.ZCacheable_set(user_ids,
                                            view_name=view_name,
                                            keywords=keywords)

                result.extend(user_ids)

        # Emergency user via HTTP basic auth always wins
        user_id, name = self._tryEmergencyUserAuthentication(
            DumbHTTPExtractor().extractCredentials(request))

        if user_id is not None:
            return [(user_id, name)]

        return result

    security.declarePrivate('_tryEmergencyUserAuthentication')

    def _tryEmergencyUserAuthentication(self, credentials):
        """ credentials -> emergency_user or None
        """
        try:
            eua = EmergencyUserAuthenticator()
            user_id, name = eua.authenticateCredentials(credentials)
        except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
            logger.debug('Credentials error: %s' % credentials, exc_info=True)
            user_id, name = (None, None)

        return (user_id, name)

    security.declarePrivate('_getGroupsForPrincipal')

    def _getGroupsForPrincipal(self,
                               principal,
                               request=None,
                               plugins=None,
                               ignore_plugins=None):
        all_groups = {}

        if ignore_plugins is None:
            ignore_plugins = ()

        if plugins is None:
            plugins = self._getOb('plugins')
        groupmakers = plugins.listPlugins(IGroupsPlugin)

        for groupmaker_id, groupmaker in groupmakers:

            if groupmaker_id in ignore_plugins:
                continue
            groups = groupmaker.getGroupsForPrincipal(principal, request)
            for group in groups:
                principal._addGroups([group])
                all_groups[group] = 1

        return all_groups.keys()

    security.declarePrivate('_createAnonymousUser')

    def _createAnonymousUser(self, plugins):
        """ Allow IAnonymousUserFactoryPlugins to create or fall back.
        """
        factories = plugins.listPlugins(IAnonymousUserFactoryPlugin)

        for factory_id, factory in factories:

            anon = factory.createAnonymousUser()

            if anon is not None:
                return anon.__of__(self)

        return nobody.__of__(self)

    security.declarePrivate('_createUser')

    def _createUser(self, plugins, user_id, name):
        """ Allow IUserFactoryPlugins to create, or fall back to default.
        """
        factories = plugins.listPlugins(IUserFactoryPlugin)

        for factory_id, factory in factories:

            user = factory.createUser(user_id, name)

            if user is not None:
                return user.__of__(self)

        return PropertiedUser(user_id, name).__of__(self)

    security.declarePrivate('_canMasquerade')

    def _canMasquerade(self, plugins, user_id, name=None, request=None):
        """ Return True if masquerading is enabled and user_id has the
            Manager or Masquerader role.
        """
        if not masquerading():
            return False

        user = self._findUser(plugins, user_id, name, request)

        if user is not None:
            roles = user.getRoles()

            if 'Manager' in roles or 'Masquerader' in roles:
                return True

        return False

    security.declarePrivate('_findUser')

    def _findUser(self, plugins, user_id, name=None, request=None):
        """ user_id -> decorated_user
        """
        if user_id == self._emergency_user.getUserName():
            return self._emergency_user

        # See if the user can be retrieved from the cache
        view_name = createViewName('_findUser', user_id)
        keywords = createKeywords(user_id=user_id, name=name)
        user = self.ZCacheable_get(view_name=view_name,
                                   keywords=keywords,
                                   default=None)

        if user is None:

            user = self._createUser(plugins, user_id, name)
            propfinders = plugins.listPlugins(IPropertiesPlugin)

            for propfinder_id, propfinder in propfinders:

                data = propfinder.getPropertiesForUser(user, request)
                if data:
                    user.addPropertysheet(propfinder_id, data)

            groups = self._getGroupsForPrincipal(user,
                                                 request,
                                                 plugins=plugins)
            user._addGroups(groups)

            rolemakers = plugins.listPlugins(IRolesPlugin)

            for rolemaker_id, rolemaker in rolemakers:
                try:
                    roles = rolemaker.getRolesForPrincipal(user, request)
                except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
                    logger.debug('IRolesPlugin %s error' % rolemaker_id,
                                 exc_info=True)
                else:
                    if roles:
                        user._addRoles(roles)

            user._addRoles(['Authenticated'])

            # Cache the user if caching is enabled
            base_user = aq_base(user)
            if getattr(base_user, '_p_jar', None) is None:
                self.ZCacheable_set(base_user,
                                    view_name=view_name,
                                    keywords=keywords)

        return user.__of__(self)

    security.declarePrivate('_verifyUser')

    def _verifyUser(self, plugins, user_id=None, login=None):
        """ user_id -> info_dict or None
        """
        if user_id is None and login is None:
            # Avoid possible hugely expensive and/or wrong behavior of
            # plugin enumerators.
            return None

        # Masquerading: Lookup role_user
        auth_user_login, role_user_login = splitmasq(login)
        if role_user_login is not None:
            login = role_user_login

        criteria = {'exact_match': True}

        if user_id is not None:
            criteria['id'] = user_id

        if login is not None:
            criteria['login'] = login

        view_name = createViewName('_verifyUser', user_id or login)
        keywords = createKeywords(**criteria)
        cached_info = self.ZCacheable_get(view_name=view_name,
                                          keywords=keywords,
                                          default=None)

        if cached_info is not None:
            return cached_info

        enumerators = plugins.listPlugins(IUserEnumerationPlugin)

        for enumerator_id, enumerator in enumerators:
            try:
                info = enumerator.enumerateUsers(**criteria)

                if info:
                    # Put the computed value into the cache
                    self.ZCacheable_set(info[0],
                                        view_name=view_name,
                                        keywords=keywords)
                    return info[0]

            except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
                reraise(enumerator)
                msg = 'UserEnumerationPlugin %s error' % enumerator_id
                logger.debug(msg, exc_info=True)

        return None

    security.declarePrivate('_authorizeUser')

    def _authorizeUser(self,
                       user,
                       accessed,
                       container,
                       name,
                       value,
                       roles=_noroles):
        """ -> boolean (whether user has roles).

        o Add the user to the SM's stack, if successful.

        o Return
        """
        user = aq_base(user).__of__(self)
        newSecurityManager(None, user)
        security = getSecurityManager()
        try:
            try:
                if roles is _noroles:
                    if security.validate(accessed, container, name, value):
                        return 1
                else:
                    if security.validate(accessed, container, name, value,
                                         roles):
                        return 1
            except:
                noSecurityManager()
                raise

        except Unauthorized:
            pass

        return 0

    security.declarePrivate('_isTop')

    def _isTop(self):
        """ Are we the user folder in the root object?
        """
        try:
            parent = aq_base(aq_parent(self))
            if parent is None:
                return 0
            return parent.isTopLevelPrincipiaApplicationObject
        except AttributeError:
            return 0

    security.declarePrivate('_getObjectContext')

    def _getObjectContext(self, v, request):
        """ request -> ( a, c, n, v )

        o 'a 'is the object the object was accessed through

        o 'c 'is the physical container of the object

        o 'n 'is the name used to access the object

        o 'v' is the object (value) we're validating access to

        o XXX:  Lifted from AccessControl.User.BasicUserFolder._getobcontext
        """
        if len(request.steps) == 0:  # someone deleted root index_html

            request['RESPONSE'].notFoundError(
                'no default view (root default view was probably deleted)')

        root = request['PARENTS'][-1]
        request_container = aq_parent(root)

        n = request.steps[-1]

        # default to accessed and container as v.aq_parent
        a = c = request['PARENTS'][0]

        # try to find actual container
        inner = aq_inner(v)
        innerparent = aq_parent(inner)

        if innerparent is not None:

            # this is not a method, we needn't treat it specially
            c = innerparent

        elif hasattr(v, 'im_self'):

            # this is a method, we need to treat it specially
            c = v.im_self
            c = aq_inner(v)

        # if pub's aq_parent or container is the request container, it
        # means pub was accessed from the root
        if a is request_container:
            a = root

        if c is request_container:
            c = root

        return a, c, n, v

    security.declarePrivate('_getEmergencyUser')

    def _getEmergencyUser(self):

        return emergency_user.__of__(self)

    security.declarePrivate('_doAddUser')

    def _doAddUser(self, login, password, roles, domains, **kw):
        """ Create a user with login, password and roles if, and only if,
            we have a registered user manager and role manager that will
            accept specific plugin interfaces.
        """
        plugins = self._getOb('plugins')
        useradders = plugins.listPlugins(IUserAdderPlugin)
        roleassigners = plugins.listPlugins(IRoleAssignerPlugin)

        user = None

        if not (useradders and roleassigners):
            raise NotImplementedError("There are no plugins"
                                      " that can create"
                                      " users and assign roles to them.")

        for useradder_id, useradder in useradders:
            if useradder.doAddUser(login, password):
                # XXX: Adds user to cache, but without roles...
                user = self.getUser(login)
                break

        # No useradder was successful.
        if user is None:
            return

        for roleassigner_id, roleassigner in roleassigners:
            for role in roles:
                try:
                    roleassigner.doAssignRoleToPrincipal(user.getId(), role)
                except _SWALLOWABLE_PLUGIN_EXCEPTIONS:
                    reraise(roleassigner)
                    logger.debug('RoleAssigner %s error' % roleassigner_id,
                                 exc_info=True)
                    pass

        if user is not None:
            notify(PrincipalCreated(user))
        return user

    security.declarePublic('all_meta_types')

    def all_meta_types(self):
        """ What objects can be put in here?
        """
        import Products
        allowed_types = tuple(MultiPlugins) + (RAMCacheManager.meta_type, )

        return [x for x in Products.meta_types if x['name'] in allowed_types]

    security.declarePrivate('manage_beforeDelete')

    def manage_beforeDelete(self, item, container):
        if item is self:
            try:
                del container.__allow_groups__
            except:
                pass

            handle = self.meta_type + '/' + self.getId()
            BeforeTraverse.unregisterBeforeTraverse(container, handle)

    security.declarePrivate('manage_afterAdd')

    def manage_afterAdd(self, item, container):
        if item is self:
            container.__allow_groups__ = aq_base(self)

            handle = self.meta_type + '/' + self.getId()
            container = container.this()
            nc = BeforeTraverse.NameCaller(self.getId())
            BeforeTraverse.registerBeforeTraverse(container, nc, handle)

    def __call__(self, container, req):
        """ The __before_publishing_traverse__ hook.
        """
        resp = req['RESPONSE']
        req._hold(ResponseCleanup(resp))
        stack = getattr(resp, '_unauthorized_stack', [])
        stack.append(resp._unauthorized)
        resp._unauthorized_stack = stack
        resp._unauthorized = self._unauthorized
        resp._has_challenged = False

    #
    # Response override
    #
    def _unauthorized(self):
        req = self.REQUEST
        resp = req['RESPONSE']
        if resp._has_challenged:  # Been here already
            return
        if not self.challenge(req, resp):
            # Need to fall back here
            resp = self._cleanupResponse()
            resp._unauthorized()
        else:
            resp._has_challenged = True

    def challenge(self, request, response):
        plugins = self._getOb('plugins')

        # Find valid protocols for this request type
        valid_protocols = []
        choosers = []
        try:
            choosers = plugins.listPlugins(IChallengeProtocolChooser)
        except KeyError:
            # Work around the fact that old instances might not have
            # IChallengeProtocolChooser registered with the
            # PluginRegistry.
            pass

        for chooser_id, chooser in choosers:
            choosen = chooser.chooseProtocols(request)
            if choosen is None:
                continue
            valid_protocols.extend(choosen)

        # Go through all challenge plugins
        challengers = plugins.listPlugins(IChallengePlugin)

        protocol = None

        for challenger_id, challenger in challengers:
            challenger_protocol = getattr(challenger, 'protocol',
                                          challenger_id)
            if valid_protocols and challenger_protocol not in valid_protocols:
                # Skip invalid protocol for this request type.
                continue
            if protocol is None or protocol == challenger_protocol:
                if challenger.challenge(request, response):
                    protocol = challenger_protocol

        if protocol is not None:
            # something fired, so it was a successful PAS challenge
            return True

        # nothing fired, so trigger the fallback
        return False

    def _cleanupResponse(self):
        resp = self.REQUEST['RESPONSE']
        # No errors of any sort may propagate, and we don't care *what*
        # they are, even to log them.
        stack = getattr(resp, '_unauthorized_stack', [])

        if stack:
            resp._unauthorized = stack.pop()
        else:
            try:
                del resp._unauthorized
            except:
                pass

        return resp

    security.declarePublic('hasUsers')

    def hasUsers(self):
        """Zope quick start sacrifice.

        The quick start page expects a hasUsers() method.
        """
        return True

    security.declarePublic('updateCredentials')

    def updateCredentials(self, request, response, login, new_password):
        """Central updateCredentials method

        This method is needed for cases where the credentials storage and
        the credentials extraction is handled by different plugins. Example
        case would be if the CookieAuthHelper is used as a Challenge and
        Extraction plugin only to take advantage of the login page feature
        but the credentials are not stored in the CookieAuthHelper cookie
        but somewhere else, like in a Session.
        """
        plugins = self._getOb('plugins')
        cred_updaters = plugins.listPlugins(ICredentialsUpdatePlugin)

        for updater_id, updater in cred_updaters:
            updater.updateCredentials(request, response, login, new_password)

    security.declarePublic('logout')

    def logout(self, REQUEST):
        """Publicly accessible method to log out a user
        """
        self.resetCredentials(REQUEST, REQUEST['RESPONSE'])

        # Little bit of a hack: Issuing a redirect to the same place
        # where the user was so that in the second request the now-destroyed
        # credentials can be acted upon to e.g. go back to the login page
        referrer = REQUEST.get('HTTP_REFERER')  # optional header
        if referrer:
            REQUEST['RESPONSE'].redirect(referrer)

    security.declarePublic('resetCredentials')

    def resetCredentials(self, request, response):
        """Reset credentials by informing all active resetCredentials plugins
        """
        user = getSecurityManager().getUser()
        if aq_base(user) is not nobody:
            plugins = self._getOb('plugins')
            cred_resetters = plugins.listPlugins(ICredentialsResetPlugin)

            for resetter_id, resetter in cred_resetters:
                resetter.resetCredentials(request, response)
Beispiel #4
0
from App.class_init import InitializeClass
from OFS.SimpleItem import SimpleItem
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from persistent.mapping import PersistentMapping
from be.ldapadmin import ldap_config
from be.ldapadmin import query
from be.ldapadmin.constants import NETWORK_NAME, ADDR_FROM
from be.ldapadmin.ui_common import CommonTemplateLogic
from be.ldapadmin.ui_common import SessionMessages
from be.ldapadmin.ui_common import TemplateRenderer
from be.ldapadmin.logic_common import _create_plain_message, load_template
from be.ldapadmin.users_admin import ldap_edit_users

log = logging.getLogger(__name__)

manage_add_pwreset_tool_html = PageTemplateFile('zpt/pwreset_manage_add',
                                                globals())
manage_add_pwreset_tool_html.ldap_config_edit_macro = ldap_config.edit_macro
manage_add_pwreset_tool_html.config_defaults = lambda: ldap_config.defaults


def manage_add_pwreset_tool(parent, id, REQUEST=None):
    """ Create a new PasswordResetTool object """
    form = (REQUEST is not None and REQUEST.form or {})
    config = ldap_config.read_form(form)
    obj = PasswordResetTool(config)
    obj.title = form.get('title', id)
    obj._setId(id)
    parent._setObject(id, obj)

    if REQUEST is not None:
        REQUEST.RESPONSE.redirect(parent.absolute_url() + '/manage_workspace')
Beispiel #5
0
# [email protected]

from AccessControl import ClassSecurityInfo
from App.class_init import default__class_init__ as InitializeClass
from OFS.Cache import Cacheable
from Products.PageTemplates.PageTemplateFile import PageTemplateFile

from zope.interface import implements

from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
from Products.membrane.interfaces.plugins import IMembraneRoleManagerPlugin
from Products.membrane.interfaces import user as user_ifaces
from Products.membrane.utils import findMembraneUserAspect

manage_addMembraneRoleManagerForm = PageTemplateFile(
    '../www/MembraneRoleManagerForm', globals(),
    __name__='manage_addMembraneRoleManager')


def addMembraneRoleManager(dispatcher, id, title=None, REQUEST=None):
    """ Add a MembraneRoleManager to a Pluggable Auth Service. """
    pmm = MembraneRoleManager(id, title)
    dispatcher._setObject(pmm.getId(), pmm)

    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect(
            '%s/manage_workspace'
            '?manage_tabs_message='
            'MembraneRoleManager+added.'
            % dispatcher.absolute_url())
Beispiel #6
0
class CalendarTool (UniqueObject, SimpleItem):

    """ A tool for encapsulating how calendars work and are displayed """

    id = 'portal_calendar'
    meta_type= 'CMF Calendar Tool'
    security = ClassSecurityInfo()

    implements(ICalendarTool)

    calendar_types = ('Event',)
    calendar_states = ('published',)
    use_session = False
    firstweekday = 6 # 6 is Sunday

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

    #
    #   ZMI methods
    #
    security.declareProtected( ManagePortal, 'manage_overview' )
    manage_overview = PageTemplateFile('www/explainCalendarTool', globals(),
                                   __name__='manage_overview')

    security.declareProtected( ManagePortal, 'manage_configure' )
    manage_configure = PageTemplateFile('www/configureCalendarTool', globals(),
                                   __name__='manage_configure')

    security.declareProtected( ManagePortal, 'edit_configuration' )
    def edit_configuration( self
                          , show_types
                          , use_session
                          , show_states=None
                          , firstweekday=None
                          ):
        """ Change the configuration of the calendar tool 
        """
        # XXX: this method violates the rules for tools/utilities:
        # it depends on self.REQUEST
        self.calendar_types = tuple(show_types)
        self.use_session = bool(use_session)

        if show_states is not None:
            self.calendar_states = tuple(show_states)

        if firstweekday is not None:
            try:
                fwd = int(firstweekday)

                if 0 <= fwd <= 6:
                    # Do nothing with illegal values
                    self.firstweekday = fwd
            except ValueError:
                # Do nothing with illegal values
                pass

        if hasattr(self.REQUEST, 'RESPONSE'):
            self.REQUEST.RESPONSE.redirect('manage_configure')

    security.declarePrivate('_getCalendar')
    def _getCalendar(self):
        """ Wrapper to ensure we set the first day of the week every time
        """
        calendar.setfirstweekday(self.getFirstWeekDay())
        return calendar

    security.declarePublic('getFirstWeekDay')
    def getFirstWeekDay(self):
        """ Get our first weekday setting
        """
        return self.firstweekday

    security.declarePublic('getCalendarTypes')
    def getCalendarTypes(self):
        """ Returns a list of type that will show in the calendar 
        """
        return self.calendar_types

    security.declarePublic('getCalendarStates')
    def getCalendarStates(self):
        """ Returns a list of workflow states that will show in the calendar 
        """
        return self.calendar_states

    security.declarePublic('getUseSession')
    def getUseSession(self):
        """ Returns the Use_Session option 
        """
        return bool(self.use_session)

    security.declarePublic('getDays')
    def getDays(self):
        """ Returns a list of days with the correct start day first 
        """
        return self._getCalendar().weekheader(2).split()

    security.declarePublic('getWeeksList')
    def getWeeksList(self, month='1', year='2002'):
        """ Return a series of weeks, each containing an integer day number.
        A day number of 0 means that day is in the previous or next month.
        """
        year = int(year)
        month = int(month)
        # daysByWeek is a list of days inside a list of weeks, like so:
        # [[0, 1, 2, 3, 4, 5, 6],
        #  [7, 8, 9, 10, 11, 12, 13],
        #  [14, 15, 16, 17, 18, 19, 20],
        #  [21, 22, 23, 24, 25, 26, 27],
        #  [28, 29, 30, 31, 0, 0, 0]]
        daysByWeek = self._getCalendar().monthcalendar(year, month)

        return daysByWeek

    security.declarePublic('getEventsForCalendar')
    def getEventsForCalendar(self, month='1', year='2002'):
        """ recreates a sequence of weeks, by days each day is a mapping.
            {'day': #, 'url': None}
        """
        year = int(year)
        month = int(month)
        # daysByWeek is a list of days inside a list of weeks, like so:
        # [[0, 1, 2, 3, 4, 5, 6],
        #  [7, 8, 9, 10, 11, 12, 13],
        #  [14, 15, 16, 17, 18, 19, 20],
        #  [21, 22, 23, 24, 25, 26, 27],
        #  [28, 29, 30, 31, 0, 0, 0]]
        daysByWeek = self._getCalendar().monthcalendar(year, month)
        weeks = []

        events = self.catalog_getevents(year, month)

        for week in daysByWeek:
            days = []
            for day in week:
                if events.has_key(day):
                    days.append(events[day])
                else:
                    days.append({'day': day, 'event': 0, 'eventslist':[]})

            weeks.append(days)

        return weeks

    security.declarePublic('catalog_getevents')
    def catalog_getevents(self, year, month):
        """ given a year and month return a list of days that have events 
        """
        # XXX: this method violates the rules for tools/utilities:
        # it depends on a non-utility tool
        year = int(year)
        month = int(month)
        last_day = self._getCalendar().monthrange(year, month)[1]
        first_date = self.getBeginAndEndTimes(1, month, year)[0]
        last_date = self.getBeginAndEndTimes(last_day, month, year)[1]

        ctool = getToolByName(self, 'portal_catalog')
        query = ctool(
                        portal_type=self.getCalendarTypes(),
                        review_state=self.getCalendarStates(),
                        start={'query': last_date, 'range': 'max'},
                        end={'query': first_date, 'range': 'min'},
                        sort_on='start' )

        # compile a list of the days that have events
        eventDays={}
        for daynumber in range(1, 32): # 1 to 31
            eventDays[daynumber] = {'eventslist': [],
                                    'event': 0,
                                    'day': daynumber}
        includedevents = []
        for result in query:
            if result.getRID() in includedevents:
                break
            else:
                includedevents.append(result.getRID())
            event={}
            # we need to deal with events that end next month
            if  result.end.greaterThan(last_date):
                eventEndDay = last_day
                event['end'] = None
            else:
                eventEndDay = result.end.day()
                if result.end == result.end.earliestTime():
                    event['end'] = (result.end - 1).latestTime().Time()
                else:
                    event['end'] = result.end.Time()
            # and events that started last month
            if result.start.lessThan(first_date):
                eventStartDay = 1
                event['start'] = None
            else:
                eventStartDay = result.start.day()
                event['start'] = result.start.Time()

            event['title'] = result.Title or result.getId

            if eventStartDay != eventEndDay:
                allEventDays = range(eventStartDay, eventEndDay+1)
                eventDays[eventStartDay]['eventslist'].append(
                        {'end': None,
                         'start': result.start.Time(),
                         'title': event['title']} )
                eventDays[eventStartDay]['event'] = 1

                for eventday in allEventDays[1:-1]:
                    eventDays[eventday]['eventslist'].append(
                        {'end': None,
                         'start': None,
                         'title': event['title']} )
                    eventDays[eventday]['event'] = 1

                if (result.end == result.end.earliestTime() and 
                    event['end'] is not None): 
                    # ends some day this month at midnight
                    last_day_data = eventDays[allEventDays[-2]]
                    last_days_event = last_day_data['eventslist'][-1]
                    last_days_event['end'] = (result.end-1).latestTime().Time()
                else:
                    eventDays[eventEndDay]['eventslist'].append( 
                        { 'end': event['end'],
                          'start': None,
                          'title': event['title']} )
                    eventDays[eventEndDay]['event'] = 1
            else:
                eventDays[eventStartDay]['eventslist'].append(event)
                eventDays[eventStartDay]['event'] = 1
            # This list is not uniqued and isn't sorted
            # uniquing and sorting only wastes time
            # and in this example we don't need to because
            # later we are going to do an 'if 2 in eventDays'
            # so the order is not important.
            # example:  [23, 28, 29, 30, 31, 23]
        return eventDays

    security.declarePublic('getEventsForThisDay')
    def getEventsForThisDay(self, thisDay):
        """ given an exact day return ALL events that:
            A) Start on this day  OR
            B) End on this day  OR
            C) Start before this day  AND  end after this day
        """
        # XXX: this method violates the rules for tools/utilities:
        # it depends on a non-utility tool
        day, month, year = ( int(thisDay.day())
                           , int(thisDay.month())
                           , int(thisDay.year())
                           )

        first_date, last_date = self.getBeginAndEndTimes(day, month, year)
        zone = first_date.localZone()
        after_midnight_str = '%d-%02d-%02d 00:01:00 %s' % (year,month,day,zone)
        after_midnight = DateTime(after_midnight_str)

        # Get all events that Start on this day
        ctool = getToolByName(self, 'portal_catalog')
        query = ctool(
                        portal_type=self.getCalendarTypes(),
                        review_state=self.getCalendarStates(),
                        start={'query': (first_date, last_date),
                               'range': 'minmax'} )

        # Get all events that End on this day
        query += ctool(
                         portal_type=self.getCalendarTypes(),
                         review_state=self.getCalendarStates(),
                         end={'query': (after_midnight, last_date),
                              'range': 'minmax'} )

        # Get all events that Start before this day AND End after this day
        query += ctool(
                         portal_type=self.getCalendarTypes(),
                         review_state=self.getCalendarStates(),
                         start={'query': first_date, 'range': 'max'},
                         end={'query': last_date, 'range': 'min'} )

        # Unique the results
        results = unique_results(query)

        # Sort by start date
        results.sort(sort_by_date)

        return results

    security.declarePublic('getPreviousMonth')
    def getPreviousMonth(self, month, year):
        """ Get a DateTime object for one month prior to the given year/month
        """
        month = int(month)
        year = int(year)

        if month == 0 or month == 1:
            month, year = 12, year - 1
        else:
            month -= 1

        return DateTime(year, month, 1)

    security.declarePublic('getNextMonth')
    def getNextMonth(self, month, year):
        """ Get a DateTime object for one month after the given year/month
        """
        month = int(month)
        year = int(year)

        if month == 12:
            month, year = 1, year + 1
        else:
            month += 1

        return DateTime(year, month, 1)

    security.declarePublic('getBeginAndEndTimes')
    def getBeginAndEndTimes(self, day, month, year):
        """ Get two DateTime objects representing the beginning and end
        of the given day
        """
        day = int(day)
        month = int(month)
        year = int(year)

        begin = DateTime('%d/%02d/%02d 00:00:00' % (year, month, day))
        end = DateTime('%d/%02d/%02d 23:59:59' % (year, month, day))

        return (begin, end)
        
    security.declarePublic('getNextEvent')
    def getNextEvent(self, start_date=None):
        """ Get the next event that starts after start_date
        
        start_date is expected to be a DateTime instance
        """
        # XXX: this method violates the rules for tools/utilities:
        # it depends on a non-utility tool
        if start_date is None:
            start_date = DateTime()

        ctool = getToolByName(self, 'portal_catalog')
        query = ctool(
                    portal_type=self.getCalendarTypes(),
                    review_state=self.getCalendarStates(),
                    start={'query': start_date, 'range': 'min'},
                    sort_on='start')

        results = unique_results(query)
        if results:
            results.sort(sort_by_date)
            return results[0]
class NotificationTool(Folder):
    """ """

    meta_type = core_constants.METATYPE_NOTIFICATIONTOOL
    icon = 'misc_/NaayaCore/NotificationTool.gif'

    meta_types = ()
    all_meta_types = meta_types

    security = ClassSecurityInfo()

    # default configuration settings
    default_config = {
        'admin_on_error': True,
        'admin_on_edit': True,
        'enable_instant': True,
        'enable_daily': True,
        'enable_anonymous': False,  # Enable anonymous notifications
        'daily_hour': 0,
        'enable_weekly': True,
        'weekly_day': 1,  # 1 = monday, 7 = sunday
        'weekly_hour': 0,
        'enable_monthly': True,
        'monthly_day': 1,  # 1 = first day of the month
        'monthly_hour': 0,
        'notif_content_types': [],
    }

    def __init__(self, id, title):
        """ """
        self.id = id
        self.title = title
        self.config = PersistentDict(self.default_config)
        self.timestamps = PersistentDict()
        # Confirmations list
        self.pending_anonymous_subscriptions = PersistentList()

    def get_config(self, key):
        return self.config.get(key)

    def get_location_link(self, location):
        if location:
            return self.restrictedTraverse(location,
                                           self.getSite()).absolute_url()
        else:
            return self.getSite().absolute_url()

    def _validate_subscription(self, **kw):
        """ Validate add/edit subscription for authorized and anonymous users

        """
        if (kw['notif_type'] not in self.available_notif_types(kw['location'])
                and not (kw['notif_type'] == 'administrative'
                         and self.checkPermissionPublishObjects())):
            raise i18n_exception(ValueError, 'Subscribing to ${notif_type} '
                                 'notifications in "${location}" not allowed',
                                 location=kw['location']
                                 or self.getSite().title,
                                 notif_type=kw['notif_type'])
        try:
            obj = self.getSite().restrictedTraverse(kw['location'])
        except:
            raise i18n_exception(ValueError,
                                 'This path is invalid or protected')
        try:
            subscription_container = ISubscriptionContainer(obj)
        except:
            raise i18n_exception(ValueError, 'Cannot subscribe to this folder')

        if kw.get('anonymous', False):
            # Check if subscription exists for this anonymous subscriber
            if not is_valid_email(kw.get('email', '')):
                raise i18n_exception(
                    ValueError, 'Your e-mail address does not appear '
                    'to be valid.')
            for id, subscription in subscription_container.list_with_keys():
                # Normal subscriptions don't have e-mail
                if isinstance(subscription, AnonymousSubscription):
                    if (subscription.email == kw['email']
                            and subscription.notif_type == kw['notif_type']
                            and subscription.lang == kw['lang']):
                        raise i18n_exception(ValueError,
                                             'Subscription already exists')

    def _sitemap_dict(self, form):
        """ Compose a sitemap dict """

        node = form.get('node', '')
        if not node or node == '/':
            node = ''

        def traverse(objects, level=0, stop_level=2, exclude_root=False):
            """ Create a dict with node properties and children.
            This is a fixed level recursion. On some sites there are a lot of
            objects so we don't need to get the whole tree.

            """

            res = []
            for ob in objects:
                if ISubscriptionTarget.providedBy(ob) is False:
                    continue
                children_objects = []
                if level != stop_level:  # Stop if the level is reached
                    # Create a list of object's children
                    if hasattr(ob, 'objectValues'):
                        # Get only naaya container objects
                        for child in ob.objectValues(
                                self.get_naaya_containers_metatypes()):
                            # Skip unsubmited/unapproved
                            if not getattr(child, 'approved', False):
                                continue
                            elif not getattr(child, 'submitted', False):
                                continue
                            else:
                                children_objects.append(child)

                if hasattr(ob, 'approved'):
                    icon = ob.approved and ob.icon or ob.icon_marked
                else:
                    icon = ob.icon

                children = traverse(children_objects, level + 1, stop_level)

                if exclude_root:  # Return only the children if this is set
                    return children

                res.append({
                    'data': {
                        'title':
                        self.utStrEscapeHTMLTags(
                            self.utToUtf8(ob.title_or_id())),
                        'icon':
                        icon
                    },
                    'attributes': {
                        'title': path_in_site(ob)
                    },
                    'children': children
                })
            return res

        if node == '':
            tree_dict = traverse([self.getSite()])
        else:
            tree_dict = traverse([self.restrictedTraverse(node)],
                                 exclude_root=True)
        return tree_dict

    security.declarePublic('sitemap')

    def sitemap(self, REQUEST=None, **kw):
        """ Return a json (for Ajax tree) representation of published objects
        marked with `ISubscriptionTarget` including the portal organized in a
        tree (sitemap)

        """

        form = {}
        if REQUEST is not None:
            form = REQUEST.form
            REQUEST.RESPONSE.setHeader('content-type', 'application/json')
        else:
            form.update(kw)
        return json.dumps(self._sitemap_dict(form))

    security.declarePrivate('add_account_subscription')

    def add_account_subscription(self,
                                 user_id,
                                 location,
                                 notif_type,
                                 lang,
                                 content_types=[]):
        """ Subscribe the user `user_id` """
        self._validate_subscription(user_id=user_id,
                                    location=location,
                                    notif_type=notif_type,
                                    lang=lang,
                                    content_types=content_types)

        try:
            self.remove_account_subscription(user_id, location, notif_type,
                                             lang)
        except ValueError:
            pass

        obj = self.getSite().restrictedTraverse(location)
        subscription_container = ISubscriptionContainer(obj)
        subscription = AccountSubscription(user_id, notif_type, lang,
                                           content_types)
        subscription_container.add(subscription)

    security.declarePrivate('add_anonymous_subscription')

    def add_anonymous_subscription(self, **kw):
        """ Handle anonymous users """
        self._validate_subscription(anonymous=True, **kw)
        subscription = AnonymousSubscription(**kw)
        # Add to temporary container
        self.pending_anonymous_subscriptions.append(subscription)

        # Send email
        email_tool = self.getSite().getEmailTool()
        email_from = email_tool.get_addr_from()
        email_template = EmailPageTemplateFile('emailpt/confirm.zpt',
                                               globals())
        email_data = email_template.render_email(**{
            'key': subscription.key,
            'here': self
        })
        email_to = subscription.email
        email_tool.sendEmail(email_data['body_text'], email_to, email_from,
                             email_data['subject'])

    security.declarePrivate('remove_account_subscription')

    def remove_account_subscription(self,
                                    user_id,
                                    location,
                                    notif_type,
                                    lang,
                                    content_types=None):
        obj = self.getSite().restrictedTraverse(location)
        subscription_container = ISubscriptionContainer(obj)
        n = utils.match_account_subscription(subscription_container, user_id,
                                             notif_type, lang, content_types)
        if n is None:
            raise ValueError('Subscription not found')
        subscription_container.remove(n)

    security.declarePrivate('unsubscribe_links_html')
    unsubscribe_links_html = PageTemplateFile("emailpt/unsubscribe_links.zpt",
                                              globals())
    security.declarePrivate('remove_anonymous_subscription')

    def remove_anonymous_subscription(self, email, location, notif_type, lang):
        try:
            obj = self.getSite().restrictedTraverse(location)
        except:
            raise i18n_exception(ValueError, 'Invalid location')

        try:
            subscription_container = ISubscriptionContainer(obj)
        except:
            raise i18n_exception(ValueError, 'Invalid container')
        anonymous_subscriptions = [
            (n, s) for n, s in subscription_container.list_with_keys()
            if hasattr(s, 'email')
        ]
        subscriptions = filter(
            lambda s: (s[1].email == email and s[1].location == location and s[
                1].notif_type == notif_type), anonymous_subscriptions)
        if len(subscriptions) == 1:
            subscription_container.remove(subscriptions[0][0])
        else:
            raise i18n_exception(ValueError, 'Subscription not found')

    security.declareProtected(view, 'available_notif_types')

    def available_notif_types(self, location=''):
        if self.config['enable_instant']:
            yield 'instant'
        if self.config['enable_daily']:
            yield 'daily'
        if self.config['enable_weekly']:
            yield 'weekly'
        if self.config['enable_monthly']:
            yield 'monthly'

    security.declarePrivate('notify_maintainer')

    def notify_maintainer(self, ob, folder, **kwargs):
        """
        Process and notify by email that B{p_object} has been
        uploaded into the B{p_folder}.
        """

        auth_tool = self.getSite().getAuthenticationTool()
        emails = self.getMaintainersEmails(ob)
        person = self.REQUEST.AUTHENTICATED_USER.getUserName()
        if len(emails) > 0:
            maintainers_data = {}
            for email in emails:
                maintainers_data[email] = {
                    'ob':
                    ob,
                    'here':
                    self,
                    'person':
                    auth_tool.name_from_userid(person),
                    'ob_edited':
                    kwargs.get('ob_edited'),
                    'approved':
                    ob.approved,
                    'container_basket':
                    '%s/basketofapprovals_html' % folder.absolute_url(),
                }
            notif_logger.info('Maintainer notifications on %r', ofs_path(ob))
            template = self._get_template('maintainer')
            self._send_notifications(maintainers_data, template)

    security.declarePrivate('notify_comment_maintainer')

    def notify_comment_maintainer(self, comment, parent, **kwargs):
        """
        Process and notify by email that a comment B{comemnt} has been added
        to the object B{parent}.
        """

        auth_tool = self.getSite().getAuthenticationTool()
        emails = self.getMaintainersEmails(parent)
        if len(emails) > 0:
            maintainers_data = {}
            for email in emails:
                maintainers_data[email] = {
                    'parent':
                    parent,
                    'here':
                    self,
                    'comment':
                    comment,
                    'person':
                    auth_tool.name_from_userid(comment.author),
                    'container_basket':
                    '%s/basketofapprovals_html' % parent.absolute_url(),
                }
            notif_logger.info('Maintainer comment notifications on %r',
                              ofs_path(parent))
            template = self._get_template('maintainer')
            self._send_notifications(maintainers_data, template)

    security.declarePrivate('notify_administrative')

    def notify_administrative(self, ob, user_id, ob_edited=False):
        """
        send administrative notifications because object `ob` was added or
        edited by the user `user_id`
        """

        auth_tool = self.getSite().getAuthenticationTool()
        subscribers_data = utils.get_subscribers_data(
            self,
            ob,
            notif_type='administrative',
            **{
                'person':
                auth_tool.name_from_userid(user_id),
                'ob_edited':
                ob_edited,
                'approved':
                ob.approved,
                'container_basket':
                '%s/basketofapprovals_html' % ob.aq_parent.absolute_url(),
            })

        if len(subscribers_data.keys()) > 0:
            notif_logger.info('Administrative notifications on %r',
                              ofs_path(ob))
            template = self._get_template('administrative')
            self._send_notifications(subscribers_data, template)

    security.declarePrivate('notify_comment_administrative')

    def notify_comment_administrative(self, comment, parent, user_id):
        """
        send administrative notifications because a comment was added to
        object `ob` by the user `user_id`
        """

        auth_tool = self.getSite().getAuthenticationTool()
        subscribers_data = utils.get_subscribers_data(
            self,
            parent,
            notif_type='administrative',
            **{
                'comment': comment,
                'parent': parent,
                'here': self,
                'person': auth_tool.name_from_userid(user_id),
            })

        if len(subscribers_data.keys()) > 0:
            notif_logger.info('Administrative comment notifications on %r',
                              ofs_path(parent))
            template = self._get_template('administrative')
            self._send_notifications(subscribers_data, template)

    security.declarePrivate('notify_instant')

    def notify_instant(self, ob, user_id, ob_edited=False):
        """
        send instant notifications because object `ob` was changed by
        the user `user_id`
        """
        if not self.config['enable_instant']:
            return

        # Don't send notifications if the object is unapproved, but store them
        # into a queue to send them later when it becomes approved
        if not ob.approved:
            return

        auth_tool = self.getSite().getAuthenticationTool()
        subscribers_data = utils.get_subscribers_data(
            self, ob, **{
                'person': auth_tool.name_from_userid(user_id),
                'ob_edited': ob_edited,
            })

        if len(subscribers_data.keys()) > 0:
            notif_logger.info('Instant notifications on %r', ofs_path(ob))
            template = self._get_template('instant')
            self._send_notifications(subscribers_data, template)

    security.declarePrivate('notify_comment_instant')

    def notify_comment_instant(self, comment, parent, user_id):
        """
        send instant notifications because a comment was added to
        object `ob` by the user `user_id`
        """
        if not self.config['enable_instant']:
            return

        # Don't send notifications if the object is unapproved, but store them
        # into a queue to send them later when it becomes approved
        if not parent.approved:
            return

        auth_tool = self.getSite().getAuthenticationTool()
        subscribers_data = utils.get_subscribers_data(
            self, parent, **{
                'comment': comment,
                'parent': parent,
                'person': auth_tool.name_from_userid(user_id),
            })

        if len(subscribers_data.keys()) > 0:
            notif_logger.info('Comment instant notifications on %r',
                              ofs_path(parent))
            template = self._get_template('instant')
            self._send_notifications(subscribers_data, template)

    security.declarePrivate('notify_account_modification')

    def notify_account_modification(self,
                                    email,
                                    obj,
                                    username=None,
                                    new_roles=[],
                                    removed_roles=[]):
        """
        Send notification that the user received or lost one or more roles
        in the specified location
        """
        # Try to fix encoding for roles entered in other languages
        new_roles = [role.decode('utf8') for role in new_roles]
        removed_roles = [role.decode('utf8') for role in removed_roles]
        email_data = {
            email: {
                'new_roles': new_roles,
                'removed_roles': removed_roles,
                'username': username,
                'obj': obj,
            }
        }

        notif_logger.info('Account modification notification on %s' %
                          self.getSite().getId())
        template = self._get_template('account_modified')
        self._send_notifications(email_data, template)

    def _get_template(self, name):

        template = self._getOb('emailpt_%s' % name, None)
        if template is not None:
            return template.render_email

        template = self._getOb(name, None)
        if template is not None:
            return template.render_email

        template = email_templates.get(name, None)
        if template is not None:
            return template.render_email

        raise ValueError('template for %r not found' % name)

    def _send_notifications(self, messages_by_email, template):
        """
        Send the notifications described in the `messages_by_email` data
        structure, using the specified EmailTemplate.

        `messages_by_email` should be a dictionary, keyed by email
        address. The values should be dictionaries suitable to be passed
        as kwargs (options) to the template.
        """
        portal = self.getSite()
        email_tool = portal.getEmailTool()
        addr_from = email_tool.get_addr_from()
        for addr_to, kwargs in messages_by_email.iteritems():
            translate = self.portal_i18n.get_translation
            kwargs.update({'portal': portal, '_translate': translate})
            mail_data = template(**kwargs)
            notif_logger.info('.. sending notification to %r', addr_to)
            utils.send_notification(email_tool, addr_from, addr_to,
                                    mail_data['subject'],
                                    mail_data['body_text'])

    def _send_newsletter(self, notif_type, when_start, when_end):
        """
        We'll look in the ``Products.Naaya.NySite.getActionLogger`` for object
        creation/modification log entries. Then we'll send notifications for
        the period between `when_start` and `when_end` using the
        `notif_type` template.

        """
        notif_logger.info(
            'Notifications newsletter on site %r, type %r, '
            'from %s to %s', ofs_path(self.getSite()), notif_type, when_start,
            when_end)
        objects_by_email = {}
        langs_by_email = {}
        subscriptions_by_email = {}
        anonymous_users = {}
        for log_type, ob in utils.get_modified_objects(self.getSite(),
                                                       when_start, when_end):
            notif_logger.info('.. modified object: %r', ofs_path(ob))
            for subscription in utils.fetch_subscriptions(ob, inherit=True):
                if subscription.notif_type != notif_type:
                    continue
                if not subscription.check_permission(ob):
                    continue
                email = subscription.get_email(ob)
                if email is None:
                    continue
                content_types = getattr(subscription, 'content_types', [])
                if content_types and ob.meta_type not in content_types:
                    continue
                notif_logger.info('.. .. sending newsletter to %r', email)
                objects_by_email.setdefault(email, []).append({
                    'ob': ob,
                    'type': log_type,
                })
                langs_by_email[email] = subscription.lang

                subscriptions_by_email[email] = subscription
                anonymous_users[email] = isinstance(subscription,
                                                    AnonymousSubscription)

        messages_by_email = {}
        for email in objects_by_email:
            messages_by_email[email] = {
                'objs': objects_by_email[email],
                '_lang': langs_by_email[email],
                'subscription': subscriptions_by_email[email],
                'here': self,
                'anonymous': anonymous_users[email]
            }

        template = self._get_template(notif_type)
        self._send_notifications(messages_by_email, template)

    def _cron_heartbeat(self, when):
        transaction.commit()  # commit earlier stuff; fresh transaction
        transaction.get().note('notifications cron at %s' % ofs_path(self))

        # Clean temporary subscriptions after a week:
        if self.config.get('enable_anonymous', False):
            a_week_ago = when - timedelta(weeks=1)
            for tmp_subscription in self.pending_anonymous_subscriptions[:]:
                if tmp_subscription.datetime <= a_week_ago:
                    self.pending_anonymous_subscriptions.remove(
                        tmp_subscription)

        #  daily newsletter ###
        if self.config['enable_daily']:
            # calculate the most recent daily newsletter time
            daily_time = time(hour=self.config['daily_hour'])
            latest_daily = datetime.combine(when.date(), daily_time)
            if latest_daily > when:
                latest_daily -= timedelta(days=1)

            # check if we should send a daily newsletter
            prev_daily = self.timestamps.get('daily', when - timedelta(days=1))
            if prev_daily < latest_daily < when:
                self._send_newsletter('daily', prev_daily, when)
                self.timestamps['daily'] = when

        #  weekly newsletter ###
        if self.config['enable_weekly']:
            # calculate the most recent weekly newsletter time
            weekly_time = time(hour=self.config['daily_hour'])
            t = datetime.combine(when.date(), weekly_time)
            days_delta = self.config['weekly_day'] - t.isoweekday()
            latest_weekly = t + timedelta(days=days_delta)
            if latest_weekly > when:
                latest_weekly -= timedelta(weeks=1)

            # check if we should send a weekly newsletter
            prev_weekly = self.timestamps.get('weekly',
                                              when - timedelta(weeks=1))
            if prev_weekly < latest_weekly < when:
                self._send_newsletter('weekly', prev_weekly, when)
                self.timestamps['weekly'] = when

        #  monthly newsletter ###
        if self.config['enable_monthly']:
            # calculate the most recent monthly newsletter time
            monthly_time = time(hour=self.config['monthly_hour'])
            the_day = utils.set_day_of_month(when.date(),
                                             self.config['monthly_day'])
            latest_monthly = datetime.combine(the_day, monthly_time)
            if latest_monthly > when:
                latest_monthly = utils.minus_one_month(latest_monthly)

            # check if we should send a monthly newsletter
            prev_monthly = self.timestamps.get('monthly',
                                               utils.minus_one_month(when))
            if prev_monthly < latest_monthly < when:
                self._send_newsletter('monthly', prev_monthly, when)
                self.timestamps['monthly'] = when

        transaction.commit()  # make sure our timestamp updates are saved

    def index_html(self, RESPONSE):
        """ redirect to admin page """
        RESPONSE.redirect(self.absolute_url() + '/my_subscriptions_html')

    security.declareProtected(view, 'my_subscriptions_html')
    my_subscriptions_html = NaayaPageTemplateFile(
        'zpt/index', globals(), 'naaya.core.notifications.my_subscriptions')

    security.declarePrivate('list_user_subscriptions')

    def user_subscriptions(self, user, cutoff_level=None):
        """
        Returns all user subscriptions in the portal.
        Use with caution as this iterates almost all the objects in site.
        You can use `cutoff_level` to limit the depth.

        """
        out = []
        user_id = user.getId()
        for obj, n, subscription in utils.walk_subscriptions(
                self.getSite(), cutoff_level):
            if not isinstance(subscription, AccountSubscription):
                continue
            if subscription.user_id != user_id:
                continue
            out.append({
                'object':
                obj,
                'notif_type':
                subscription.notif_type,
                'content_types':
                getattr(subscription, 'content_types', []),
                'lang':
                subscription.lang
            })

        return out

    security.declareProtected(view, 'user_not_found')

    def user_not_found(self, REQUEST):
        """
        Returns True if the user is not Anonymous, but is still not found by
        the AuthenticationTool (i.e. is maybe defined in the Zope root)

        """
        user = REQUEST.AUTHENTICATED_USER
        if not isinstance(user, basestring):
            # with LDAP authentication, user is LDAP user instance
            user = user.id
        acl_tool = self.getAuthenticationTool()
        if acl_tool.get_user_with_userid(user) is None:
            return True

    security.declareProtected(view, 'list_my_subscriptions')

    def list_my_subscriptions(self, REQUEST):
        """
        Returns a list of mappings (location, notif_type, lang)
        for all subscriptions of logged-in user

        """
        user = REQUEST.AUTHENTICATED_USER
        if user.getId() is None and not self.config.get(
                'enable_anonymous', False):
            raise Unauthorized  # to force login

        subscriptions = self.user_subscriptions(user)
        for subscription in subscriptions:
            subscription['location'] = path_in_site(subscription['object'])
            del subscription['object']

        return subscriptions

    security.declareProtected(view, 'my_first_subscription')

    def get_location_subscription(self, location, notif_type=None):
        """
        Returns the first of the authenticated user's subscriptions in location

        """
        for subscription in self.list_my_subscriptions(self.REQUEST):
            if subscription['location'] == location:
                if notif_type:
                    if subscription['notif_type'] == notif_type:
                        return subscription
                else:
                    return subscription

    security.declareProtected(view, 'subscribe_me')

    def subscribe_me(self,
                     REQUEST,
                     location,
                     notif_type,
                     lang=None,
                     content_types=[]):
        """ add subscription for currently-logged-in user """
        # Even if some content types were selected (by turning off javascript)
        # they should be ignored, no filtering in administrative notifications
        if notif_type == 'administrative':
            content_types = []
        if isinstance(content_types, basestring):
            content_types = [content_types]
        if lang is None:
            lang = self.gl_get_selected_language()
            REQUEST.form['lang'] = lang
        user_id = REQUEST.AUTHENTICATED_USER.getId()
        if location == '/':
            location = ''
        if user_id is None and not self.config.get('enable_anonymous', False):
            raise Unauthorized  # to force login
        try:
            if user_id:
                self.add_account_subscription(user_id, location, notif_type,
                                              lang, content_types)
                if content_types:
                    self.setSessionInfoTrans(
                        'You will receive ${notif_type} notifications'
                        ' for any changes in "${location}" for objects of '
                        'types ${content_types}.',
                        notif_type=notif_type,
                        location=location or self.getSite().title,
                        content_types=', '.join(content_types))
                else:
                    self.setSessionInfoTrans(
                        'You will receive ${notif_type} notifications'
                        ' for any changes in "${location}".',
                        notif_type=notif_type,
                        location=location)
            else:
                self.add_anonymous_subscription(**dict(REQUEST.form))
                self.setSessionInfoTrans(
                    'An activation e-mail has been sent to ${email}. '
                    'Follow the instructions to subscribe to ${notif_type} '
                    'notifications for any changes in "${location}".',
                    notif_type=notif_type,
                    location=location,
                    content_types=content_types,
                    email=REQUEST.form.get('email'))
        except ValueError, msg:
            self.setSessionErrors([unicode(msg)])
        return REQUEST.RESPONSE.redirect(self.absolute_url() +
                                         '/my_subscriptions_html')
Beispiel #8
0
_marker = {}


def manage_addAuthomaticPlugin(context, id, title='', RESPONSE=None, **kw):
    """Create an instance of a Authomatic Plugin.
    """
    plugin = AuthomaticPlugin(id, title, **kw)
    context._setObject(plugin.getId(), plugin)
    if RESPONSE is not None:
        RESPONSE.redirect('manage_workspace')


manage_addAuthomaticPluginForm = PageTemplateFile(
    os.path.join(tpl_dir, 'add_plugin.pt'),
    globals(),
    __name__='addAuthomaticPlugin',
)


@implementer(IAuthomaticPlugin, pas_interfaces.IAuthenticationPlugin,
             pas_interfaces.IPropertiesPlugin,
             pas_interfaces.IUserEnumerationPlugin,
             pas_interfaces.IRolesPlugin)
class AuthomaticPlugin(BasePlugin):
    """Authomatic PAS Plugin
    """

    security = ClassSecurityInfo()
    meta_type = 'Authomatic Plugin'
    BasePlugin.manage_options
            msg += "Previewable setting changed. "

        if not bool(usable) is self.is_usable():
            self.set_usable(bool(usable))
            msg += "Usability setting changed. "

        if layout_id and layout_id != self._layout_id:
            self._layout_id = layout_id
            msg += "Layout object id changed. "

        return self.editSQLSource(manage_tabs_message=msg)

InitializeClass(SQLSource)


manage_addSQLSourceForm = PageTemplateFile(
    "www/sqlSourceAdd", globals(), __name__='manage_addSQLSourceForm')

def manage_addSQLSource(context, id, title=None, REQUEST=None):
    """Add a SQLSource object
    """
    source = SQLSource(id)
    title = unicode(title, source.management_page_charset)
    source.title = title
    context._setObject(id, source)
    source = context._getOb(id)
    source._set_statement('SELECT <dtml-var columns> FROM <dtml-var table>')
    # parameters form
    reset_parameter_form(source)
    reset_table_layout(source)
    add_and_edit(context, id, REQUEST, screen='editSQLSource')
    return ''
Beispiel #10
0
class SetupTool(Folder):

    """ Profile-based site configuration manager.
    """

    implements(ISetupTool)

    meta_type = 'Generic Setup Tool'

    _import_context_id = ''

    security = ClassSecurityInfo()

    def __init__(self, id):
        self.id = str(id)
        self._import_registry = ImportStepRegistry()
        self._export_registry = ExportStepRegistry()
        self._export_registry.registerStep('step_registries',
                                           exportStepRegistries,
                                           'Export import / export steps.',
                                          )
        self._toolset_registry = ToolsetRegistry()

    #
    #   ISetupTool API
    #
    security.declareProtected(ManagePortal, 'getEncoding')
    def getEncoding(self):

        """ See ISetupTool.
        """
        return 'ascii'

    security.declareProtected(ManagePortal, 'getImportContextID')
    def getImportContextID(self):

        """ See ISetupTool.
        """
        return self._import_context_id

    security.declareProtected(ManagePortal, 'setImportContext')
    def setImportContext(self, context_id, encoding=None):

        """ See ISetupTool.
        """
        self._import_context_id = context_id
        context = self._getImportContext(context_id)

        self.applyContext(context, encoding)

    security.declareProtected(ManagePortal, 'applyContext')
    def applyContext(self, context, encoding=None):
        self._updateImportStepsRegistry(context, encoding)
        self._updateExportStepsRegistry(context, encoding)

    security.declareProtected(ManagePortal, 'getImportStepRegistry')
    def getImportStepRegistry(self):

        """ See ISetupTool.
        """
        return self._import_registry

    security.declareProtected(ManagePortal, 'getExportStepRegistry')
    def getExportStepRegistry(self):

        """ See ISetupTool.
        """
        return self._export_registry

    security.declareProtected(ManagePortal, 'getToolsetRegistry')
    def getToolsetRegistry(self):

        """ See ISetupTool.
        """
        return self._toolset_registry

    security.declareProtected(ManagePortal, 'runImportStep')
    def runImportStep(self, step_id, run_dependencies=True, purge_old=None):

        """ See ISetupTool.
        """
        context = self._getImportContext(self._import_context_id, purge_old)

        info = self._import_registry.getStepMetadata(step_id)

        if info is None:
            raise ValueError, 'No such import step: %s' % step_id

        dependencies = info.get('dependencies', ())

        messages = {}
        steps = []
        if run_dependencies:
            for dependency in dependencies:

                if dependency not in steps:
                    message = self._doRunImportStep(dependency, context)
                    messages[dependency] = message or ''
                    steps.append(dependency)

        message = self._doRunImportStep(step_id, context)
        message_list = filter(None, [message])
        message_list.extend( ['%s: %s' % x[1:] for x in context.listNotes()] )
        messages[step_id] = '\n'.join(message_list)
        steps.append(step_id)

        return { 'steps' : steps, 'messages' : messages }

    security.declareProtected(ManagePortal, 'runAllImportSteps')
    def runAllImportSteps(self, purge_old=None):

        """ See ISetupTool.
        """
        __traceback_info__ = self._import_context_id

        context = self._getImportContext(self._import_context_id, purge_old)

        return self._runImportStepsFromContext(context, purge_old=purge_old)

    security.declareProtected(ManagePortal, 'runExportStep')
    def runExportStep(self, step_id):

        """ See ISetupTool.
        """
        return self._doRunExportSteps([step_id])

    security.declareProtected(ManagePortal, 'runAllExportSteps')
    def runAllExportSteps(self):

        """ See ISetupTool.
        """
        return self._doRunExportSteps(self._export_registry.listSteps())

    security.declareProtected(ManagePortal, 'createSnapshot')
    def createSnapshot(self, snapshot_id):

        """ See ISetupTool.
        """
        context = SnapshotExportContext(self, snapshot_id)
        messages = {}
        steps = self._export_registry.listSteps()

        for step_id in steps:

            handler = self._export_registry.getStep(step_id)

            if handler is None:
                raise ValueError('Invalid export step: %s' % step_id)

            messages[step_id] = handler(context)


        return { 'steps' : steps
               , 'messages' : messages
               , 'url' : context.getSnapshotURL()
               , 'snapshot' : context.getSnapshotFolder()
               }

    security.declareProtected(ManagePortal, 'compareConfigurations')
    def compareConfigurations(self,
                              lhs_context,
                              rhs_context,
                              missing_as_empty=False,
                              ignore_blanks=False,
                              skip=SKIPPED_FILES,
                             ):
        """ See ISetupTool.
        """
        differ = ConfigDiff(lhs_context,
                            rhs_context,
                            missing_as_empty,
                            ignore_blanks,
                            skip,
                           )

        return differ.compare()

    security.declareProtected(ManagePortal, 'markupComparison')
    def markupComparison(self, lines):

        """ See ISetupTool.
        """
        result = []

        for line in lines.splitlines():

            if line.startswith('** '):

                if line.find('File') > -1:
                    if line.find('replaced') > -1:
                        result.append(('file-to-dir', line))
                    elif line.find('added') > -1:
                        result.append(('file-added', line))
                    else:
                        result.append(('file-removed', line))
                else:
                    if line.find('replaced') > -1:
                        result.append(('dir-to-file', line))
                    elif line.find('added') > -1:
                        result.append(('dir-added', line))
                    else:
                        result.append(('dir-removed', line))

            elif line.startswith('@@'):
                result.append(('diff-range', line))

            elif line.startswith(' '):
                result.append(('diff-context', line))

            elif line.startswith('+'):
                result.append(('diff-added', line))

            elif line.startswith('-'):
                result.append(('diff-removed', line))

            elif line == '\ No newline at end of file':
                result.append(('diff-context', line))

            else:
                result.append(('diff-header', line))

        return '<pre>\n%s\n</pre>' % (
            '\n'.join([('<span class="%s">%s</span>' % (cl, escape(l)))
                                  for cl, l in result]))

    #
    #   ZMI
    #
    manage_options = (Folder.manage_options[:1]
                    + ({'label' : 'Properties',
                        'action' : 'manage_tool'
                       },
                       {'label' : 'Import',
                        'action' : 'manage_importSteps'
                       },
                       {'label' : 'Export',
                        'action' : 'manage_exportSteps'
                       },
                       {'label' : 'Snapshots',
                        'action' : 'manage_snapshots'
                       },
                       {'label' : 'Comparison',
                        'action' : 'manage_showDiff'
                       },
                      )
                    + Folder.manage_options[3:] # skip "View", "Properties"
                     )

    security.declareProtected(ManagePortal, 'manage_tool')
    manage_tool = PageTemplateFile('sutProperties', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_updateToolProperties')
    def manage_updateToolProperties(self, context_id, RESPONSE):
        """ Update the tool's settings.
        """
        self.setImportContext(context_id)

        RESPONSE.redirect('%s/manage_tool?manage_tabs_message=%s'
                         % (self.absolute_url(), 'Properties+updated.'))

    security.declareProtected(ManagePortal, 'manage_importSteps')
    manage_importSteps = PageTemplateFile('sutImportSteps', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_importSelectedSteps')
    def manage_importSelectedSteps(self,
                                   ids,
                                   run_dependencies,
                                   RESPONSE,
                                   create_report=True,
                                  ):
        """ Import the steps selected by the user.
        """
        messages = {}
        if not ids:
            summary = 'No steps selected.'

        else:
            steps_run = []
            for step_id in ids:
                result = self.runImportStep(step_id, run_dependencies)
                steps_run.extend(result['steps'])
                messages.update(result['messages'])

            summary = 'Steps run: %s' % ', '.join(steps_run)

            if create_report:
                name = self._mangleTimestampName('import-selected', 'log')
                self._createReport(name, result['steps'], result['messages'])

        return self.manage_importSteps(manage_tabs_message=summary,
                                       messages=messages)

    security.declareProtected(ManagePortal, 'manage_importSelectedSteps')
    def manage_importAllSteps(self, RESPONSE, create_report=True):

        """ Import all steps.
        """
        result = self.runAllImportSteps()
        steps_run = 'Steps run: %s' % ', '.join(result['steps'])

        if create_report:
            name = self._mangleTimestampName('import-all', 'log')
            self._createReport(name, result['steps'], result['messages'])

        return self.manage_importSteps(manage_tabs_message=steps_run,
                                       messages=result['messages'])

    security.declareProtected(ManagePortal, 'manage_importTarball')
    def manage_importTarball(self, tarball, RESPONSE, create_report=True):
        """ Import steps from the uploaded tarball.
        """
        if getattr(tarball, 'read', None) is not None:
            tarball = tarball.read()

        context = TarballImportContext(tool=self,
                                       archive_bits=tarball,
                                       encoding='UTF8',
                                       should_purge=True,
                                      )
        result = self._runImportStepsFromContext(context,
                                                 purge_old=True)
        steps_run = 'Steps run: %s' % ', '.join(result['steps'])

        if create_report:
            name = self._mangleTimestampName('import-all', 'log')
            self._createReport(name, result['steps'], result['messages'])

        return self.manage_importSteps(manage_tabs_message=steps_run,
                                       messages=result['messages'])

    security.declareProtected(ManagePortal, 'manage_exportSteps')
    manage_exportSteps = PageTemplateFile('sutExportSteps', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_exportSelectedSteps')
    def manage_exportSelectedSteps(self, ids, RESPONSE):

        """ Export the steps selected by the user.
        """
        if not ids:
            RESPONSE.redirect('%s/manage_exportSteps?manage_tabs_message=%s'
                             % (self.absolute_url(), 'No+steps+selected.'))

        result = self._doRunExportSteps(ids)
        RESPONSE.setHeader('Content-type', 'application/x-gzip')
        RESPONSE.setHeader('Content-disposition',
                           'attachment; filename=%s' % result['filename'])
        return result['tarball']

    security.declareProtected(ManagePortal, 'manage_exportAllSteps')
    def manage_exportAllSteps(self, RESPONSE):

        """ Export all steps.
        """
        result = self.runAllExportSteps()
        RESPONSE.setHeader('Content-type', 'application/x-gzip')
        RESPONSE.setHeader('Content-disposition',
                           'attachment; filename=%s' % result['filename'])
        return result['tarball']

    security.declareProtected(ManagePortal, 'manage_snapshots')
    manage_snapshots = PageTemplateFile('sutSnapshots', _wwwdir)

    security.declareProtected(ManagePortal, 'listSnapshotInfo')
    def listSnapshotInfo(self):

        """ Return a list of mappings describing available snapshots.

        o Keys include:

          'id' -- snapshot ID

          'title' -- snapshot title or ID

          'url' -- URL of the snapshot folder
        """
        result = []
        snapshots = self._getOb('snapshots', None)

        if snapshots:

            for id, folder in snapshots.objectItems('Folder'):

                result.append({ 'id' : id
                               , 'title' : folder.title_or_id()
                               , 'url' : folder.absolute_url()
                               })
        return result

    security.declareProtected(ManagePortal, 'listProfileInfo')
    def listProfileInfo(self):

        """ Return a list of mappings describing registered profiles.

        o Keys include:

          'id' -- profile ID

          'title' -- profile title or ID

          'description' -- description of the profile

          'path' -- path to the profile within its product

          'product' -- name of the registering product
        """
        return _profile_registry.listProfileInfo()

    security.declareProtected(ManagePortal, 'listContextInfos')
    def listContextInfos(self):

        """ List registered profiles and snapshots.
        """

        s_infos = [{ 'id': 'snapshot-%s' % info['id'],
                      'title': info['title'] }
                    for info in self.listSnapshotInfo()]
        p_infos = [{ 'id': 'profile-%s' % info['id'],
                      'title': info['title'] }
                    for info in self.listProfileInfo()]

        return tuple(s_infos + p_infos)

    security.declareProtected(ManagePortal, 'manage_createSnapshot')
    def manage_createSnapshot(self, RESPONSE, snapshot_id=None):

        """ Create a snapshot with the given ID.

        o If no ID is passed, generate one.
        """
        if snapshot_id is None:
            snapshot_id = self._mangleTimestampName('snapshot')

        self.createSnapshot(snapshot_id)

        RESPONSE.redirect('%s/manage_snapshots?manage_tabs_message=%s'
                         % (self.absolute_url(), 'Snapshot+created.'))

    security.declareProtected(ManagePortal, 'manage_showDiff')
    manage_showDiff = PageTemplateFile('sutCompare', _wwwdir)

    def manage_downloadDiff(self,
                            lhs,
                            rhs,
                            missing_as_empty,
                            ignore_blanks,
                            RESPONSE,
                           ):
        """ Crack request vars and call compareConfigurations.

        o Return the result as a 'text/plain' stream, suitable for framing.
        """
        comparison = self.manage_compareConfigurations(lhs,
                                                       rhs,
                                                       missing_as_empty,
                                                       ignore_blanks,
                                                      )
        RESPONSE.setHeader('Content-Type', 'text/plain')
        return _PLAINTEXT_DIFF_HEADER % (lhs, rhs, comparison)

    security.declareProtected(ManagePortal, 'manage_compareConfigurations')
    def manage_compareConfigurations(self,
                                     lhs,
                                     rhs,
                                     missing_as_empty,
                                     ignore_blanks,
                                    ):
        """ Crack request vars and call compareConfigurations.
        """
        lhs_context = self._getImportContext(lhs)
        rhs_context = self._getImportContext(rhs)

        return self.compareConfigurations(lhs_context,
                                          rhs_context,
                                          missing_as_empty,
                                          ignore_blanks,
                                         )


    #
    #   Helper methods
    #
    security.declarePrivate('_getProductPath')
    def _getProductPath(self, product_name):

        """ Return the absolute path of the product's directory.
        """
        try:
            # BBB: for GenericSetup 1.1 style product names
            product = __import__('Products.%s' % product_name
                                , globals(), {}, ['initialize'])
        except ImportError:
            try:
                product = __import__(product_name
                                    , globals(), {}, ['initialize'])
            except ImportError:
                raise ValueError('Not a valid product name: %s'
                                 % product_name)

        return product.__path__[0]

    security.declarePrivate('_getImportContext')
    def _getImportContext(self, context_id, should_purge=None):

        """ Crack ID and generate appropriate import context.
        """
        encoding = self.getEncoding()

        if context_id.startswith('profile-'):

            context_id = context_id[len('profile-'):]
            info = _profile_registry.getProfileInfo(context_id)

            if info.get('product'):
                path = os.path.join(self._getProductPath(info['product'])
                                   , info['path'])
            else:
                path = info['path']
            if should_purge is None:
                should_purge = (info.get('type') != EXTENSION)
            return DirectoryImportContext(self, path, should_purge, encoding)

        # else snapshot
        context_id = context_id[len('snapshot-'):]
        if should_purge is None:
            should_purge = True
        return SnapshotImportContext(self, context_id, should_purge, encoding)

    security.declarePrivate('_updateImportStepsRegistry')
    def _updateImportStepsRegistry(self, context, encoding):

        """ Update our import steps registry from our profile.
        """
        if context is None:
            context = self._getImportContext(self._import_context_id)
        xml = context.readDataFile(IMPORT_STEPS_XML)
        if xml is None:
            return

        info_list = self._import_registry.parseXML(xml, encoding)

        for step_info in info_list:

            id = step_info['id']
            version = step_info['version']
            handler = _resolveDottedName(step_info['handler'])

            dependencies = tuple(step_info.get('dependencies', ()))
            title = step_info.get('title', id)
            description = ''.join(step_info.get('description', []))

            self._import_registry.registerStep(id=id,
                                               version=version,
                                               handler=handler,
                                               dependencies=dependencies,
                                               title=title,
                                               description=description,
                                              )

    security.declarePrivate('_updateExportStepsRegistry')
    def _updateExportStepsRegistry(self, context, encoding):

        """ Update our export steps registry from our profile.
        """
        if context is None:
            context = self._getImportContext(self._import_context_id)
        xml = context.readDataFile(EXPORT_STEPS_XML)
        if xml is None:
            return

        info_list = self._export_registry.parseXML(xml, encoding)

        for step_info in info_list:

            id = step_info['id']
            handler = _resolveDottedName(step_info['handler'])

            title = step_info.get('title', id)
            description = ''.join(step_info.get('description', []))

            self._export_registry.registerStep(id=id,
                                               handler=handler,
                                               title=title,
                                               description=description,
                                              )

    security.declarePrivate('_doRunImportStep')
    def _doRunImportStep(self, step_id, context):

        """ Run a single import step, using a pre-built context.
        """
        __traceback_info__ = step_id

        handler = self._import_registry.getStep(step_id)

        if handler is None:
            raise ValueError('Invalid import step: %s' % step_id)

        return handler(context)

    security.declarePrivate('_doRunExportSteps')
    def _doRunExportSteps(self, steps):

        """ See ISetupTool.
        """
        context = TarballExportContext(self)
        messages = {}

        for step_id in steps:

            handler = self._export_registry.getStep(step_id)

            if handler is None:
                raise ValueError('Invalid export step: %s' % step_id)

            messages[step_id] = handler(context)

        return { 'steps' : steps
               , 'messages' : messages
               , 'tarball' : context.getArchive()
               , 'filename' : context.getArchiveFilename()
               }

    security.declarePrivate('_runImportStepsFromContext')
    def _runImportStepsFromContext(self, context, steps=None, purge_old=None):
        self.applyContext(context)

        if steps is None:
            steps = self._import_registry.sortSteps()
        messages = {}

        for step in steps:
            message = self._doRunImportStep(step, context)
            message_list = filter(None, [message])
            message_list.extend( ['%s: %s' % x[1:]
                                  for x in context.listNotes()] )
            messages[step] = '\n'.join(message_list)
            context.clearNotes()

        return { 'steps' : steps, 'messages' : messages }

    security.declarePrivate('_mangleTimestampName')
    def _mangleTimestampName(self, prefix, ext=None):

        """ Create a mangled ID using a timestamp.
        """
        timestamp = time.gmtime()
        items = (prefix,) + timestamp[:6]

        if ext is None:
            fmt = '%s-%4d%02d%02d%02d%02d%02d'
        else:
            fmt = '%s-%4d%02d%02d%02d%02d%02d.%s'
            items += (ext,)

        return fmt % items

    security.declarePrivate('_createReport')
    def _createReport(self, name, steps, messages):

        """ Record the results of a run.
        """
        lines = []
        # Create report
        for step in steps:
            lines.append('=' * 65)
            lines.append('Step: %s' % step)
            lines.append('=' * 65)
            msg = messages[step]
            lines.extend(msg.split('\n'))
            lines.append('')

        report = '\n'.join(lines)
        if isinstance(report, unicode):
            report = report.encode('latin-1')

        file = File(id=name,
                    title='',
                    file=report,
                    content_type='text/plain'
                   )
        self._setObject(name, file)
Beispiel #11
0
    def _getExportTemplate(self):

        return PageTemplateFile('aitExport.xml', _xmldir)
Beispiel #12
0
class LocalChannel(SimpleItem, utils):
    """ """

    implements(ILocalChannel)

    meta_type = METATYPE_LOCALCHANNEL
    icon = 'misc_/NaayaCore/LocalChannel.gif'

    manage_options = ((
        {
            'label': 'Properties',
            'action': 'manage_properties_html'
        },
        {
            'label': 'View',
            'action': 'index_html'
        },
    ) + SimpleItem.manage_options)

    security = ClassSecurityInfo()

    def __init__(self, id, title, description, language, type, objmetatype,
                 numberofitems):
        """ """
        self.id = id
        self.title = title
        self.description = description
        self.language = language
        self.type = type
        self.objmetatype = objmetatype
        self.numberofitems = numberofitems

    security.declarePrivate('syndicateThis')

    def syndicateThis(self):
        xml = rss_item_for_channel(self)
        return etree.tostring(xml, xml_declaration=False, encoding="utf-8")

    security.declareProtected(view_management_screens, 'manageProperties')

    def manageProperties(self,
                         title='',
                         description='',
                         language=None,
                         type='',
                         objmetatype=[],
                         numberofitems='',
                         REQUEST=None):
        """ """
        if language is None: language = self.gl_get_selected_language()
        objmetatype = self.utConvertToList(objmetatype)
        try:
            numberofitems = abs(int(numberofitems))
        except:
            numberofitems = 0
        self.title = title
        self.description = description
        self.language = language
        self.type = type
        self.objmetatype = objmetatype
        self.numberofitems = numberofitems
        self._p_changed = 1
        if REQUEST: REQUEST.RESPONSE.redirect('manage_properties_html')

    def get_objects_for_rdf(self):
        #return the objects to be syndicated
        l_items = []
        if len(self.objmetatype) > 0:
            l_howmany = -1
            if self.numberofitems != 0:
                l_howmany = self.numberofitems
            l_items = self.query_translated_objects(meta_type=self.objmetatype,
                                                    lang=self.language,
                                                    approved=1,
                                                    howmany=l_howmany)
        return l_items

    security.declareProtected(view, 'index_html')

    def index_html(self, feed='', REQUEST=None, RESPONSE=None):
        """ """
        if feed == 'atom':
            return self.syndicateAtom(self, self.get_objects_for_rdf(),
                                      self.language)

        s = self.getSite()
        lang = self.language
        if lang == 'auto':
            lang = self.gl_get_selected_language()
        l_items = self.get_objects_for_rdf()
        namespaces = self.getNamespaceItemsList()
        nsmap = nsmap = get_nsmap(namespaces)
        header = []
        for n in namespaces:
            header.append(str(n))
        rdf_namespace = nsmap['rdf']
        Rdf = ElementMaker(namespace=rdf_namespace, nsmap=nsmap)
        E = ElementMaker(None, nsmap=nsmap)

        xml = Rdf.RDF(rss_channel_for_channel(self, lang))

        channel = xml[0]
        items = channel[-1]
        seq = etree.SubElement(items, '{%s}Seq' % rdf_namespace)
        for i in l_items:
            x = etree.SubElement(seq,
                                 '{%s}li' % rdf_namespace,
                                 resource=i.absolute_url())
        if self.hasImage():
            image = E.image(E.title(self.title), E.url(self.getImagePath()),
                            E.link(s.absolute_url()),
                            E.description(self.utToUtf8(self.description)))
            xml.append(image)
        received_items = ''.join([i.syndicateThis() for i in l_items])
        received = '<rdf:RDF %s>%s</rdf:RDF>' % (''.join(header),
                                                 received_items)
        xml_received = etree.XML(received, etree.XMLParser(strip_cdata=False))
        xml.extend(xml_received)
        self.REQUEST.RESPONSE.setHeader('content-type', 'text/xml')
        return etree.tostring(xml, xml_declaration=True, encoding="utf-8")

    #zmi pages
    security.declareProtected(view_management_screens,
                              'manage_properties_html')
    manage_properties_html = PageTemplateFile('zpt/localchannel_properties',
                                              globals())
Beispiel #13
0
from zope.interface import implements
from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from AccessControl.Permissions import view_management_screens, view
from OFS.SimpleItem import SimpleItem
from Products.PageTemplates.PageTemplateFile import PageTemplateFile

from Products.NaayaCore.interfaces import ILocalChannel
from Products.NaayaCore.constants import *
from Products.NaayaCore.managers.utils import utils, get_nsmap, rss_channel_for_channel, rss_item_for_channel

from lxml import etree
from lxml.builder import ElementMaker

manage_addLocalChannelForm = PageTemplateFile('zpt/localchannel_manage_add',
                                              globals())


def manage_addLocalChannel(self,
                           id='',
                           title='',
                           description='',
                           language=None,
                           type='',
                           objmetatype=[],
                           numberofitems='',
                           portlet='',
                           REQUEST=None):
    """ """
    id = self.utSlugify(id)
    if language is None: language = self.gl_get_selected_language()
Beispiel #14
0
class ZMSFormatProvider(ZMSItem.ZMSItem,
                        ZMSTextformatManager.ZMSTextformatManager,
                        ZMSCharformatManager.ZMSCharformatManager):

    # Properties.
    # -----------
    meta_type = 'ZMSFormatProvider'
    zmi_icon = "fas fa-font"
    icon_clazz = zmi_icon

    # Management Options.
    # -------------------
    manage_options_default_action = '../manage_customize'

    def manage_options(self):
        return [
            self.operator_setitem(x, 'action', '../' + x['action'])
            for x in copy.deepcopy(self.aq_parent.manage_options())
        ]

    manage_sub_options__roles__ = None

    def manage_sub_options(self):
        return (
            {
                'label': 'TAB_TEXTFORMATS',
                'action': 'manage_textformats'
            },
            {
                'label': 'TAB_CHARFORMATS',
                'action': 'manage_charformats'
            },
        )

    # Management Interface.
    # ---------------------
    manage = PageTemplateFile('zpt/ZMSFormatProvider/manage_textformats',
                              globals())
    manage_main = PageTemplateFile('zpt/ZMSFormatProvider/manage_textformats',
                                   globals())
    manage_textformats = PageTemplateFile(
        'zpt/ZMSFormatProvider/manage_textformats', globals())
    manage_charformats = PageTemplateFile(
        'zpt/ZMSFormatProvider/manage_charformats', globals())

    # Management Permissions.
    # -----------------------
    __administratorPermissions__ = (
        'manage_changeTextformat',
        'manage_textformats',
        'manage_changeCharformat',
        'manage_charformats',
    )
    __ac_permissions__ = (('ZMS Administrator',
                           __administratorPermissions__), )
    """
    ############################################################################
    #
    #   Constructor
    #
    ############################################################################
    """

    ############################################################################
    #  ZMSFormatProvider.__init__:
    #
    #  Initialise a new instance.
    ############################################################################
    def __init__(self, textformats=[], charformats=[]):
        self.id = 'format_manager'
        self.textformats = copy.deepcopy(textformats)
        self.charformats = copy.deepcopy(charformats)
Beispiel #15
0
class UniqueIdHandlerTool(UniqueObject, SimpleItem, ActionProviderBase):

    __doc__ = __doc__ # copy from module

    implements(IUniqueIdHandler, IUniqueIdBrainQuery,
               IUniqueIdUnrestrictedQuery)
    __implements__ = (
        ActionProviderBase.__implements__,
        SimpleItem.__implements__,
    )

    id = 'portal_uidhandler'

    manage_options = ( ActionProviderBase.manage_options
                     + ( {'label':'Query',
                          'action':'manage_queryObject'}
                       ,
                       )
                     + SimpleItem.manage_options
                     )

    alternative_id = "portal_standard_uidhandler"
    meta_type = 'Unique Id Handler Tool'

    # make the uid attribute name available for the unit tests
    # not meant to be altered as long you don't know what you do!!!
    UID_ATTRIBUTE_NAME = UID_ATTRIBUTE_NAME

    # make the exception class available through the tool
    UniqueIdError = UniqueIdError

    security = ClassSecurityInfo()

    def _reindexObject(self, obj):
        # add uid index and colums to catalog if not yet done
        UID_ATTRIBUTE_NAME = self.UID_ATTRIBUTE_NAME
        catalog = getToolByName(self, 'portal_catalog')
        if UID_ATTRIBUTE_NAME not in catalog.indexes():
            catalog.addIndex(UID_ATTRIBUTE_NAME, 'FieldIndex')
            catalog.addColumn(UID_ATTRIBUTE_NAME)

        # reindex
        catalog.reindexObject(obj)

    def _setUid(self, obj, uid):
        """Attaches a unique id to the object and does reindexing.
        """
        # attach a unique id annotation to the object
        anno_tool = getToolByName(self, 'portal_uidannotation')
        annotation = anno_tool(obj, self.UID_ATTRIBUTE_NAME)
        annotation.setUid(uid)

        # reindex the object
        self._reindexObject(obj)

    security.declarePublic('register')
    def register(self, obj):
        """See IUniqueIdSet.
        """
        uid = self.queryUid(obj, default=None)
        if uid is None:
            # generate a new unique id and set it
            generator = getToolByName(self, 'portal_uidgenerator')
            uid = generator()
            self._setUid(obj, uid)

        return uid

    security.declareProtected(ManagePortal, 'unregister')
    def unregister(self, obj):
        """See IUniqueIdSet.
        """
        UID_ATTRIBUTE_NAME = self.UID_ATTRIBUTE_NAME
        if getattr(aq_base(obj), UID_ATTRIBUTE_NAME, None) is None:
            raise UniqueIdError, \
                  "No unique id available to be unregistered on '%s'" % obj

        # delete the uid and reindex
        delattr(obj, UID_ATTRIBUTE_NAME)
        self._reindexObject(obj)

    security.declarePublic('queryUid')
    def queryUid(self, obj, default=None):
        """See IUniqueIdQuery.
        """
        uid = getattr(aq_base(obj), self.UID_ATTRIBUTE_NAME, None)
        # If 'obj' is a content object the 'uid' attribute is usually a
        # callable object. If 'obj' is a catalog brain the uid attribute
        # is non callable and possibly equals the 'Missing.MV' value.
        if uid is Missing.MV or uid is None:
            return default
        if callable(uid):
            return uid()
        return uid

    security.declarePublic('getUid')
    def getUid(self, obj):
        """See IUniqueIdQuery.
        """
        uid = self.queryUid(obj, None)
        if uid is None:
            raise UniqueIdError, "No unique id available on '%s'" % obj
        return uid

    security.declarePrivate('setUid')
    def setUid(self, obj, uid, check_uniqueness=True):
        """See IUniqueIdSet.
        """
        # None is the only value a unique id shall never have!
        if uid is None:
            raise UniqueIdError, "It's forbidden to set a unique id to 'None'."

        # check for uniqueness if enabled
        if check_uniqueness:
            result = self.queryObject(uid)
            if result is not None and result != obj:
                if callable(uid):
                    uid = uid()
                raise UniqueIdError, \
                      "The unique id '%s' is already in use" % uid

        # everything is ok: set it!
        self._setUid(obj, uid)

    def _queryBrain(self, uid, searchMethodName, default=None):
        """This helper method does the "hard work" of querying the catalog
           and interpreting the results.
        """
        if uid is None:
            return default

        # convert the uid to the right format
        generator = getToolByName(self, 'portal_uidgenerator')
        uid = generator.convert(uid)

        catalog = getToolByName(self, 'portal_catalog')
        searchMethod = getattr(catalog, searchMethodName)
        result = searchMethod({self.UID_ATTRIBUTE_NAME: uid})
        len_result = len(result)

        # return None if no object found with this uid
        if len_result == 0:
            return default

        # print a message to the log  if more than one object has
        # the same uid (uups!)
        if len_result > 1:
            logging.info("CMUid ASSERT:",
                     "Uups, %s objects have '%s' as uid!!!" % \
                     (len_result, uid))

        return result[0]

    security.declarePublic('queryBrain')
    def queryBrain(self, uid, default=None):
        """See IUniqueIdBrainQuery.
        """
        return self._queryBrain(uid, 'searchResults', default)

    def _getBrain(self, uid, queryBrainMethod):
        brain = queryBrainMethod(uid, default=None)
        if brain is None:
            raise UniqueIdError, "No object found with '%s' as uid." % uid
        return brain

    security.declarePublic('getBrain')
    def getBrain(self, uid):
        """See IUniqueIdBrainQuery.
        """
        return self._getBrain(uid, self.queryBrain)

    security.declarePublic('getObject')
    def getObject(self, uid):
        """See IUniqueIdQuery.
        """
        return self.getBrain(uid).getObject()

    security.declarePublic('queryObject')
    def queryObject(self, uid, default=None):
        """See IUniqueIdQuery.
        """
        try:
            return self.getObject(uid)
        except UniqueIdError:
            return default

    security.declarePrivate('unrestrictedQueryBrain')
    def unrestrictedQueryBrain(self, uid, default=None):
        """See IUniqueIdUnrestrictedQuery.
        """
        return self._queryBrain(uid, 'unrestrictedSearchResults', default)

    security.declarePrivate('unrestrictedGetBrain')
    def unrestrictedGetBrain(self, uid):
        """See IUniqueIdUnrestrictedQuery.
        """
        return self._getBrain(uid, self.unrestrictedQueryBrain)

    security.declarePrivate('unrestrictedGetObject')
    def unrestrictedGetObject(self, uid):
        """See IUniqueIdUnrestrictedQuery.
        """
        return self.unrestrictedGetBrain(uid).getObject()

    security.declarePrivate('unrestrictedQueryObject')
    def unrestrictedQueryObject(self, uid, default=None):
        """See IUniqueIdUnrestrictedQuery.
        """
        try:
            return self.unrestrictedGetObject(uid)
        except UniqueIdError:
            return default

    security.declareProtected(ManagePortal, 'manage_queryObject')
    manage_queryObject = PageTemplateFile('queryUID.pt', _wwwdir)
class SQLSource(EditableExternalSource, Folder, ZMIObject):
    grok.implements(IExternalSource)
    # register icon and factories
    silvaconf.icon('www/sqlsource.png')
    silvaconf.factory('manage_addSQLSourceForm')
    silvaconf.factory('manage_addSQLSource')
    silvaconf.zmi_addable(True)

    meta_type = "Silva SQL Source"
    security = ClassSecurityInfo()

    _sql_method_id = 'sql_method'
    _layout_id = 'layout'
    _default_batch_size = 10
    _v_cached_parameters = None

    # ZMI Tabs
    manage_options = (
        {'label':'Edit', 'action':'editSQLSource'},
        {'label':'Parameters', 'action':'parameters/manage_main'},
        ) + Folder.manage_options
    management_page_charset = 'utf-8'

    security.declareProtected(ViewManagementScreens, 'editSQLSource')
    editSQLSource = PageTemplateFile(
        'www/sqlSourceEdit', globals(),  __name__='sqlCodeSource')

    def __init__(self, id):
        self.id = id
        self._sql_method = None
        self._statement = None
        self._connection_id = None

    # ACCESSORS

    def layout_id(self):
        return self._layout_id

    def connection_id(self):
        return self._connection_id

    def statement(self):
        return self._statement

    def available_connection_ids(self):
        return SQLConnectionIDs(self)

    security.declareProtected(AccessContentsInformation, 'to_html')
    def to_html(self, content, request, **parameters):
        """ render HTML for SQL source
        """
        values = self._get_data(parameters)
        names = values.names()
        batch_size = self._default_batch_size
        if parameters.get('sqlbatchsize'):
            batch_size = int(parameters.get('sqlbatchsize'))
        data = Batch(
            values.dictionaries(),
            factory=self._decode_dict_helper,
            count=batch_size,
            name=self.getId(),
            request=request)
        model = content
        if IVersion.providedBy(content):
            model = content.get_content()
        layout = self._getOb(self._layout_id)
        batch = getMultiAdapter((model, data, request), IBatching)()
        return layout(
            table=data, batch=batch, names=names, parameters=parameters)

    def _get_data(self, args):
        if not self._sql_method:
            self._set_sql_method()
        elif self._v_cached_parameters != self.get_parameters_form().get_field_ids():
            self._set_sql_method()
        args = self._encode_dict_helper(args)
        return self._sql_method(REQUEST=args)

    def _decode_dict_helper(self, dictionary):
        for key, value in dictionary.items():
            if type(value) is type(''):
                dictionary[key] = unicode(
                    value, self._data_encoding, 'replace')
        return dictionary

    def _encode_dict_helper(self, dictionary):
        for key, value in dictionary.items():
            if type(value) is type(u''):
                dictionary[key] =  value.encode(
                    self._data_encoding, 'replace')
        return dictionary

    # MODIFIERS

    def _set_statement(self, statement):
        self._statement = statement
        #invalidate sql method
        self._sql_method = None
        self._p_changed = 1

    def _set_connection_id(self, id):
        self._connection_id = id
        #invalidate sql method
        self._sql_method = None
        self._p_changed = 1

    def _set_sql_method(self):
        self._v_cached_parameters = parameters = self.get_parameters_form().get_field_ids()
        arguments = '\n'.join(parameters)
        self._sql_method = SQL(
            self._sql_method_id, '', self._connection_id,
            arguments.encode('ascii'), self._statement.encode('UTF-8'))
        self._p_changed = 1

    # MANAGERS

    security.declareProtected(ViewManagementScreens, 'manage_editSQLSource')
    def manage_editSQLSource(
        self, title, data_encoding, statement, connection_id=None,
        description=None, cacheable=None, layout_id=None, reset_layout=None,
        reset_params=None, previewable=None, usable=None,
        ):
        """ Edit SQLSource object
        """
        msg = u''

        if reset_layout:
            reset_table_layout(self)
            return self.editSQLSource(
                manage_tabs_message="Table rendering pagetemplate reset " \
                    "to default layout.")

        if reset_params:
            reset_parameter_form(self)
            return self.editSQLSource(
                manage_tabs_message="Parameters form reset to default.")

        if data_encoding and data_encoding != self._data_encoding:
            try:
                unicode('abcd', data_encoding, 'replace')
            except LookupError:
                # unknown encoding, return error message
                msg  += "Unknown encoding %s, not changed!" % data_encoding
                return self.editSQLSource(manage_tabs_message=msg)
            self.set_data_encoding(data_encoding)
            msg += "Data encoding changed. "

        if connection_id and connection_id != self._connection_id:
            self._set_connection_id(connection_id)
            msg += "Connection id changed. "

        if statement:
            statement = unicode(statement, 'UTF-8')
            self._set_statement(statement)
            msg += "SQL statement changed. "

        title = unicode(title, self.management_page_charset)
        if title and title != self.title:
            self.set_title(title)
            msg += "Title changed. "

        description = unicode(description, self.management_page_charset)
        if description != self._description:
            self.set_description(description)
            msg += "Description changed. "

        if not bool(cacheable) is self.is_cacheable():
            self.set_cacheable(bool(cacheable))
            msg += "Cacheability setting changed. "

        if not bool(previewable) is self.is_previewable():
            self.set_previewable(bool(previewable))
            msg += "Previewable setting changed. "

        if not bool(usable) is self.is_usable():
            self.set_usable(bool(usable))
            msg += "Usability setting changed. "

        if layout_id and layout_id != self._layout_id:
            self._layout_id = layout_id
            msg += "Layout object id changed. "

        return self.editSQLSource(manage_tabs_message=msg)
Beispiel #17
0
class SetupTool( UniqueObject, Folder ):

    """ Profile-based site configuration manager.
    """
    __implements__ = ( ISetupTool, ) + Folder.__implements__

    id = 'portal_setup'
    meta_type = 'Portal Setup Tool'

    _product_name = None
    _profile_directory = None
    _root_directory = None

    security = ClassSecurityInfo()

    def __init__( self ):

        self._import_registry = ImportStepRegistry()
        self._export_registry = ExportStepRegistry()
        self._export_registry.registerStep( 'step_registries'
                                          , exportStepRegistries
                                          , 'Export import / export steps.'
                                          )
        self._toolset_registry = ToolsetRegistry()

    #
    #   ISetupTool API
    #
    security.declareProtected( ManagePortal, 'getProfileProduct' )
    def getProfileProduct( self ):

        """ See ISetupTool.
        """
        return self._product_name

    security.declareProtected( ManagePortal, 'getProfileDirectory' )
    def getProfileDirectory( self, relative_to_product=False ):

        """ See ISetupTool.
        """
        return ( relative_to_product
             and self._profile_directory
              or self._getFullyQualifiedProfileDirectory()
               )

    security.declareProtected( ManagePortal, 'setProfileDirectory' )
    def setProfileDirectory( self, path, product_name=None, encoding=None ):

        """ See ISetupTool.
        """
        if product_name is not None:

            root = self._root_directory = self._getProductPath( product_name )

            if not os.path.exists( os.path.join( root, path ) ):
                raise ValueError, 'Invalid path: %s' % path

        else:
            if not os.path.exists( path ):
                raise ValueError, 'Invalid path: %s' % path

            self._root_directory = None

        self._profile_directory = path
        self._product_name = product_name

        self._updateImportStepsRegistry( encoding )
        self._updateExportStepsRegistry( encoding )
        self._updateToolsetRegistry( encoding )

    security.declareProtected( ManagePortal, 'getImportStepRegistry' )
    def getImportStepRegistry( self ):

        """ See ISetupTool.
        """
        return self._import_registry

    security.declareProtected( ManagePortal, 'getImportStepRegistry' )
    def getExportStepRegistry( self ):

        """ See ISetupTool.
        """
        return self._export_registry

    security.declareProtected( ManagePortal, 'getToolsetRegistry' )
    def getToolsetRegistry( self ):

        """ See ISetupTool.
        """
        return self._toolset_registry

    security.declareProtected( ManagePortal, 'executeStep' )
    def runImportStep( self, step_id, run_dependencies=True, purge_old=True ):

        """ See ISetupTool.
        """
        profile_path = self._getFullyQualifiedProfileDirectory()
        context = DirectoryImportContext( self, profile_path, purge_old )

        info = self._import_registry.getStepMetadata( step_id )

        if info is None:
            raise ValueError, 'No such import step: %s' % step_id

        dependencies = info.get( 'dependencies', () )

        messages = {}
        steps = []
        if run_dependencies:
            for dependency in dependencies:

                if dependency not in steps:
                    message = self._doRunImportStep( dependency, context )
                    messages[ dependency ] = message
                    steps.append( dependency )

        message = self._doRunImportStep( step_id, context )
        messages[ step_id ] = message
        steps.append( step_id )

        return { 'steps' : steps, 'messages' : messages }

    security.declareProtected( ManagePortal, 'runAllSetupSteps')
    def runAllImportSteps( self, purge_old=True ):

        """ See ISetupTool.
        """
        profile_path = self._getFullyQualifiedProfileDirectory()
        context = DirectoryImportContext( self, profile_path, purge_old )

        steps = self._import_registry.sortSteps()
        messages = {}

        for step in steps:
            message = self._doRunImportStep( step, context )
            messages[ step ] = message

        return { 'steps' : steps, 'messages' : messages }

    security.declareProtected( ManagePortal, 'runExportStep')
    def runExportStep( self, step_id ):

        """ See ISetupTool.
        """
        return self._doRunExportSteps( [ step_id ] )

    security.declareProtected(ManagePortal, 'runAllExportSteps')
    def runAllExportSteps( self ):

        """ See ISetupTool.
        """
        return self._doRunExportSteps( self._export_registry.listSteps() )

    security.declareProtected( ManagePortal, 'createSnapshot')
    def createSnapshot( self, snapshot_id ):

        """ See ISetupTool.
        """
        context = SnapshotExportContext( self, snapshot_id )
        messages = {}
        steps = self._export_registry.listSteps()

        for step_id in steps:

            handler = self._export_registry.getStep( step_id )

            if handler is None:
                raise ValueError( 'Invalid export step: %s' % step_id )

            messages[ step_id ] = handler( context )


        return { 'steps' : steps
               , 'messages' : messages
               , 'url' : context.getSnapshotURL()
               , 'snapshot' : context.getSnapshotFolder()
               }

    security.declareProtected(ManagePortal, 'compareConfigurations')
    def compareConfigurations( self
                             , lhs_context
                             , rhs_context
                             , missing_as_empty=False
                             , ignore_blanks=False
                             , skip=( 'CVS', '.svn' )
                             ):
        """ See ISetupTool.
        """
        differ = ConfigDiff( lhs_context
                           , rhs_context
                           , missing_as_empty
                           , ignore_blanks
                           , skip
                           )

        return differ.compare()

    security.declareProtected( ManagePortal, 'markupComparison')
    def markupComparison(self, lines):

        """ See ISetupTool.
        """
        result = []

        for line in lines.splitlines():

            if line.startswith('** '):

                if line.find('File') > -1:
                    if line.find('replaced') > -1:
                        result.append( ( 'file-to-dir', line ) )
                    elif line.find('added') > -1:
                        result.append( ( 'file-added', line ) )
                    else:
                        result.append( ( 'file-removed', line ) )
                else:
                    if line.find('replaced') > -1:
                        result.append( ( 'dir-to-file', line ) )
                    elif line.find('added') > -1:
                        result.append( ( 'dir-added', line ) )
                    else:
                        result.append( ( 'dir-removed', line ) )

            elif line.startswith('@@'):
                result.append( ( 'diff-range', line ) )

            elif line.startswith(' '):
                result.append( ( 'diff-context', line ) )

            elif line.startswith('+'):
                result.append( ( 'diff-added', line ) )

            elif line.startswith('-'):
                result.append( ( 'diff-removed', line ) )

            elif line == '\ No newline at end of file':
                result.append( ( 'diff-context', line ) )

            else:
                result.append( ( 'diff-header', line ) )

        return '<pre>\n%s\n</pre>' % (
            '\n'.join( [ ( '<span class="%s">%s</span>' % ( cl, escape( l ) ) )
                                  for cl, l in result] ) )

    #
    #   ZMI
    #
    manage_options = ( Folder.manage_options[ :1 ]
                     + ( { 'label' : 'Properties'
                         , 'action' : 'manage_tool'
                         }
                       , { 'label' : 'Import'
                         , 'action' : 'manage_importSteps'
                         }
                       , { 'label' : 'Export'
                         , 'action' : 'manage_exportSteps'
                         }
                       , { 'label' : 'Snapshots'
                         , 'action' : 'manage_snapshots'
                         }
                       , { 'label' : 'Comparison'
                         , 'action' : 'manage_showDiff'
                         }
                       )
                     + Folder.manage_options[ 3: ] # skip "View", "Properties"
                     )

    security.declareProtected( ManagePortal, 'manage_tool' )
    manage_tool = PageTemplateFile( 'sutProperties', _wwwdir )

    security.declareProtected( ManagePortal, 'manage_updateToolProperties' )
    def manage_updateToolProperties( self
                                   , profile_directory
                                   , profile_product
                                   , RESPONSE
                                   ):
        """ Update the tool's settings.
        """
        profile_directory = profile_directory.strip()
        profile_product = profile_product.strip()

        if profile_directory.startswith( '.' ):
            raise ValueError(
                    "Directories begining with '.' are not allowed." )

        if profile_product and profile_directory.startswith( '/' ):
            raise ValueError(
                    "Product may not be specified with absolute directories" )

        self.setProfileDirectory( profile_directory, profile_product )

        RESPONSE.redirect( '%s/manage_tool?manage_tabs_message=%s'
                         % ( self.absolute_url(), 'Properties+updated.' )
                         )

    security.declareProtected( ManagePortal, 'manage_importSteps' )
    manage_importSteps = PageTemplateFile( 'sutImportSteps', _wwwdir )

    security.declareProtected( ManagePortal, 'manage_importSelectedSteps' )
    def manage_importSelectedSteps( self
                                  , ids
                                  , run_dependencies
                                  , purge_old
                                  , RESPONSE
                                  ):
        """ Import the steps selected by the user.
        """
        if not ids:
            message = 'No+steps+selected.'

        else:
            steps_run = []
            for step_id in ids:
                result = self.runImportStep( step_id
                                           , run_dependencies
                                           , purge_old
                                           )
                steps_run.extend( result[ 'steps' ] )

            message = 'Steps+run:%s' % '+,'.join( steps_run )

        RESPONSE.redirect( '%s/manage_importSteps?manage_tabs_message=%s'
                         % ( self.absolute_url(), message )
                         )

    security.declareProtected( ManagePortal, 'manage_importSelectedSteps' )
    def manage_importAllSteps( self, purge_old, RESPONSE ):

        """ Import all steps.
        """
        result = self.runAllImportSteps( purge_old )
        message = 'Steps+run:%s' % '+,'.join( result[ 'steps' ] )

        RESPONSE.redirect( '%s/manage_importSteps?manage_tabs_message=%s'
                         % ( self.absolute_url(), message )
                         )

    security.declareProtected( ManagePortal, 'manage_exportSteps' )
    manage_exportSteps = PageTemplateFile( 'sutExportSteps', _wwwdir )

    security.declareProtected( ManagePortal, 'manage_exportSelectedSteps' )
    def manage_exportSelectedSteps( self, ids, RESPONSE ):

        """ Export the steps selected by the user.
        """
        if not ids:
            RESPONSE.redirect( '%s/manage_exportSteps?manage_tabs_message=%s'
                             % ( self.absolute_url(), 'No+steps+selected.' )
                             )

        result = self._doRunExportSteps( ids )
        RESPONSE.setHeader( 'Content-type', 'application/x-gzip')
        RESPONSE.setHeader( 'Content-disposition'
                          , 'attachment; filename=%s' % result[ 'filename' ]
                          )
        return result[ 'tarball' ]

    security.declareProtected( ManagePortal, 'manage_exportAllSteps' )
    def manage_exportAllSteps( self, RESPONSE ):

        """ Export all steps.
        """
        result = self.runAllExportSteps()
        RESPONSE.setHeader( 'Content-type', 'application/x-gzip')
        RESPONSE.setHeader( 'Content-disposition'
                          , 'attachment; filename=%s' % result[ 'filename' ]
                          )
        return result[ 'tarball' ]

    security.declareProtected( ManagePortal, 'manage_snapshots' )
    manage_snapshots = PageTemplateFile( 'sutSnapshots', _wwwdir )

    security.declareProtected( ManagePortal, 'listSnapshotInfo' )
    def listSnapshotInfo( self ):

        """ Return a list of mappings describing available snapshots.

        o Keys include:

          'id' -- snapshot ID

          'title' -- snapshot title or ID

          'url' -- URL of the snapshot folder
        """
        result = []
        snapshots = self._getOb( 'snapshots', None )

        if snapshots:

            for id, folder in snapshots.objectItems( 'Folder' ):

                result.append( { 'id' : id
                               , 'title' : folder.title_or_id()
                               , 'url' : folder.absolute_url()
                               } )
        return result

    security.declareProtected( ManagePortal, 'listProfileInfo' )
    def listProfileInfo( self ):

        """ Return a list of mappings describing registered profiles.

        o Keys include:

          'id' -- profile ID

          'title' -- profile title or ID

          'description' -- description of the profile

          'path' -- path to the profile within its product

          'product' -- name of the registering product
        """
        return _profile_registry.listProfileInfo()

    security.declareProtected( ManagePortal, 'manage_createSnapshot' )
    def manage_createSnapshot( self, RESPONSE, snapshot_id=None ):

        """ Create a snapshot with the given ID.

        o If no ID is passed, generate one.
        """
        if snapshot_id is None:
            timestamp = time.gmtime()
            snapshot_id = 'snapshot-%4d%02d%02d%02d%02d%02d' % timestamp[:6]

        self.createSnapshot( snapshot_id )

        RESPONSE.redirect( '%s/manage_snapshots?manage_tabs_message=%s'
                         % ( self.absolute_url(), 'Snapshot+created.' ) )

    security.declareProtected( ManagePortal, 'manage_showDiff' )
    manage_showDiff = PageTemplateFile( 'sutCompare', _wwwdir )

    def manage_downloadDiff( self
                           , lhs
                           , rhs
                           , missing_as_empty
                           , ignore_blanks
                           , RESPONSE
                           ):
        """ Crack request vars and call compareConfigurations.

        o Return the result as a 'text/plain' stream, suitable for framing.
        """
        comparison = self.manage_compareConfigurations( lhs
                                                      , rhs
                                                      , missing_as_empty
                                                      , ignore_blanks
                                                      )
        RESPONSE.setHeader( 'Content-Type', 'text/plain' )
        return _PLAINTEXT_DIFF_HEADER % ( lhs, rhs, comparison )

    security.declareProtected( ManagePortal, 'manage_compareConfigurations' )
    def manage_compareConfigurations( self
                                    , lhs
                                    , rhs
                                    , missing_as_empty
                                    , ignore_blanks
                                    ):
        """ Crack request vars and call compareConfigurations.
        """
        lhs_context = self._getImportContext( lhs )
        rhs_context = self._getImportContext( rhs )

        return self.compareConfigurations( lhs_context
                                         , rhs_context
                                         , missing_as_empty
                                         , ignore_blanks
                                         )


    #
    #   Helper methods
    #
    security.declarePrivate( '_getProductPath' )
    def _getProductPath( self, product_name ):

        """ Return the absolute path of the product's directory.
        """
        try:
            product = __import__( 'Products.%s' % product_name
                                , globals(), {}, ['initialize' ] )
        except ImportError:
            raise ValueError, 'Not a valid product name: %s' % product_name

        return product.__path__[0]

    security.declarePrivate( '_getImportContext' )
    def _getImportContext( self, context_id ):

        """ Crack ID and generate appropriate import context.
        """
        if context_id.startswith( 'profile-' ):

            context_id = context_id[ len( 'profile-' ): ]
            info = _profile_registry.getProfileInfo( context_id )

            if info.get( 'product' ):
                path = os.path.join( self._getProductPath( info[ 'product' ] )
                                   , info[ 'path' ] )
            else:
                path = info[ 'path' ]

            return DirectoryImportContext( self, path )

        # else snapshot
        context_id = context_id[ len( 'snapshot-' ): ]
        return SnapshotImportContext( self, context_id )

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

        """ Return the fully-qualified directory path of our profile.
        """
        if self._root_directory is not None:
            return os.path.join( self._root_directory
                               , self._profile_directory )

        return self._profile_directory

    security.declarePrivate( '_updateImportStepsRegistry' )
    def _updateImportStepsRegistry( self, encoding ):

        """ Update our import steps registry from our profile.
        """
        fq = self._getFullyQualifiedProfileDirectory()

        f = open( os.path.join( fq, IMPORT_STEPS_XML ), 'r' )
        xml = f.read()
        f.close()

        info_list = self._import_registry.parseXML( xml, encoding )

        for step_info in info_list:

            id = step_info[ 'id' ]
            version = step_info[ 'version' ]
            handler = _resolveDottedName( step_info[ 'handler' ] )

            dependencies = tuple( step_info.get( 'dependencies', () ) )
            title = step_info.get( 'title', id )
            description = ''.join( step_info.get( 'description', [] ) )

            self._import_registry.registerStep( id=id
                                              , version=version
                                              , handler=handler
                                              , dependencies=dependencies
                                              , title=title
                                              , description=description
                                              )

    security.declarePrivate( '_updateExportStepsRegistry' )
    def _updateExportStepsRegistry( self, encoding ):

        """ Update our export steps registry from our profile.
        """
        fq = self._getFullyQualifiedProfileDirectory()

        f = open( os.path.join( fq, EXPORT_STEPS_XML ), 'r' )
        xml = f.read()
        f.close()

        info_list = self._export_registry.parseXML( xml, encoding )

        for step_info in info_list:

            id = step_info[ 'id' ]
            handler = _resolveDottedName( step_info[ 'handler' ] )

            title = step_info.get( 'title', id )
            description = ''.join( step_info.get( 'description', [] ) )

            self._export_registry.registerStep( id=id
                                              , handler=handler
                                              , title=title
                                              , description=description
                                              )

    security.declarePrivate( '_updateToolsetRegistry' )
    def _updateToolsetRegistry( self, encoding ):

        """ Update our toolset registry from our profile.
        """
        fq = self._getFullyQualifiedProfileDirectory()

        f = open( os.path.join( fq, TOOLSET_XML ), 'r' )
        xml = f.read()
        f.close()

        self._toolset_registry.parseXML( xml, encoding )

    security.declarePrivate( '_doRunImportStep' )
    def _doRunImportStep( self, step_id, context ):

        """ Run a single import step, using a pre-built context.
        """
        handler = self._import_registry.getStep( step_id )

        if handler is None:
            raise ValueError( 'Invalid import step: %s' % step_id )

        return handler( context )

    security.declarePrivate( '_doRunExportSteps')
    def _doRunExportSteps( self, steps ):

        """ See ISetupTool.
        """
        context = TarballExportContext( self )
        messages = {}

        for step_id in steps:

            handler = self._export_registry.getStep( step_id )

            if handler is None:
                raise ValueError( 'Invalid export step: %s' % step_id )

            messages[ step_id ] = handler( context )


        return { 'steps' : steps
               , 'messages' : messages
               , 'tarball' : context.getArchive()
               , 'filename' : context.getArchiveFilename()
               }
Beispiel #18
0
class StateDefinition(SimpleItem):
    """State definition"""

    meta_type = 'Workflow State'

    manage_options = (
        {
            'label': 'Properties',
            'action': 'manage_properties'
        },
        {
            'label': 'Permissions',
            'action': 'manage_permissions'
        },
        {
            'label': 'Groups',
            'action': 'manage_groups'
        },
        {
            'label': 'Variables',
            'action': 'manage_variables'
        },
    )

    title = ''
    description = ''
    transitions = ()  # The ids of possible transitions.
    permission_roles = None  # { permission: [role] or (role,) }
    group_roles = None  # { group name : (role,) }
    var_values = None  # PersistentMapping if set.  Overrides transition exprs.

    security = ClassSecurityInfo()
    security.declareObjectProtected(ManagePortal)

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

    def getId(self):
        return self.id

    def getWorkflow(self):
        return aq_parent(aq_inner(aq_parent(aq_inner(self))))

    def getTransitions(self):
        return filter(self.getWorkflow().transitions.has_key, self.transitions)

    def getTransitionTitle(self, tid):
        t = self.getWorkflow().transitions.get(tid, None)
        if t is not None:
            return t.title
        return ''

    def getAvailableTransitionIds(self):
        return self.getWorkflow().transitions.keys()

    def getAvailableVarIds(self):
        return self.getWorkflow().variables.keys()

    def getManagedPermissions(self):
        return list(self.getWorkflow().permissions)

    def getAvailableRoles(self):
        return self.getWorkflow().getAvailableRoles()

    def getPermissionInfo(self, p):
        """Returns the list of roles to be assigned to a permission.
        """
        roles = None
        if self.permission_roles:
            roles = self.permission_roles.get(p, None)
        if roles is None:
            return {'acquired': 1, 'roles': []}
        else:
            if isinstance(roles, tuple):
                acq = 0
            else:
                acq = 1
            return {'acquired': acq, 'roles': list(roles)}

    def getGroupInfo(self, group):
        """Returns the list of roles to be assigned to a group.
        """
        if self.group_roles:
            return self.group_roles.get(group, ())
        return ()

    _properties_form = DTMLFile('state_properties', _dtmldir)

    def manage_properties(self, REQUEST, manage_tabs_message=None):
        """Show state properties ZMI form."""
        return self._properties_form(
            REQUEST,
            management_view='Properties',
            manage_tabs_message=manage_tabs_message,
        )

    def setProperties(self,
                      title='',
                      transitions=(),
                      REQUEST=None,
                      description=''):
        """Set the properties for this State."""
        self.title = str(title)
        self.description = str(description)
        self.transitions = tuple(map(str, transitions))
        if REQUEST is not None:
            return self.manage_properties(REQUEST, 'Properties changed.')

    _variables_form = DTMLFile('state_variables', _dtmldir)

    def manage_variables(self, REQUEST, manage_tabs_message=None):
        """Show State variables ZMI form."""
        return self._variables_form(
            REQUEST,
            management_view='Variables',
            manage_tabs_message=manage_tabs_message,
        )

    def getVariableValues(self):
        """Get VariableValues for management UI."""
        vv = self.var_values
        if vv is None:
            return []
        else:
            return vv.items()

    def getWorkflowVariables(self):
        """Get all variables that are available from the workflow and
        not handled yet.
        """
        wf_vars = self.getAvailableVarIds()
        if self.var_values is None:
            return wf_vars
        ret = []
        for vid in wf_vars:
            if not self.var_values.has_key(vid):
                ret.append(vid)
        return ret

    def addVariable(self, id, value, REQUEST=None):
        """Add a WorkflowVariable to State."""
        if self.var_values is None:
            self.var_values = PersistentMapping()

        self.var_values[id] = value

        if REQUEST is not None:
            return self.manage_variables(REQUEST, 'Variable added.')

    def deleteVariables(self, ids=[], REQUEST=None):
        """Delete a WorkflowVariable from State."""
        vv = self.var_values
        for id in ids:
            if vv.has_key(id):
                del vv[id]

        if REQUEST is not None:
            return self.manage_variables(REQUEST, 'Variables deleted.')

    def setVariables(self, ids=[], REQUEST=None):
        """Set values for Variables set by this State."""
        if self.var_values is None:
            self.var_values = PersistentMapping()

        vv = self.var_values

        if REQUEST is not None:
            for id in vv.keys():
                fname = 'varval_%s' % id
                vv[id] = str(REQUEST[fname])
            return self.manage_variables(REQUEST, 'Variables changed.')

    _permissions_form = DTMLFile('state_permissions', _dtmldir)

    def manage_permissions(self, REQUEST, manage_tabs_message=None):
        """Present TTW UI for managing this State's permissions."""
        return self._permissions_form(
            REQUEST,
            management_view='Permissions',
            manage_tabs_message=manage_tabs_message,
        )

    def setPermissions(self, REQUEST):
        """Set the permissions in REQUEST for this State."""
        pr = self.permission_roles
        if pr is None:
            self.permission_roles = pr = PersistentMapping()
        pr.clear()
        for p in self.getManagedPermissions():
            roles = []
            acquired = REQUEST.get('acquire_' + p, 0)
            for r in self.getAvailableRoles():
                if REQUEST.get('%s|%s' % (p, r), 0):
                    roles.append(r)
            roles.sort()
            if not acquired:
                roles = tuple(roles)
            pr[p] = roles
        return self.manage_permissions(REQUEST, 'Permissions changed.')

    def setPermission(self, permission, acquired, roles):
        """Set a permission for this State."""
        pr = self.permission_roles
        if pr is None:
            self.permission_roles = pr = PersistentMapping()
        if acquired:
            roles = list(roles)
        else:
            roles = tuple(roles)
        pr[permission] = roles

    manage_groups = PageTemplateFile('state_groups.pt', _dtmldir)

    def setGroups(self, REQUEST, RESPONSE=None):
        """Set the group to role mappings in REQUEST for this State.
        """
        map = self.group_roles
        if map is None:
            self.group_roles = map = PersistentMapping()
        map.clear()
        all_roles = self.getWorkflow().getRoles()
        for group in self.getWorkflow().getGroups():
            roles = []
            for role in all_roles:
                if REQUEST.get('%s|%s' % (group, role), 0):
                    roles.append(role)
            roles.sort()
            roles = tuple(roles)
            map[group] = roles
        if RESPONSE is not None:
            RESPONSE.redirect(
                "%s/manage_groups?manage_tabs_message=Groups+changed." %
                self.absolute_url())
Beispiel #19
0
                else:
                    raise ValueError("Confirmation key not found")
        else:
            if REQUEST is not None:
                self.setSessionErrorsTrans("Confirmation key is invalid")
            else:
                raise ValueError("Confirmation key is invalid")

        if REQUEST is not None:
            return REQUEST.RESPONSE.redirect(self.absolute_url() +
                                             '/my_subscriptions_html')

    # Administration

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS, 'admin_html')
    admin_html = PageTemplateFile('zpt/admin', globals())

    security.declareProtected(PERMISSION_PUBLISH_OBJECTS,
                              'admin_get_subscriptions')

    def admin_get_subscriptions(self, user_query=''):
        user_query = user_query.strip()
        for obj, sub_id, subscription in utils.walk_subscriptions(
                self.getSite()):
            user = subscription.to_string(obj)
            if not user_query or re.match('.*%s.*' % user_query, user,
                                          re.IGNORECASE):
                yield {
                    'user': user,
                    'location': relative_object_path(obj, self.getSite()),
                    'sub_id': sub_id,
Beispiel #20
0
            report = report.encode('latin-1')

        # BBB: ObjectManager won't allow unicode IDS
        if isinstance(name, unicode):
            name = name.encode('UTF-8')

        file = File(id=name,
                    title='',
                    file=report,
                    content_type='text/plain'
                   )
        self._setObject(name, file)

InitializeClass(SetupTool)

_PLAINTEXT_DIFF_HEADER ="""\
Comparing configurations: '%s' and '%s'

%s"""

_TOOL_ID = 'setup_tool'

addSetupToolForm = PageTemplateFile('toolAdd.zpt', _wwwdir)

def addSetupTool(dispatcher, RESPONSE):
    """
    """
    dispatcher._setObject(_TOOL_ID, SetupTool(_TOOL_ID))

    RESPONSE.redirect('%s/manage_main' % dispatcher.absolute_url())
Beispiel #21
0
from AccessControl.Permissions import manage_users
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PluggableAuthService import registerMultiPlugin

import plugin

manage_add_rpx_form = PageTemplateFile('browser/add_plugin',
                                       globals(),
                                       __name__='manage_add_rpx_form')


def manage_add_rpx_helper(dispatcher, id, title=None, REQUEST=None):
    """Add an rpx Helper to the PluggableAuthentication Service."""

    sp = plugin.RpxHelper(id, title)
    dispatcher._setObject(sp.getId(), sp)

    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect('%s/manage_workspace'
                                     '?manage_tabs_message='
                                     'rpxHelper+added.' %
                                     dispatcher.absolute_url())


def register_rpx_plugin():
    try:
        registerMultiPlugin(plugin.RpxHelper.meta_type)
    except RuntimeError:
        # make refresh users happy
        pass
Beispiel #22
0
class SetupTool(Folder):

    """ Profile-based site configuration manager.
    """

    implements(ISetupTool)

    meta_type = 'Generic Setup Tool'

    _baseline_context_id = ''
    # BBB _import_context_id is a vestige of a stateful import context
    _import_context_id = ''

    _profile_upgrade_versions = {}

    security = ClassSecurityInfo()

    def __init__(self, id):
        self.id = str(id)
        self._import_registry = ImportStepRegistry()
        self._export_registry = ExportStepRegistry()
        self._toolset_registry = ToolsetRegistry()

    #
    #   ISetupTool API
    #
    security.declareProtected(ManagePortal, 'getEncoding')
    def getEncoding(self):

        """ See ISetupTool.
        """
        return 'utf-8'

    security.declareProtected(ManagePortal, 'getImportContextID')
    def getImportContextID(self):

        """ See ISetupTool.
        """
        warn('getImportContextId, and the very concept of a stateful '
             'active import context, is deprecated.  You can find the '
             'base profile that was applied using getBaselineContextID.',
             DeprecationWarning, stacklevel=2)
        return self._import_context_id

    security.declareProtected(ManagePortal, 'getBaselineContextID')
    def getBaselineContextID(self):

        """ See ISetupTool.
        """
        return self._baseline_context_id

    security.declareProtected(ManagePortal, 'setImportContext')
    def setImportContext(self, context_id, encoding=None):
        """ See ISetupTool.
        """
        warn('setImportContext is deprecated.  Use setBaselineContext to '
             'specify the baseline context, and/or runImportStepFromProfile '
             'to run the steps from a specific import context.',
             DeprecationWarning, stacklevel=2)
        self._import_context_id = context_id

        context_type = BASE  # snapshots are always baseline contexts
        if context_id.startswith('profile-'):
            profile_info = _profile_registry.getProfileInfo(context_id[8:])
            context_type = profile_info['type']

        if context_type == BASE:
            self.setBaselineContext(context_id, encoding)

    security.declareProtected(ManagePortal, 'setBaselineContext')
    def setBaselineContext(self, context_id, encoding=None):
        """ See ISetupTool.
        """
        self._baseline_context_id = context_id
        self.applyContextById(context_id, encoding)


    security.declareProtected(ManagePortal, 'applyContextById')
    def applyContextById(self, context_id, encoding=None):
        context = self._getImportContext(context_id)
        self.applyContext(context, encoding)


    security.declareProtected(ManagePortal, 'applyContext')
    def applyContext(self, context, encoding=None):
        self._updateImportStepsRegistry(context, encoding)
        self._updateExportStepsRegistry(context, encoding)

    security.declareProtected(ManagePortal, 'getImportStepRegistry')
    def getImportStepRegistry(self):

        """ See ISetupTool.
        """
        return self._import_registry

    security.declareProtected(ManagePortal, 'getExportStepRegistry')
    def getExportStepRegistry(self):

        """ See ISetupTool.
        """
        return self._export_registry

    security.declareProtected(ManagePortal, 'getExportStep')
    def getExportStep(self, step, default=None):
        """Simple wrapper to query both the global and local step registry."""
        res=_export_step_registry.getStep(step, default)
        if res is not default:
            return res
        return self._export_registry.getStep(step, default)

    security.declareProtected(ManagePortal, 'listExportSteps')
    def listExportSteps(self):
        steps = _export_step_registry.listSteps() + \
                self._export_registry.listSteps()
        return tuple(set(steps))

    security.declareProtected(ManagePortal, 'getImportStep')
    def getImportStep(self, step, default=None):
        """Simple wrapper to query both the global and local step registry."""
        res=_import_step_registry.getStep(step, default)
        if res is not default:
            return res
        return self._import_registry.getStep(step, default)

    security.declareProtected(ManagePortal, 'getSortedImportSteps')
    def getSortedImportSteps(self):
        steps = _import_step_registry.listSteps() + \
                self._import_registry.listSteps()
        step_infos = [ self.getImportStepMetadata(step)
                       for step in set(steps) ]
        return tuple(_computeTopologicalSort(step_infos))

    security.declareProtected(ManagePortal, 'getImportStepMetadata')
    def getImportStepMetadata(self, step, default=None):
        """Simple wrapper to query both the global and local step registry."""
        res=self._import_registry.getStepMetadata(step, default)
        if res is not default:
            return res
        return _import_step_registry.getStepMetadata(step, default)

    security.declareProtected(ManagePortal, 'getExportStepMetadata')
    def getExportStepMetadata(self, step, default=None):
        """Simple wrapper to query both the global and local step registry."""
        res=self._export_registry.getStepMetadata(step, default)
        if res is not default:
            return res
        return _export_step_registry.getStepMetadata(step, default)

    security.declareProtected(ManagePortal, 'getToolsetRegistry')
    def getToolsetRegistry(self):

        """ See ISetupTool.
        """
        return self._toolset_registry

    security.declareProtected(ManagePortal, 'runImportStepFromProfile')
    def runImportStepFromProfile(self, profile_id, step_id,
                                 run_dependencies=True, purge_old=None):
        """ See ISetupTool.
        """
        old_context = self._import_context_id
        context = self._getImportContext(profile_id, purge_old)

        self.applyContext(context)

        info = self.getImportStepMetadata(step_id)

        if info is None:
            self._import_context_id = old_context
            raise ValueError, 'No such import step: %s' % step_id

        dependencies = info.get('dependencies', ())

        messages = {}
        steps = []

        if run_dependencies:
            for dependency in dependencies:
                if dependency not in steps:
                    steps.append(dependency)
        steps.append (step_id)

        full_import=(set(steps)==set(self.getSortedImportSteps()))
        event.notify(BeforeProfileImportEvent(self, profile_id, steps, full_import))

        for step in steps:
            message = self._doRunImportStep(step, context)
            messages[step] = message or ''

        message_list = filter(None, [message])
        message_list.extend( ['%s: %s' % x[1:] for x in context.listNotes()] )
        messages[step_id] = '\n'.join(message_list)

        self._import_context_id = old_context

        event.notify(ProfileImportedEvent(self, profile_id, steps, full_import))

        return { 'steps' : steps, 'messages' : messages }

    security.declareProtected(ManagePortal, 'runImportStep')
    def runImportStep(self, step_id, run_dependencies=True, purge_old=None):

        """ See ISetupTool.
        """
        warn('The runImportStep method is deprecated.  Please use '
             'runImportStepFromProfile instead.',
             DeprecationWarning, stacklevel=2)
        return self.runImportStepFromProfile(self._import_context_id,
                                             step_id,
                                             run_dependencies,
                                             purge_old,
                                             )

    security.declareProtected(ManagePortal, 'runAllImportStepsFromProfile')
    def runAllImportStepsFromProfile(self,
                                     profile_id,
                                     purge_old=None,
                                     ignore_dependencies=False,
                                     archive=None):

        """ See ISetupTool.
        """
        __traceback_info__ = profile_id

        old_context = self._import_context_id

        result = self._runImportStepsFromContext(purge_old=purge_old,
                                                 profile_id=profile_id,
                                                 archive=archive,
                                                 ignore_dependencies=ignore_dependencies)
        if profile_id is None:
            prefix = 'import-all-from-tar'
        else:
            prefix = 'import-all-%s' % profile_id.replace(':', '_')
        name = self._mangleTimestampName(prefix, 'log')
        self._createReport(name, result['steps'], result['messages'])

        self._import_context_id = old_context

        return result

    security.declareProtected(ManagePortal, 'runAllImportSteps')
    def runAllImportSteps(self, purge_old=None):

        """ See ISetupTool.
        """
        warn('The runAllImportSteps method is deprecated.  Please use '
             'runAllImportStepsFromProfile instead.',
             DeprecationWarning, stacklevel=2)
        context_id = self._import_context_id
        return self.runAllImportStepsFromProfile(self._import_context_id,
                                                 purge_old)

    security.declareProtected(ManagePortal, 'runExportStep')
    def runExportStep(self, step_id):

        """ See ISetupTool.
        """
        return self._doRunExportSteps([step_id])

    security.declareProtected(ManagePortal, 'runAllExportSteps')
    def runAllExportSteps(self):

        """ See ISetupTool.
        """
        return self._doRunExportSteps(self.listExportSteps())

    security.declareProtected(ManagePortal, 'createSnapshot')
    def createSnapshot(self, snapshot_id):

        """ See ISetupTool.
        """
        context = SnapshotExportContext(self, snapshot_id)
        messages = {}
        steps = self.listExportSteps()

        for step_id in steps:

            handler = self.getExportStep(step_id)

            if handler is None:
                logger = logging.getLogger('GenericSetup')
                logger.error('Step %s has an invalid handler' % step_id)
                continue

            messages[step_id] = handler(context)


        return { 'steps' : steps
               , 'messages' : messages
               , 'url' : context.getSnapshotURL()
               , 'snapshot' : context.getSnapshotFolder()
               }

    security.declareProtected(ManagePortal, 'compareConfigurations')
    def compareConfigurations(self,
                              lhs_context,
                              rhs_context,
                              missing_as_empty=False,
                              ignore_blanks=False,
                              skip=SKIPPED_FILES,
                             ):
        """ See ISetupTool.
        """
        differ = ConfigDiff(lhs_context,
                            rhs_context,
                            missing_as_empty,
                            ignore_blanks,
                            skip,
                           )

        return differ.compare()

    security.declareProtected(ManagePortal, 'markupComparison')
    def markupComparison(self, lines):

        """ See ISetupTool.
        """
        result = []

        for line in lines.splitlines():

            if line.startswith('** '):

                if line.find('File') > -1:
                    if line.find('replaced') > -1:
                        result.append(('file-to-dir', line))
                    elif line.find('added') > -1:
                        result.append(('file-added', line))
                    else:
                        result.append(('file-removed', line))
                else:
                    if line.find('replaced') > -1:
                        result.append(('dir-to-file', line))
                    elif line.find('added') > -1:
                        result.append(('dir-added', line))
                    else:
                        result.append(('dir-removed', line))

            elif line.startswith('@@'):
                result.append(('diff-range', line))

            elif line.startswith(' '):
                result.append(('diff-context', line))

            elif line.startswith('+'):
                result.append(('diff-added', line))

            elif line.startswith('-'):
                result.append(('diff-removed', line))

            elif line == '\ No newline at end of file':
                result.append(('diff-context', line))

            else:
                result.append(('diff-header', line))

        return '<pre>\n%s\n</pre>' % (
            '\n'.join([('<span class="%s">%s</span>' % (cl, escape(l)))
                                  for cl, l in result]))

    #
    #   ZMI
    #
    manage_options = (Folder.manage_options[:1]
                    + ({'label' : 'Profiles',
                        'action' : 'manage_tool'
                       },
                       {'label' : 'Import',
                        'action' : 'manage_importSteps'
                       },
                       {'label' : 'Export',
                        'action' : 'manage_exportSteps'
                       },
                       {'label' : 'Upgrades',
                        'action' : 'manage_upgrades'
                        },
                       {'label' : 'Snapshots',
                        'action' : 'manage_snapshots'
                       },
                       {'label' : 'Comparison',
                        'action' : 'manage_showDiff'
                       },
                       {'label' : 'Manage',
                        'action' : 'manage_stepRegistry'
                       },
                      )
                    + Folder.manage_options[3:] # skip "View", "Properties"
                     )

    security.declareProtected(ManagePortal, 'manage_tool')
    manage_tool = PageTemplateFile('sutProperties', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_updateToolProperties')
    def manage_updateToolProperties(self, context_id, RESPONSE):
        """ Update the tool's settings.
        """
        self.setBaselineContext(context_id)

        RESPONSE.redirect('%s/manage_tool?manage_tabs_message=%s'
                         % (self.absolute_url(), 'Properties+updated.'))

    security.declareProtected(ManagePortal, 'manage_importSteps')
    manage_importSteps = PageTemplateFile('sutImportSteps', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_importSelectedSteps')
    def manage_importSelectedSteps(self, ids, run_dependencies, context_id=None):
        """ Import the steps selected by the user.
        """
        messages = {}
        if not ids:
            summary = 'No steps selected.'

        else:
            if context_id is None:
                context_id = self.getBaselineContextID()
            steps_run = []
            for step_id in ids:
                result = self.runImportStepFromProfile(context_id,
                                                       step_id,
                                                       run_dependencies)
                steps_run.extend(result['steps'])
                messages.update(result['messages'])

            summary = 'Steps run: %s' % ', '.join(steps_run)

            name = self._mangleTimestampName('import-selected', 'log')
            self._createReport(name, result['steps'], result['messages'])

        return self.manage_importSteps(manage_tabs_message=summary,
                                       messages=messages)

    security.declareProtected(ManagePortal, 'manage_importSelectedSteps')
    def manage_importAllSteps(self, context_id=None):

        """ Import all steps.
        """
        if context_id is None:
            context_id = self.getBaselineContextID()
        result = self.runAllImportStepsFromProfile(context_id, purge_old=None)

        steps_run = 'Steps run: %s' % ', '.join(result['steps'])

        return self.manage_importSteps(manage_tabs_message=steps_run,
                                       messages=result['messages'])

    security.declareProtected(ManagePortal, 'manage_importExtensions')
    def manage_importExtensions(self, RESPONSE, profile_ids=()):

        """ Import all steps for the selected extension profiles.
        """
        detail = {}
        if len(profile_ids) == 0:
            message = 'Please select one or more extension profiles.'
            RESPONSE.redirect('%s/manage_tool?manage_tabs_message=%s'
                                  % (self.absolute_url(), message))
        else:
            message = 'Imported profiles: %s' % ', '.join(profile_ids)
        
            for profile_id in profile_ids:

                result = self.runAllImportStepsFromProfile(profile_id)

                for k, v in result['messages'].items():
                    detail['%s:%s' % (profile_id, k)] = v

            return self.manage_importSteps(manage_tabs_message=message,
                                        messages=detail)

    security.declareProtected(ManagePortal, 'manage_importTarball')
    def manage_importTarball(self, tarball):
        """ Import steps from the uploaded tarball.
        """
        if getattr(tarball, 'read', None) is not None:
            tarball = tarball.read()

        result = self.runAllImportStepsFromProfile(None, True, archive=tarball)

        steps_run = 'Steps run: %s' % ', '.join(result['steps'])

        return self.manage_importSteps(manage_tabs_message=steps_run,
                                       messages=result['messages'])

    security.declareProtected(ManagePortal, 'manage_exportSteps')
    manage_exportSteps = PageTemplateFile('sutExportSteps', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_exportSelectedSteps')
    def manage_exportSelectedSteps(self, ids, RESPONSE):

        """ Export the steps selected by the user.
        """
        if not ids:
            RESPONSE.redirect('%s/manage_exportSteps?manage_tabs_message=%s'
                             % (self.absolute_url(), 'No+steps+selected.'))

        result = self._doRunExportSteps(ids)
        RESPONSE.setHeader('Content-type', 'application/x-gzip')
        RESPONSE.setHeader('Content-disposition',
                           'attachment; filename=%s' % result['filename'])
        return result['tarball']

    security.declareProtected(ManagePortal, 'manage_exportAllSteps')
    def manage_exportAllSteps(self, RESPONSE):

        """ Export all steps.
        """
        result = self.runAllExportSteps()
        RESPONSE.setHeader('Content-type', 'application/x-gzip')
        RESPONSE.setHeader('Content-disposition',
                           'attachment; filename=%s' % result['filename'])
        return result['tarball']

    security.declareProtected(ManagePortal, 'manage_upgrades')
    manage_upgrades = PageTemplateFile('setup_upgrades', _wwwdir)

    security.declareProtected(ManagePortal, 'upgradeStepMacro')
    upgradeStepMacro = PageTemplateFile('upgradeStep', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_snapshots')
    manage_snapshots = PageTemplateFile('sutSnapshots', _wwwdir)

    security.declareProtected(ManagePortal, 'listSnapshotInfo')
    def listSnapshotInfo(self):

        """ Return a list of mappings describing available snapshots.

        o Keys include:

          'id' -- snapshot ID

          'title' -- snapshot title or ID

          'url' -- URL of the snapshot folder
        """
        result = []
        snapshots = self._getOb('snapshots', None)

        if snapshots:

            for id, folder in snapshots.objectItems('Folder'):

                result.append({ 'id' : id
                               , 'title' : folder.title_or_id()
                               , 'url' : folder.absolute_url()
                               })
        return result

    security.declareProtected(ManagePortal, 'listProfileInfo')
    def listProfileInfo(self, for_=None):

        """ Return a list of mappings describing registered profiles.
        Base profile is listed first, extensions are sorted.

        o Keys include:

          'id' -- profile ID

          'title' -- profile title or ID

          'description' -- description of the profile

          'path' -- path to the profile within its product

          'product' -- name of the registering product
        """
        base = []
        ext = []
        for info in _profile_registry.listProfileInfo(for_):
            if info.get('type', BASE) == BASE:
                base.append(info)
            else:
                ext.append(info)
        ext.sort(lambda x, y: cmp(x['id'], y['id']))
        return base + ext

    security.declareProtected(ManagePortal, 'listContextInfos')
    def listContextInfos(self):

        """ List registered profiles and snapshots.
        """
        def readableType(x):
            if x is BASE:
                return 'base'
            elif x is EXTENSION:
                return 'extension'
            return 'unknown'

        s_infos = [{'id': 'snapshot-%s' % info['id'],
                     'title': info['title'],
                     'type': 'snapshot',
                   }
                    for info in self.listSnapshotInfo()]
        p_infos = [{'id': 'profile-%s' % info['id'],
                    'title': info['title'],
                    'type': readableType(info['type']),
                   }
                   for info in self.listProfileInfo()]

        return tuple(s_infos + p_infos)

    security.declareProtected(ManagePortal, 'getProfileImportDate')
    def getProfileImportDate(self, profile_id):
        """ See ISetupTool.
        """
        prefix = ('import-all-%s-' % profile_id).replace(':', '_')
        candidates = [x for x in self.objectIds('File')
                        if x[:-18]==prefix and x.endswith('.log')]
        if len(candidates) == 0:
            return None
        candidates.sort()
        last = candidates[-1]
        stamp = last[-18:-4]
        return '%s-%s-%sT%s:%s:%sZ' % (stamp[0:4],
                                       stamp[4:6],
                                       stamp[6:8],
                                       stamp[8:10],
                                       stamp[10:12],
                                       stamp[12:14],
                                      )

    security.declareProtected(ManagePortal, 'manage_createSnapshot')
    def manage_createSnapshot(self, RESPONSE, snapshot_id=None):

        """ Create a snapshot with the given ID.

        o If no ID is passed, generate one.
        """
        if snapshot_id is None:
            snapshot_id = self._mangleTimestampName('snapshot')

        self.createSnapshot(snapshot_id)

        return RESPONSE.redirect('%s/manage_snapshots?manage_tabs_message=%s'
                         % (self.absolute_url(), 'Snapshot+created.'))

    security.declareProtected(ManagePortal, 'manage_showDiff')
    manage_showDiff = PageTemplateFile('sutCompare', _wwwdir)

    def manage_downloadDiff(self,
                            lhs,
                            rhs,
                            missing_as_empty,
                            ignore_blanks,
                            RESPONSE,
                           ):
        """ Crack request vars and call compareConfigurations.

        o Return the result as a 'text/plain' stream, suitable for framing.
        """
        comparison = self.manage_compareConfigurations(lhs,
                                                       rhs,
                                                       missing_as_empty,
                                                       ignore_blanks,
                                                      )
        RESPONSE.setHeader('Content-Type', 'text/plain')
        return _PLAINTEXT_DIFF_HEADER % (lhs, rhs, comparison)

    security.declareProtected(ManagePortal, 'manage_compareConfigurations')
    def manage_compareConfigurations(self,
                                     lhs,
                                     rhs,
                                     missing_as_empty,
                                     ignore_blanks,
                                    ):
        """ Crack request vars and call compareConfigurations.
        """
        lhs_context = self._getImportContext(lhs)
        rhs_context = self._getImportContext(rhs)

        return self.compareConfigurations(lhs_context,
                                          rhs_context,
                                          missing_as_empty,
                                          ignore_blanks,
                                         )

    security.declareProtected(ManagePortal, 'manage_stepRegistry')
    manage_stepRegistry = PageTemplateFile('sutManage', _wwwdir)

    security.declareProtected(ManagePortal, 'manage_deleteImportSteps')
    def manage_deleteImportSteps(self, ids, request=None):
        if request is None:
            request = self.REQUEST
        for id in ids:
            self._import_registry.unregisterStep(id)
        self._p_changed=True
        url = self.absolute_url()
        request.RESPONSE.redirect("%s/manage_stepRegistry" % url)

    security.declareProtected(ManagePortal, 'manage_deleteExportSteps')
    def manage_deleteExportSteps(self, ids, request=None):
        if request is None:
            request = self.REQUEST
        for id in ids:
            self._export_registry.unregisterStep(id)
        self._p_changed=True
        url = self.absolute_url()
        request.RESPONSE.redirect("%s/manage_stepRegistry" % url)

    #
    # Upgrades management
    #
    security.declareProtected(ManagePortal, 'getLastVersionForProfile')
    def getLastVersionForProfile(self, profile_id):
        """Return the last upgraded version for the specified profile.
        """
        version = self._profile_upgrade_versions.get(profile_id, 'unknown')
        return version

    security.declareProtected(ManagePortal, 'setLastVersionForProfile')
    def setLastVersionForProfile(self, profile_id, version):
        """Set the last upgraded version for the specified profile.
        """
        if isinstance(version, basestring):
            version = tuple(version.split('.'))
        prof_versions = self._profile_upgrade_versions.copy()
        prof_versions[profile_id] = version
        self._profile_upgrade_versions = prof_versions

    security.declareProtected(ManagePortal, 'getVersionForProfile')
    def getVersionForProfile(self, profile_id):
        """Return the registered filesystem version for the specified
        profile.
        """
        return self.getProfileInfo( profile_id ).get('version', 'unknown')

    security.declareProtected(ManagePortal, 'profileExists')
    def profileExists(self, profile_id):
        """Check if a profile exists."""
        try:
            self.getProfileInfo( profile_id )
        except KeyError:
            return False
        else:
            return True

    security.declareProtected(ManagePortal, "getProfileInfo")
    def getProfileInfo(self, profile_id):
        if profile_id.startswith("profile-"):
            profile_id = profile_id[len('profile-'):]
        elif profile_id.startswith("snapshot-"):
            profile_id = profile_id[len('snapshot-'):]
        return _profile_registry.getProfileInfo(profile_id)

    security.declareProtected(ManagePortal, 'getDependenciesForProfile')
    def getDependenciesForProfile(self, profile_id):
        if profile_id.startswith("snapshot-"):
            return ()

        if not self.profileExists( profile_id ):
            raise KeyError, profile_id
        try:
            return self.getProfileInfo( profile_id ).get('dependencies', ())
        except KeyError:
            return ()


    security.declareProtected(ManagePortal, 'listProfilesWithUpgrades')
    def listProfilesWithUpgrades(self):
        return listProfilesWithUpgrades()

    security.declarePrivate('_massageUpgradeInfo')
    def _massageUpgradeInfo(self, info):
        """Add a couple of data points to the upgrade info dictionary.
        """
        info = info.copy()
        info['haspath'] = info['source'] and info['dest']
        info['ssource'] = '.'.join(info['source'] or ('all',))
        info['sdest'] = '.'.join(info['dest'] or ('all',))
        return info

    security.declareProtected(ManagePortal, 'listUpgrades')
    def listUpgrades(self, profile_id, show_old=False):
        """Get the list of available upgrades.
        """
        if show_old:
            source = None
        else:
            source = self.getLastVersionForProfile(profile_id)
        upgrades = listUpgradeSteps(self, profile_id, source)
        res = []
        for info in upgrades:
            if type(info) == list:
                subset = []
                for subinfo in info:
                    subset.append(self._massageUpgradeInfo(subinfo))
                res.append(subset)
            else:
                res.append(self._massageUpgradeInfo(info))
        return res

    security.declareProtected(ManagePortal, 'manage_doUpgrades')
    def manage_doUpgrades(self, request=None):
        """Perform all selected upgrade steps.
        """
        if request is None:
            request = self.REQUEST
        logger = logging.getLogger('GenericSetup')
        steps_to_run = request.form.get('upgrades', [])
        profile_id = request.get('profile_id', '')
        step = None
        for step_id in steps_to_run:
            step = _upgrade_registry.getUpgradeStep(profile_id, step_id)
            if step is not None:
                step.doStep(self)
                msg = "Ran upgrade step %s for profile %s" % (step.title,
                                                              profile_id)
                logger.log(logging.INFO, msg)

        # We update the profile version to the last one we have reached
        # with runnning an upgrade step.
        if step and step.dest is not None:
            self.setLastVersionForProfile(profile_id, step.dest)

        url = self.absolute_url()
        request.RESPONSE.redirect("%s/manage_upgrades?saved=%s" % (url, profile_id))

    #
    #   Helper methods
    #
    security.declarePrivate('_getImportContext')
    def _getImportContext(self, context_id, should_purge=None, archive=None):

        """ Crack ID and generate appropriate import context.
        """
        encoding = self.getEncoding()

        if context_id is not None:
            if context_id.startswith('profile-'):
                context_id = context_id[len('profile-'):]
                info = _profile_registry.getProfileInfo(context_id)

                if info.get('product'):
                    path = os.path.join(_getProductPath(info['product'])
                                       , info['path'])
                else:
                    path = info['path']
                if should_purge is None:
                    should_purge = (info.get('type') != EXTENSION)
                return DirectoryImportContext(self, path, should_purge, encoding)

            elif context_id.startswith('snapshot-'):
                context_id = context_id[len('snapshot-'):]
                if should_purge is None:
                    should_purge = True
                return SnapshotImportContext(self, context_id, should_purge, encoding)

        if archive is not None:
            return TarballImportContext(tool=self,
                                       archive_bits=archive,
                                       encoding='UTF8',
                                       should_purge=should_purge,
                                      )

        raise KeyError, 'Unknown context "%s"' % context_id

    security.declarePrivate('_updateImportStepsRegistry')
    def _updateImportStepsRegistry(self, context, encoding):

        """ Update our import steps registry from our profile.
        """
        if context is None:
            context = self._getImportContext(self._import_context_id)
        xml = context.readDataFile(IMPORT_STEPS_XML)
        if xml is None:
            return

        info_list = self._import_registry.parseXML(xml, encoding)

        for step_info in info_list:

            id = step_info['id']
            version = step_info['version']
            handler = step_info['handler']
            dependencies = tuple(step_info.get('dependencies', ()))
            title = step_info.get('title', id)
            description = ''.join(step_info.get('description', []))

            self._import_registry.registerStep(id=id,
                                               version=version,
                                               handler=handler,
                                               dependencies=dependencies,
                                               title=title,
                                               description=description,
                                              )

    security.declarePrivate('_updateExportStepsRegistry')
    def _updateExportStepsRegistry(self, context, encoding):

        """ Update our export steps registry from our profile.
        """
        if context is None:
            context = self._getImportContext(self._import_context_id)
        xml = context.readDataFile(EXPORT_STEPS_XML)
        if xml is None:
            return

        info_list = self._export_registry.parseXML(xml, encoding)

        for step_info in info_list:

            id = step_info['id']
            handler = step_info['handler']
            title = step_info.get('title', id)
            description = ''.join(step_info.get('description', []))

            self._export_registry.registerStep(id=id,
                                               handler=handler,
                                               title=title,
                                               description=description,
                                              )

    security.declarePrivate('_doRunImportStep')
    def _doRunImportStep(self, step_id, context):

        """ Run a single import step, using a pre-built context.
        """
        __traceback_info__ = step_id
        marker = object()

        handler = self.getImportStep(step_id)

        if handler is marker:
            raise ValueError('Invalid import step: %s' % step_id)

        if handler is None:
            msg = 'Step %s has an invalid import handler' % step_id
            logger = logging.getLogger('GenericSetup')
            logger.error(msg)
            return 'ERROR: ' + msg

        return handler(context)

    security.declarePrivate('_doRunExportSteps')
    def _doRunExportSteps(self, steps):

        """ See ISetupTool.
        """
        context = TarballExportContext(self)
        messages = {}
        marker = object()

        for step_id in steps:

            handler = self.getExportStep(step_id, marker)

            if handler is marker:
                raise ValueError('Invalid export step: %s' % step_id)

            if handler is None:
                msg = 'Step %s has an invalid import handler' % step_id
                logger = logging.getLogger('GenericSetup')
                logger.error(msg)
                messages[step_id] = msg
            else:
                messages[step_id] = handler(context)

        return { 'steps' : steps
               , 'messages' : messages
               , 'tarball' : context.getArchive()
               , 'filename' : context.getArchiveFilename()
               }


    security.declareProtected(ManagePortal, 'getProfileDependencyChain')
    def getProfileDependencyChain(self, profile_id, seen=None):
        if seen is None:
            seen = set()
        elif profile_id in seen:
            return [] # cycle break
        seen.add( profile_id )
        chain = []

        dependencies = self.getDependenciesForProfile( profile_id )
        for dependency in dependencies:
            chain.extend(self.getProfileDependencyChain( dependency, seen ))

        chain.append(profile_id)

        return chain


    security.declarePrivate('_runImportStepsFromContext')
    def _runImportStepsFromContext(self,
                                   steps=None,
                                   purge_old=None,
                                   profile_id=None,
                                   archive=None,
                                   ignore_dependencies=False,
                                   seen=None):

        if profile_id is not None and not ignore_dependencies:
            try: 
                chain = self.getProfileDependencyChain( profile_id )
            except KeyError, e:
                logger = logging.getLogger('GenericSetup')
                logger.error('Unknown step in dependency chain: %s' % str(e))
                raise
        else:
Beispiel #23
0
class PasswordResetTool(SimpleItem):
    meta_type = 'LDAP Password Reset Tool'
    security = ClassSecurityInfo()
    icon = '++resource++be.ldapadmin-www/eionet_password_reset_tool.gif'
    session_messages = SESSION_MESSAGES

    manage_options = (
        {
            'label': 'Configure',
            'action': 'manage_edit'
        },
        {
            'label': 'View',
            'action': ''
        },
    ) + SimpleItem.manage_options

    _render_template = TemplateRenderer(CommonTemplateLogic)

    def __init__(self, config={}):
        super(PasswordResetTool, self).__init__()
        self._config = PersistentMapping(config)
        self._tokens = PersistentMapping()

    security.declareProtected(view_management_screens, 'get_config')

    def get_config(self):
        return dict(self._config)

    security.declareProtected(view_management_screens, 'manage_edit')
    manage_edit = PageTemplateFile('zpt/pwreset_manage_edit', globals())
    manage_edit.ldap_config_edit_macro = ldap_config.edit_macro

    security.declareProtected(view_management_screens, 'manage_edit_save')

    def manage_edit_save(self, REQUEST):
        """ save changes to configuration """
        form = REQUEST.form
        new_config = ldap_config.read_form(form, edit=True)

        new_config['legacy_ldap_server'] = form.get('legacy_ldap_server', '')
        new_config['legacy_admin_dn'] = form.get('legacy_admin_dn', '')
        new_config['legacy_admin_pw'] = form.get('legacy_admin_pw', '')
        if not new_config['legacy_admin_pw']:
            del new_config['legacy_admin_pw']  # don't overwrite

        self._config.update(new_config)
        REQUEST.RESPONSE.redirect(self.absolute_url() + '/manage_edit')

    def _get_ldap_agent(self, bind=True, secondary=False):
        return ldap_config._get_ldap_agent(self, bind, secondary)

    def _predefined_filters(self):
        return sorted(self.objectValues([query.Query.meta_type]),
                      key=lambda ob: ob.getId())

    security.declareProtected(view, 'index_html')

    def index_html(self, REQUEST):
        """ view """
        email = REQUEST.get('email', '')
        options = {'email': email}
        return self._render_template('zpt/pwreset_index.zpt', **options)

    def _new_token(self, user_id):
        token = random_token()
        self._tokens[token] = TokenData(user_id, datetime.utcnow())
        return token

    def _send_token_email(self, addr_to, token, user_info):
        addr_from = ADDR_FROM
        email_template = load_template('zpt/pwreset_token_email.zpt')
        expiration_time = datetime.utcnow() + timedelta(days=1)
        options = {
            'token_url': self.absolute_url() + "/confirm_email?token=" + token,
            'user_info': user_info,
            'context': self,
            'network_name': NETWORK_NAME,
            'expiration_time': expiration_time.strftime("%Y-%m-%d %H:%M:%S")
        }
        print(options['token_url'])
        message = _create_plain_message(
            email_template(**options).encode('utf-8'))
        message['From'] = addr_from
        message['To'] = addr_to
        message['Subject'] = "%s account password recovery" % NETWORK_NAME

        try:
            mailer = getUtility(IMailDelivery, name="Mail")
            mailer.send(addr_from, [addr_to], message.as_string())
        except ComponentLookupError:
            mailer = getUtility(IMailDelivery, name="naaya-mail-delivery")
            try:
                mailer.send(addr_from, [addr_to], message.as_string())
            except (ValueError, AssertionError):
                mailer.send(addr_from, [addr_to], message)

    security.declareProtected(view, 'ask_for_password_reset')

    def ask_for_password_reset(self,
                               REQUEST=None,
                               email=None,
                               on_create=False):
        """ view """
        if REQUEST is None:
            REQUEST = self.REQUEST
        if not email:
            email = REQUEST.form['email']

        agent = self._get_ldap_agent()
        users = agent.search_user_by_email(email)  # , no_disabled=True)

        if users:
            # some people have multiple accounts; send mail for each account.
            for user_info in users:
                if user_info['status'] == 'disabled':
                    msg = "This email: %s belongs to a disabled account" % \
                        user_info['email']
                    _set_session_message(REQUEST, 'error', msg)
                    location = (self.absolute_url() +
                                '/messages_html?msg=email-disabled')
                else:
                    token = self._new_token(user_info['id'])
                    log.info(
                        "Sending password recovery email to user %r at %r.",
                        user_info['id'], email)
                    self._send_token_email(email, token, user_info)

                    location = (self.absolute_url() +
                                '/messages_html?msg=email-sent')

        else:
            log.info("Requested password recovery with invalid email %r.",
                     email)
            msg = "Email address not found in database."
            _set_session_message(REQUEST, 'error', msg)
            location = self.absolute_url() + '/'

        if REQUEST and not on_create:
            REQUEST.RESPONSE.redirect(location)

    security.declareProtected(view, 'messages_html')

    def messages_html(self, REQUEST):
        """ view """
        options = {
            'message-name': REQUEST.form['msg'],
        }
        return self._render_template('zpt/pwreset_message.zpt', **options)

    def _say_token_expired(self, REQUEST):
        msg = ("Password reset link is invalid, perhaps it has "
               "expired. Please try again.")
        _set_session_message(REQUEST, 'error', msg)
        location = self.absolute_url() + '/'
        REQUEST.RESPONSE.redirect(location)

    def _expire_tokens(self):
        expired = []
        cutoff_time = datetime.utcnow() - timedelta(days=1)
        for token, token_data in self._tokens.iteritems():
            if token_data.timestamp < cutoff_time:
                expired.append(token)
        for token in expired:
            log.info('Token %r expired.', token)
            del self._tokens[token]

    security.declareProtected(view, 'confirm_email')

    def confirm_email(self, REQUEST):
        """ view """

        token = REQUEST.form['token']
        self._expire_tokens()
        token_data = self._tokens.get(token, None)

        if token_data is None:
            return self._say_token_expired(REQUEST)

        options = {
            'token': token,
            'user_id': token_data.user_id,
        }
        return self._render_template('zpt/pwreset_new_password.zpt', **options)

    def reset_password(self, REQUEST):
        """ view """

        token = REQUEST.form['token']
        self._expire_tokens()
        token_data = self._tokens.get(token, None)

        if token_data is None:
            return self._say_token_expired(REQUEST)

        new_password = REQUEST.form['password']
        if new_password != REQUEST.form['password-confirm']:
            _set_session_message(REQUEST, 'error', "Passwords do not match.")
            location = self.absolute_url() + '/confirm_email?token=' + token

        else:
            log.info("Restting password for user %r with token %r",
                     token_data.user_id, token)
            agent = self._get_ldap_agent(bind=True)
            try:
                agent.set_user_password(token_data.user_id, None, new_password)
            except CONSTRAINT_VIOLATION as e:
                if e.message['info'] in [
                        'Password fails quality checking policy'
                ]:
                    try:
                        defaultppolicy = agent.conn.search_s(
                            'cn=defaultppolicy,ou=pwpolicies,o=EIONET,'
                            'l=Europe', SCOPE_BASE)
                        p_length = defaultppolicy[0][1]['pwdMinLength'][0]
                        message = '%s (min. %s characters)' % (
                            e.message['info'], p_length)
                    except NO_SUCH_OBJECT:
                        message = e.message['info']
                else:
                    message = e.message['info']
                _set_session_message(REQUEST, 'error', message)
                location = (self.absolute_url() + '/confirm_email?token=' +
                            token)
            else:
                del self._tokens[token]
                location = (self.absolute_url() +
                            '/messages_html?msg=password-reset')

        REQUEST.RESPONSE.redirect(location)

    security.declareProtected(view, 'can_edit_users')

    def can_edit_users(self):
        user = self.REQUEST.AUTHENTICATED_USER
        return bool(user.has_permission(ldap_edit_users, self))
Beispiel #24
0
    security.declareProtected(view, 'index_html')

    def index_html(self, REQUEST=None, RESPONSE=None):
        """ """
        return self.getFormsTool().getContent({'here': self}, 'youtube_index')

    security.declareProtected(PERMISSION_EDIT_OBJECTS, 'edit_html')

    def edit_html(self, REQUEST=None, RESPONSE=None):
        """ """
        return self.getFormsTool().getContent({'here': self}, 'youtube_edit')


InitializeClass(NyYoutube)

manage_addNyYoutube_html = PageTemplateFile('zpt/youtube_manage_add',
                                            globals())
manage_addNyYoutube_html.kind = config['meta_type']
manage_addNyYoutube_html.action = 'addNyYoutube'
config.update({
    'constructors': (manage_addNyYoutube_html, addNyYoutube),
    'folder_constructors': [
        ('manage_addNyYoutube_html', manage_addNyYoutube_html),
        ('youtube_add_html', youtube_add_html),
        ('addNyYoutube', addNyYoutube),
    ],
    'add_method':
    addNyYoutube,
    'validation':
    issubclass(NyYoutube, NyValidation),
    '_class':
    NyYoutube,
Beispiel #25
0
#Python imports

#Zope imports
from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from AccessControl.Permissions import view_management_screens, view
import Products
from OFS.Folder import Folder
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
from Products.PageTemplates.PageTemplateFile import PageTemplateFile

#Product imports
from Products.NaayaCore.constants import *
from managers.portlets_templates import *

manage_addPortlet_html = PageTemplateFile('zpt/portlet_manage_add', globals())


def addPortlet(self, id='', title='', portlettype='0', REQUEST=None):
    """ """
    id = self.utCleanupId(id)
    if not id: id = PREFIX_PORTLET + self.utGenRandomId(6)
    content_type = 'text/html'
    try:
        portlettype = abs(int(portlettype))
    except:
        portlettype = 0
    body = PORTLETS_BODIES.get(portlettype, 0)
    ob = Portlet(id, title, body, content_type, portlettype)
    self._setObject(id, ob)
    if REQUEST:
Beispiel #26
0
class NyYoutube(Implicit, NyContentData, NyAttributes, NyItem,
                NyNonCheckControl, NyValidation, NyContentType):
    """ """

    implements(INyYoutube)

    meta_type = config['meta_type']
    meta_label = config['label']

    icon = 'misc_/NaayaContent/NyYoutube.png'
    icon_marked = 'misc_/NaayaContent/NyYoutube_marked.png'

    manage_options = (
        {
            'label': 'Properties',
            'action': 'manage_edit_html'
        },
        {
            'label': 'View',
            'action': 'index_html'
        },
    ) + NyItem.manage_options

    security = ClassSecurityInfo()

    def __init__(self, id, contributor):
        """ """
        self.id = id
        NyValidation.__dict__['__init__'](self)
        NyItem.__dict__['__init__'](self)
        self.contributor = contributor

    # zmi actions
    security.declareProtected(view_management_screens, 'manageProperties')

    def manageProperties(self, REQUEST=None, **kwargs):
        """ """
        if not self.checkPermissionEditObject():
            raise EXCEPTION_NOTAUTHORIZED(EXCEPTION_NOTAUTHORIZED_MSG)

        if REQUEST is not None:
            schema_raw_data = dict(REQUEST.form)
        else:
            schema_raw_data = kwargs
        _lang = schema_raw_data.pop('_lang', schema_raw_data.pop('lang', None))
        _releasedate = self.process_releasedate(
            schema_raw_data.pop('releasedate', ''), self.releasedate)
        _approved = int(bool(schema_raw_data.pop('approved', False)))

        if schema_raw_data['iframe_width'] in ['', '0']:
            schema_raw_data['iframe_width'] = 640
        if schema_raw_data['iframe_height'] in ['', '0']:
            schema_raw_data['iframe_height'] = 360

        if len(schema_raw_data['youtube_id']) > 11:
            try:
                schema_raw_data['youtube_id'] = schema_raw_data[
                    'youtube_id'].split('watch?v=')[1][:11]
            except IndexError:
                schema_raw_data['youtube_id'] = schema_raw_data[
                    'youtube_id'].split('&v=')[1][:11]

        form_errors = self.process_submitted_form(
            schema_raw_data, _lang, _override_releasedate=_releasedate)
        try:
            schema_raw_data['iframe_width'] = int(
                schema_raw_data['iframe_width'])
        except ValueError:
            form_errors['iframe_width'] = ['Integer value required.']
        try:
            schema_raw_data['iframe_height'] = int(
                schema_raw_data['iframe_height'])
        except ValueError:
            form_errors['iframe_height'] = ['Integer value required.']
        if not schema_raw_data['youtube_id']:
            form_errors['youtube_id'] = ['Youtube Id is mandatory']

        if schema_raw_data['youtube_id']:
            yt_service = YouTubeService()
            try:
                yt_service.GetYouTubeVideoEntry(
                    video_id=schema_raw_data['youtube_id'])
            except RequestError:
                form_errors['youtube_id'] = [
                    'Invalid Youtube ID (inexisting video)'
                ]

        if form_errors:
            raise ValueError(form_errors.popitem()[1])  # pick a random error

        if _approved != self.approved:
            if _approved == 0:
                _approved_by = None
            else:
                _approved_by = self.REQUEST.AUTHENTICATED_USER.getUserName()
            self.approveThis(_approved, _approved_by)
        self._p_changed = 1
        if self.discussion:
            self.open_for_comments()
        else:
            self.close_for_comments()
        self.recatalogNyObject(self)
        if REQUEST:
            REQUEST.RESPONSE.redirect('manage_edit_html?save=ok')

    security.declareProtected(PERMISSION_EDIT_OBJECTS, 'saveProperties')

    def saveProperties(self, REQUEST=None, **kwargs):
        """ """
        if not self.checkPermissionEditObject():
            raise EXCEPTION_NOTAUTHORIZED(EXCEPTION_NOTAUTHORIZED_MSG)

        if REQUEST is not None:
            schema_raw_data = dict(REQUEST.form)
        else:
            schema_raw_data = kwargs
        _lang = schema_raw_data.pop('_lang', schema_raw_data.pop('lang', None))
        _releasedate = self.process_releasedate(
            schema_raw_data.pop('releasedate', ''), self.releasedate)

        if schema_raw_data['iframe_width'] in ['', '0']:
            schema_raw_data['iframe_width'] = 640
        if schema_raw_data['iframe_height'] in ['', '0']:
            schema_raw_data['iframe_height'] = 360

        if len(schema_raw_data['youtube_id']) > 11:
            try:
                schema_raw_data['youtube_id'] = schema_raw_data[
                    'youtube_id'].split('watch?v=')[1][:11]
            except IndexError:
                schema_raw_data['youtube_id'] = schema_raw_data[
                    'youtube_id'].split('&v=')[1][:11]

        form_errors = self.process_submitted_form(
            schema_raw_data, _lang, _override_releasedate=_releasedate)

        try:
            schema_raw_data['iframe_width'] = int(
                schema_raw_data['iframe_width'])
        except ValueError:
            form_errors['iframe_width'] = ['Integer value required.']
        try:
            schema_raw_data['iframe_height'] = int(
                schema_raw_data['iframe_height'])
        except ValueError:
            form_errors['iframe_height'] = ['Integer value required.']
        if not schema_raw_data['youtube_id']:
            form_errors['youtube_id'] = ['Youtube Id is mandatory']

        if schema_raw_data['youtube_id']:
            yt_service = YouTubeService()
            try:
                yt_service.GetYouTubeVideoEntry(
                    video_id=schema_raw_data['youtube_id'])
            except RequestError:
                form_errors['youtube_id'] = [
                    'Invalid Youtube ID (inexisting video)'
                ]

        if not form_errors:
            if self.discussion:
                self.open_for_comments()
            else:
                self.close_for_comments()
            self._p_changed = 1
            self.recatalogNyObject(self)
            # log date
            contributor = self.REQUEST.AUTHENTICATED_USER.getUserName()
            auth_tool = self.getAuthenticationTool()
            auth_tool.changeLastPost(contributor)
            notify(NyContentObjectEditEvent(self, contributor))
            if REQUEST:
                self.setSessionInfoTrans(MESSAGE_SAVEDCHANGES,
                                         date=self.utGetTodayDate())
                REQUEST.RESPONSE.redirect('%s/edit_html?lang=%s' %
                                          (self.absolute_url(), _lang))
        else:
            if REQUEST is not None:
                self._prepare_error_response(REQUEST, form_errors,
                                             schema_raw_data)
                REQUEST.RESPONSE.redirect('%s/edit_html?lang=%s' %
                                          (self.absolute_url(), _lang))
            else:
                raise ValueError(form_errors.popitem()[1])  # pick an error

    # zmi pages
    security.declareProtected(view_management_screens, 'manage_edit_html')
    manage_edit_html = PageTemplateFile('zpt/youtube_manage_edit', globals())

    # site pages
    security.declareProtected(view, 'index_html')

    def index_html(self, REQUEST=None, RESPONSE=None):
        """ """
        return self.getFormsTool().getContent({'here': self}, 'youtube_index')

    security.declareProtected(PERMISSION_EDIT_OBJECTS, 'edit_html')

    def edit_html(self, REQUEST=None, RESPONSE=None):
        """ """
        return self.getFormsTool().getContent({'here': self}, 'youtube_edit')
logger = logging.getLogger('RhaptosRepository')


def cmpTitle(x, y):
    """A method to provide a comparison between the titles of two record objects.
    Uses the sortTitle attribute if available; Title otherwise. Does case-less comparison.
    Returns a 'cmp' compatible value, suitable for use in a 'sort'.
    """
    return int(
        cmp(x.sortTitle and x.sortTitle.lower() or x.Title.lower(),
            y.sortTitle and y.sortTitle.lower() or y.Title.lower()))


manage_addRepositoryForm = PageTemplateFile(
    'zpt/manage_addRepositoryForm',
    globals(),
    __name__='manage_addRepositoryForm')


def manage_addRepository(self, id, title='', REQUEST=None):
    ''' '''

    id = str(id)
    self = self.this()

    self._setObject(id, Repository(id, title))

    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect(self.absolute_url() + '/manage_main')

Beispiel #28
0
from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from OFS.Folder import Folder
from Products.PageTemplates.PageTemplateFile import PageTemplateFile

from Products.NaayaCore.constants import *
import Scheme
import Template
import Style
import DiskFile
import DiskTemplate

manage_addSkinForm = PageTemplateFile('zpt/skin_add', globals())


def manage_addSkin(self, id='', title='', content=None, REQUEST=None):
    """ """
    if content is None or content == '':
        ob = Skin(id, title)
        self._setObject(id, ob)
        if content == '':
            #create default empty templates
            self._getOb(id).createSkinFiles()
    else:
        self.manage_clone(self._getOb(content), id)
        ob = self._getOb(id)
        ob.title = title
        ob._p_changed = 1
    if REQUEST is not None:
        return self.manage_main(self, REQUEST, update_menu=1)
from Products.PluggableAuthService.utils import classImplements
from Products.PluggableAuthService.utils import csrf_only

LOG = logging.getLogger('PluggableAuthService')


class MultiplePrincipalError(Exception):
    pass


class IZODBRoleManager(Interface):
    """ Marker interface.
    """


manage_addZODBRoleManagerForm = PageTemplateFile(
    'www/zrAdd', globals(), __name__='manage_addZODBRoleManagerForm')


def addZODBRoleManager(dispatcher, id, title=None, REQUEST=None):
    """ Add a ZODBRoleManager to a Pluggable Auth Service. """

    zum = ZODBRoleManager(id, title)
    dispatcher._setObject(zum.getId(), zum)

    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect('%s/manage_workspace'
                                     '?manage_tabs_message='
                                     'ZODBRoleManager+added.' %
                                     dispatcher.absolute_url())

Beispiel #30
0
    manage_options = (PropertyManager.manage_options +
                      SimpleItem.manage_options)

    _properties = ({
        'id': 'find_script',
        'mode': 'w',
        'type': 'string',
        'label': 'Script that finds available elements',
    }, )

    def findAvailableElements(self, slot):
        if not self.find_script:
            return None
        tool = aq_parent(aq_inner(aq_parent(aq_inner(self))))
        s = tool.restrictedTraverse(self.find_script)
        return s(slot)


addSlotClassForm = PageTemplateFile("addSlotClassForm", _www)


def manage_addSlotClass(dispatcher, id, REQUEST=None):
    """Adds a slot class to a composite tool.
    """
    ob = SlotClass()
    ob._setId(id)
    dispatcher._setObject(ob.getId(), ob)
    if REQUEST is not None:
        return dispatcher.manage_main(dispatcher, REQUEST)