Example #1
0
 def __init__(self, id, title, file, permissions=None, categories=None):
     self.id=id
     self.title=title
     file,ext=os.path.splitext(file)
     prefix,file=os.path.split(file)
     self.index_html=DTMLFile(file,prefix)
     if permissions is not None:
         self.permissions=permissions
     if categories is not None:
         self.categories=categories
Example #2
0
class DTMLTopic(HelpTopic):
    """
    A basic Help Topic. Holds a HTMLFile object.
    """
    def __init__(self, id, title, file, permissions=None, categories=None):
        self.id=id
        self.title=title
        file,ext=os.path.splitext(file)
        prefix,file=os.path.split(file)
        self.index_html=DTMLFile(file,prefix)
        if permissions is not None:
            self.permissions=permissions
        if categories is not None:
            self.categories=categories

    def SearchableText(self):
        "The full text of the Help Topic, for indexing purposes"
        return '%s %s' % (self.title, self.index_html.read())
Example #3
0
class MemberDataTool (UniqueObject, SimpleItem, PropertyManager, ActionProviderBase):
    '''This tool wraps user objects, making them act as Member objects.
    '''
    id = 'portal_memberdata'
    meta_type = 'CMF Member Data Tool'
    _actions = []
    _v_temps = None
    _properties = ()

    security = ClassSecurityInfo()

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

    #
    #   ZMI methods
    #
    security.declareProtected( CMFCorePermissions.ManagePortal
                             , 'manage_overview' )
    manage_overview = DTMLFile( 'explainMemberDataTool', _dtmldir )

    security.declareProtected( CMFCorePermissions.ViewManagementScreens
                             , 'manage_showContents')
    manage_showContents = DTMLFile('memberdataContents', _dtmldir )

    security.declareProtected( CMFCorePermissions.ViewManagementScreens
                             , 'getContentsInformation',)


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

    #
    #   'portal_memberdata' interface methods
    #
    security.declarePrivate('listActions')
    def listActions(self, info=None):
        """
        Return actions provided via tool.
        """
        return self._actions

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

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

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

    security.declarePrivate( 'searchMemberDataContents' )
    def searchMemberDataContents( self, search_param, search_term ):
        """ Search members """
        res = []

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

        for user_wrapper in self._members.values():
            searched = getattr( user_wrapper, search_param, None )
            if searched is not None and string.find( searched, search_term ) != -1:
                res.append( { 'username' : getattr( user_wrapper, 'id' )
                            , 'email' : getattr( user_wrapper, 'email', '' )
                            }
                          )

        return res

    security.declarePrivate('pruneMemberDataContents')
    def pruneMemberDataContents(self):
        '''
        Compare the user IDs stored in the member data
        tool with the list in the actual underlying acl_users
        and delete anything not in acl_users
        '''
        membertool= getToolByName(self, 'portal_membership')
        members   = self._members
        user_list = membertool.listMemberIds()

        for tuple in members.items():
            member_name = tuple[0]
            member_obj  = tuple[1]
            if member_name not in user_list:
                del members[member_name]

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

    security.declarePrivate('registerMemberData')
    def registerMemberData(self, m, id):
        '''
        Adds the given member data to the _members dict.
        This is done as late as possible to avoid side effect
        transactions and to reduce the necessary number of
        entries.
        '''
        self._members[id] = m
Example #4
0
class RegistrationTool(BaseTool):
    """ Manage through-the-web signup policies.
    """

    __implements__ = BaseTool.__implements__

    meta_type = 'Default Registration Tool'
    _actions = (ActionInformation(
        id='join',
        title='Join',
        description='Click here to Join',
        action=Expression(text='string:${portal_url}/join_form'),
        permissions=(AddPortalMember, ),
        category='user',
        condition=Expression(text='not: member'),
        visible=1), )

    security = ClassSecurityInfo()

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

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

    #
    #   'portal_registration' interface
    #
    security.declarePublic('testPasswordValidity')

    def testPasswordValidity(self, password, confirm=None):
        """ Verify that the password satisfies the portal's requirements.

        o If the password is valid, return None.
        o If not, return a string explaining why.
        """
        if len(password) < 5 and not _checkPermission('Manage portal', self):
            return 'Your password must contain at least 5 characters.'

        if confirm is not None and confirm != password:
            return ('Your password and confirmation did not match. ' +
                    'Please try again.')

        return None

    security.declarePublic('testPropertiesValidity')

    def testPropertiesValidity(self, props, member=None):
        """ Verify that the properties supplied satisfy portal's requirements.

        o If the properties are valid, return None.
        o If not, return a string explaining why.
        """
        if member is None:  # New member.

            username = props.get('username', '')
            if not username:
                return 'You must enter a valid name.'

            if not self.isMemberIdAllowed(username):
                return ('The login name you selected is already '
                        'in use or is not valid. Please choose another.')

            email = props.get('email')
            if email is None:
                return 'You must enter an email address.'

            ok, message = _checkEmail(email)
            if not ok:
                return 'You must enter a valid email address.'

        else:  # Existing member.
            email = props.get('email')

            if email is not None:

                ok, message = _checkEmail(email)
                if not ok:
                    return 'You must enter a valid email address.'

            # Not allowed to clear an existing non-empty email.
            existing = member.getProperty('email')

            if existing and email == '':
                return 'You must enter a valid email address.'

        return None

    security.declarePublic('mailPassword')

    def mailPassword(self, forgotten_userid, REQUEST):
        """ Email a forgotten password to a member.

        o Raise an exception if user ID is not found.
        """
        membership = getToolByName(self, 'portal_membership')
        member = membership.getMemberById(forgotten_userid)

        if member is None:
            raise 'NotFound', 'The username you entered could not be found.'

        # assert that we can actually get an email address, otherwise
        # the template will be made with a blank To:, this is bad
        if not member.getProperty('email'):
            raise 'ValueError', 'That user does not have an email address.'

        check, msg = _checkEmail(member.getProperty('email'))
        if not check:
            raise 'ValueError', msg

        # Rather than have the template try to use the mailhost, we will
        # render the message ourselves and send it from here (where we
        # don't need to worry about 'UseMailHost' permissions).
        mail_text = self.mail_password_template(self,
                                                REQUEST,
                                                member=member,
                                                password=member.getPassword())

        host = self.MailHost
        host.send(mail_text)

        return self.mail_password_response(self, REQUEST)

    security.declarePublic('registeredNotify')

    def registeredNotify(self, new_member_id):
        """ Handle mailing the registration / welcome message.
        """
        membership = getToolByName(self, 'portal_membership')
        member = membership.getMemberById(new_member_id)

        if member is None:
            raise 'NotFound', 'The username you entered could not be found.'

        password = member.getPassword()
        email = member.getProperty('email')

        if email is None:
            raise ValueError('Member %s has no e-mail address!' %
                             new_member_id)

        check, msg = _checkEmail(email)
        if not check:
            raise 'ValueError', msg

        # Rather than have the template try to use the mailhost, we will
        # render the message ourselves and send it from here (where we
        # don't need to worry about 'UseMailHost' permissions).
        mail_text = self.registered_notify_template(self,
                                                    self.REQUEST,
                                                    member=member,
                                                    password=password,
                                                    email=email)

        host = self.MailHost
        host.send(mail_text)

        return self.mail_password_response(self, self.REQUEST)

    security.declareProtected(ManagePortal, 'editMember')

    def editMember(self,
                   member_id,
                   properties=None,
                   password=None,
                   roles=None,
                   domains=None):
        """ Edit a user's properties and security settings

        o Checks should be done before this method is called using
          testPropertiesValidity and testPasswordValidity
        """

        mtool = getToolByName(self, 'portal_membership')
        member = mtool.getMemberById(member_id)
        member.setMemberProperties(properties)
        member.setSecurityProfile(password, roles, domains)

        return member
Example #5
0
    """
    invoked by whatever Object manager to create a Redirect challenge
    plugin.
    """

    # set object on the object manager.
    self._setObject(id, RedirectChallenge(id, title, path))

    if REQUEST:
        REQUEST['RESPONSE'].redirect("%s/manage_workspace" %
                                     self.absolute_url(),
                                     lock=1)


# the simplest form for create a new RedirectChallenge instance.
manage_addRedirectChallengeForm = DTMLFile('../zmi/redirect', globals())


# a very simple challenge plugin for testing.
class RedirectChallenge(BasePlugin):
    """
    A simple challenge plugin to redirect un-authenticated user to a
    static URL.
    """

    # meta_type will be displayed in the add dropdown list on folder
    # acl_users
    meta_type = "iScorpio PAS Simple Redirect Challenge"

    # this will help to manage the properties on Properties tab.
    _properties = ({
from Products.ZenUtils.Utils import unused
from Products.ZenUtils.tbdetail import log_tb


def manage_addToManyContRelationship(context, id, REQUEST=None):
    """factory for ToManyRelationship"""
    rel = ToManyContRelationship(id)
    context._setObject(rel.id, rel)
    if REQUEST:
        REQUEST['RESPONSE'].redirect(context.absolute_url_path() +
                                     '/manage_main')
    return rel.id


addToManyContRelationship = DTMLFile('dtml/addToManyContRelationship',
                                     globals())


class ToManyContRelationship(ToManyRelationshipBase):
    """
    ToManyContRelationship is the ToMany side of a realtionship that
    contains its related objects (like the normal Zope ObjectManager)
    """

    meta_type = "ToManyContRelationship"

    security = ClassSecurityInfo()

    def __init__(self, id):
        """set our instance values"""
        self.id = id
Example #7
0
class DateRangeIndex(UnIndex):
    """Index for date ranges, such as the "effective-expiration" range in CMF.

    Any object may return None for either the start or the end date: for the
    start date, this should be the logical equivalent of "since the beginning
    of time"; for the end date, "until the end of time".

    Therefore, divide the space of indexed objects into four containers:

    - Objects which always match (i.e., they returned None for both);

    - Objects which match after a given time (i.e., they returned None for the
      end date);

    - Objects which match until a given time (i.e., they returned None for the
      start date);

    - Objects which match only during a specific interval.
    """

    __implements__ = UnIndex.__implements__
    implements(IDateRangeIndex)

    security = ClassSecurityInfo()

    meta_type = "DateRangeIndex"

    manage_options = ({
        'label': 'Properties',
        'action': 'manage_indexProperties'
    }, )

    query_options = ['query']

    since_field = until_field = None

    def __init__(self,
                 id,
                 since_field=None,
                 until_field=None,
                 caller=None,
                 extra=None):

        if extra:
            since_field = extra.since_field
            until_field = extra.until_field

        self._setId(id)
        self._edit(since_field, until_field)
        self.clear()

    security.declareProtected(VIEW_PERMISSION, 'getSinceField')

    def getSinceField(self):
        """Get the name of the attribute indexed as start date.
        """
        return self._since_field

    security.declareProtected(VIEW_PERMISSION, 'getUntilField')

    def getUntilField(self):
        """Get the name of the attribute indexed as end date.
        """
        return self._until_field

    manage_indexProperties = DTMLFile('manageDateRangeIndex', _dtmldir)

    security.declareProtected(INDEX_MGMT_PERMISSION, 'manage_edit')

    def manage_edit(self, since_field, until_field, REQUEST):
        """
        """
        self._edit(since_field, until_field)
        REQUEST['RESPONSE'].redirect('%s/manage_main'
                                     '?manage_tabs_message=Updated' %
                                     REQUEST.get('URL2'))

    security.declarePrivate('_edit')

    def _edit(self, since_field, until_field):
        """
            Update the fields used to compute the range.
        """
        self._since_field = since_field
        self._until_field = until_field

    security.declareProtected(INDEX_MGMT_PERMISSION, 'clear')

    def clear(self):
        """
            Start over fresh.
        """
        self._always = IITreeSet()
        self._since_only = IOBTree()
        self._until_only = IOBTree()
        self._since = IOBTree()
        self._until = IOBTree()
        self._unindex = IOBTree()  # 'datum' will be a tuple of date ints
        self._length = BTrees.Length.Length()

    #
    #   PluggableIndexInterface implementation (XXX inherit assertions?)
    #
    def getEntryForObject(self, documentId, default=None):
        """
            Get all information contained for the specific object
            identified by 'documentId'.  Return 'default' if not found.
        """
        return self._unindex.get(documentId, default)

    def index_object(self, documentId, obj, threshold=None):
        """
            Index an object:

             - 'documentId' is the integer ID of the document

             - 'obj' is the object to be indexed

             - ignore threshold
        """
        if self._since_field is None:
            return 0

        since = getattr(obj, self._since_field, None)
        if safe_callable(since):
            since = since()
        since = self._convertDateTime(since)

        until = getattr(obj, self._until_field, None)
        if safe_callable(until):
            until = until()
        until = self._convertDateTime(until)

        datum = (since, until)

        old_datum = self._unindex.get(documentId, None)
        if datum == old_datum:  # No change?  bail out!
            return 0

        if old_datum is not None:
            old_since, old_until = old_datum
            self._removeForwardIndexEntry(old_since, old_until, documentId)

        self._insertForwardIndexEntry(since, until, documentId)
        self._unindex[documentId] = datum

        return 1

    def unindex_object(self, documentId):
        """
            Remove the object corresponding to 'documentId' from the index.
        """
        datum = self._unindex.get(documentId, None)

        if datum is None:
            return

        since, until = datum

        self._removeForwardIndexEntry(since, until, documentId)
        del self._unindex[documentId]

    def uniqueValues(self, name=None, withLengths=0):
        """
            Return a list of unique values for 'name'.

            If 'withLengths' is true, return a sequence of tuples, in
            the form '( value, length )'.
        """
        if not name in (self._since_field, self._until_field):
            return []

        if name == self._since_field:

            t1 = self._since
            t2 = self._since_only

        else:

            t1 = self._until
            t2 = self._until_only

        result = []
        IntType = type(0)

        if not withLengths:

            result.extend(t1.keys())
            result.extend(t2.keys())

        else:

            for key in t1.keys():
                set = t1[key]
                if type(set) is IntType:
                    length = 1
                else:
                    length = len(set)
                result.append((key, length))

            for key in t2.keys():
                set = t2[key]
                if type(set) is IntType:
                    length = 1
                else:
                    length = len(set)
                result.append((key, length))

        return tuple(result)

    def _apply_index(self, request, cid=''):
        """
            Apply the index to query parameters given in 'request', which
            should be a mapping object.

            If the request does not contain the needed parametrs, then
            return None.

            If the request contains a parameter with the name of the
            column + "_usage", snif for information on how to handle
            applying the index.

            Otherwise return two objects.  The first object is a ResultSet
            containing the record numbers of the matching records.  The
            second object is a tuple containing the names of all data fields
            used.
        """
        record = parseIndexRequest(request, self.getId())
        if record.keys is None:
            return None

        term = self._convertDateTime(record.keys[0])

        #
        #   Aggregate sets for each bucket separately, to avoid
        #   large-small union penalties.
        #
        #until_only  = IISet()
        #map( until_only.update, self._until_only.values( term ) )
        # XXX use multi-union
        until_only = multiunion(self._until_only.values(term))

        #since_only  = IISet()
        #map( since_only.update, self._since_only.values( None, term ) )
        # XXX use multi-union
        since_only = multiunion(self._since_only.values(None, term))

        #until       = IISet()
        #map( until.update, self._until.values( term ) )
        # XXX use multi-union
        until = multiunion(self._until.values(term))

        #since       = IISet()
        #map( since.update, self._since.values( None, term ) )
        # XXX use multi-union
        since = multiunion(self._since.values(None, term))

        bounded = intersection(until, since)

        #   Merge from smallest to largest.
        #result      = union( self._always, until_only )
        result = union(bounded, until_only)
        result = union(result, since_only)
        #result      = union( result, bounded )
        result = union(result, self._always)

        return result, (self._since_field, self._until_field)

    #
    #   ZCatalog needs this, although it isn't (yet) part of the interface.
    #
    security.declareProtected(VIEW_PERMISSION, 'numObjects')

    def numObjects(self):
        """ """
        return len(self._unindex)

    def indexSize(self):
        """ """
        return len(self)

    #
    #   Helper functions.
    #
    def _insertForwardIndexEntry(self, since, until, documentId):
        """
            Insert 'documentId' into the appropriate set based on
            'datum'.
        """
        if since is None and until is None:

            self._always.insert(documentId)

        elif since is None:

            set = self._until_only.get(until, None)
            if set is None:
                set = self._until_only[until] = IISet()  # XXX: Store an int?
            set.insert(documentId)

        elif until is None:

            set = self._since_only.get(since, None)
            if set is None:
                set = self._since_only[since] = IISet()  # XXX: Store an int?
            set.insert(documentId)

        else:

            set = self._since.get(since, None)
            if set is None:
                set = self._since[since] = IISet()  # XXX: Store an int?
            set.insert(documentId)

            set = self._until.get(until, None)
            if set is None:
                set = self._until[until] = IISet()  # XXX: Store an int?
            set.insert(documentId)

    def _removeForwardIndexEntry(self, since, until, documentId):
        """
            Remove 'documentId' from the appropriate set based on
            'datum'.
        """
        if since is None and until is None:

            self._always.remove(documentId)

        elif since is None:

            set = self._until_only.get(until, None)
            if set is not None:

                set.remove(documentId)

                if not set:
                    del self._until_only[until]

        elif until is None:

            set = self._since_only.get(since, None)
            if set is not None:

                set.remove(documentId)

                if not set:
                    del self._since_only[since]

        else:

            set = self._since.get(since, None)
            if set is not None:
                set.remove(documentId)

                if not set:
                    del self._since[since]

            set = self._until.get(until, None)
            if set is not None:
                set.remove(documentId)

                if not set:
                    del self._until[until]

    def _convertDateTime(self, value):
        if value is None:
            return value
        if type(value) == type(''):
            dt_obj = DateTime(value)
            value = dt_obj.millis() / 1000 / 60  # flatten to minutes
        if isinstance(value, DateTime):
            value = value.millis() / 1000 / 60  # flatten to minutes
        result = int(value)
        if isinstance(result, long):  # this won't work (Python 2.3)
            raise OverflowError('%s is not within the range of dates allowed'
                                'by a DateRangeIndex' % value)
        return result
Example #8
0
class AdminNews(SimpleItem, PropertyManager):
    """
	A Blend Admin News object
	"""

    meta_type = "Blend Admin News"

    manage_options = ((
        {
            'label': 'Edit',
            'action': 'manage_main',
        },
        {
            'label': 'View',
            'action': 'manage_view',
        },
        {
            'label': 'CMS Edit',
            'action': 'adminNewsEditCMS',
        },
    ) + PropertyManager.manage_options + SimpleItem.manage_options)

    def __init__(self, id, title, data, author, active, tags, created):
        "initialize a new instance of a Blend Admin News"
        self.id = id  #required
        self.title = title
        self.author = author
        self.data = data
        self.active = active
        self.tags = tags
        self.tags = tags.strip()
        self.tags = tags.capitalize()
        self.created = created

    def manage_editSaveAction(self,
                              title,
                              data,
                              author,
                              active,
                              tags,
                              created,
                              RESPONSE=None):
        "Edit CMS Admin News object property values"
        self.title = title
        self.data = data
        self.author = author
        self.active = active
        self.tags = tags
        self.tags = tags.strip()
        self.tags = tags.capitalize()
        self.created = created
        self._p_changed = 1
        RESPONSE.redirect('adminNewsEditCMS')

    def manage_editZMI(self, title, author, data, created, RESPONSE=None):
        "Edit CMS Admin News product property values"
        self.title = title
        self.author = author
        self.data = data
        self.created = created
        self._p_changed = 1
        RESPONSE.redirect('manage_main')

    index_html = DTMLFile('dtml/indexAdminNews', globals())
    cms_edit_header = DTMLFile('dtml/edit_cms_header', globals())
    cms_header = DTMLFile('dtml/standard_cms_header', globals())
    cms_footer = DTMLFile('dtml/standard_cms_footer', globals())
    news_header = DTMLFile('dtml/news_cms_header', globals())
    site_header = DTMLFile('dtml/standard_html_header', globals())
    site_footer = DTMLFile('dtml/standard_html_footer', globals())
    manage_main = DTMLFile('dtml/manage_editAdminNews', globals())
    adminNewsEditCMS = DTMLFile('dtml/manage_editAdminNewsCMS', globals())
    checkActive = DTMLFile('dtml/manage_adminNewscheckActive', globals())
    delete = DTMLFile('dtml/manage_deleteAdminNews', globals())
class ZenPropertyManager(object, PropertyManager):
    """
    ZenPropertyManager adds keyedselection type to PropertyManager.
    A keyedselection displays a different name in the popup than
    the actual value the popup will have.

    It also has management for zenProperties which are properties that can be
    inherited long the acquision chain.  All properties are for a branch are
    defined on a "root node" specified by the function which must be returned
    by the function getZenRootNode that should be over ridden in a sub class.
    Prperties can then be added further "down" the aq_chain by calling
    setZenProperty on any contained node.

    ZenProperties all have the same prefix which is defined by iszprop
    this can be overridden in a subclass.

    ZenPropertyManager overrides getProperty and getPropertyType from
    PropertyManager to support acquisition. If you want to query an object
    about a property, but do not want it to search the acquistion chain then
    use the super classes method or aq_base.  Example:

        # acquires property from dmd.Devices
        dmd.Devices.Server.getProperty('zCollectorPlugins')

        # does not acquire property from dmd.Devices
        PropertyManager.getProperty(dmd.Devices.Server, 'zCollectorPlugins')

        # also does not acquire property from dmd.Devices
        aq_base(dmd.Devices.Server).getProperty('zSnmpCommunity')

    The properties are stored as attributes which is convenient, but can be
    confusing.  Attribute access always uses acquistion.  Setting an
    attribute, will not add it to the list of properties, so subsquent calls
    to hasProperty or getProperty won't return it.

    Property Transformers are stored at dmd.propertyTransformers and transform
    the property based on type during calls to the _setProperty,
    _updateProperty, and getProperty methods. Adding a property using
    _setProperty applies the appropriate transformer and adds its value as an
    attribute, but when you access it as an attribute the property transformer
    is again applied, but this time using its transformForGet method.
    """

    security = ClassSecurityInfo()

    manage_propertiesForm = DTMLFile('dtml/properties',
                                     globals(),
                                     property_extensible_schema__=1)

    def _setPropValue(self, id, value):
        """Override from PerpertyManager to handle checks and ip creation.
        """
        self._wrapperCheck(value)
        propType = self.getPropertyType(id)
        if propType == 'keyedselection':
            value = int(value)
        if not getattr(self, '_v_propdict', False):
            self._v_propdict = self.propdict()
        if 'setter' in self._v_propdict:
            settername = self._v_propdict['setter']
            setter = getattr(aq_base(self), settername, None)
            if not setter:
                raise ValueError("setter %s for property %s doesn't exist" %
                                 (settername, id))
            if not callable(setter):
                raise TypeError("setter %s for property %s not callable" %
                                (settername, id))
            setter(value)
        else:
            setattr(self, id, value)

    def _setProperty(self,
                     id,
                     value,
                     type='string',
                     label=None,
                     visible=True,
                     setter=None,
                     description=None):
        """For selection and multiple selection properties the value
        argument indicates the select variable of the property.
        """
        self._wrapperCheck(value)
        if not self.valid_property_id(id):
            raise BadRequest('Id %s is invalid or duplicate' % id)

        def setprops(**pschema):
            if setter:
                pschema['setter'] = setter
            if label:
                pschema['label'] = label
            if description:
                pschema['description'] = description
            self._properties = self._properties + (pschema, )

        if type in ('selection', 'multiple selection'):

            # NOTE: Moved `import messaging` here to lazify code and
            # remove circular import.
            from Products.ZenWidgets import messaging

            if not hasattr(self, value):
                IMessageSender(self).sendToBrowser(
                    "Selection variable '%s' not found" % value,
                    priority=messaging.WARNING,
                )
                return

            # NOTE: When creating selection properties, specify the name of
            # another property as the Value. This property should return a list
            # of strings will be used to provide choices for the selection.
            select_values = getattr(self, value)
            if not (isinstance(select_values, (list, tuple))
                    and all(isinstance(v, basestring) for v in select_values)):
                IMessageSender(self).sendToBrowser(
                    "Selection variable '%s' must be a LINES type" % value,
                    priority=messaging.WARNING,
                )
                return

            setprops(id=id, type=type, visible=visible, select_variable=value)
            self._setPropValue(id, '' if (type == 'selection') else [])
        else:
            setprops(id=id, type=type, visible=visible)
            self._setPropValue(id, value)

    _onlystars = re.compile("^\*+$").search

    def _updateProperty(self, id, value):
        """This method sets a property on a zope object. It overrides the
        method in PropertyManager. If Zope is upgraded you will need to check
        that this method has not changed! It is overridden so that we can catch
        the ValueError returned from the field2* converters in the class
        Converters.py
        """
        try:
            # Do not update property if its a password
            # and value is secured(equals to all asterisk)
            if self.zenPropIsPassword(id) and self._onlystars(value):
                return
            super(ZenPropertyManager, self)._updateProperty(id, value)
        except ValueError:
            proptype = self.getPropertyType(id)
            log.error(
                "Error Saving Property '%s'. New value '%s' is of invalid "
                "type. It should be type '%s'.", id, value, proptype)

    security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'manage_editProperties')

    def manage_editProperties(self, REQUEST):
        """Edit object properties via the web.
        The purpose of this method is to change all property values,
        even those not listed in REQUEST; otherwise checkboxes that
        get turned off will be ignored.  Use manage_changeProperties()
        instead for most situations.
        """
        for prop in self._propertyMap():
            name = prop['id']
            if 'w' in prop.get('mode', 'wd'):
                value = REQUEST.get(name, '')
                if self.zenPropIsPassword(name) and self._onlystars(value):
                    continue
                self._updateProperty(name, value)
        if getattr(self, "index_object", False):
            self.index_object()
        if REQUEST:
            return self.manage_propertiesForm(
                self, REQUEST, manage_tabs_message="Saved changes.")

    def getZenRootNode(self):
        """Sub class must implement to use zenProperties.
        """
        raise NotImplementedError

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyIds')

    def zenPropertyIds(self, all=True, pfilt=iszprop):
        """Return list of device tree property names.
        If all use list from property root node.
        """
        if all:
            rootnode = self.getZenRootNode()
        else:
            if self.id == self.dmdRootName:
                return []
            rootnode = aq_base(self)
        return sorted(prop for prop in rootnode.propertyIds() if pfilt(prop))

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyItems')

    def zenPropertyItems(self):
        """Return list of (id, value) tuples of zenProperties.
        """
        return map(lambda x: (x, getattr(self, x)), self.zenPropertyIds())

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyMap')

    def zenPropertyMap(self, pfilt=iszprop):
        """Return property mapping of device tree properties.
        """
        rootnode = self.getZenRootNode()
        return sorted(
            (pdict for pdict in rootnode.propertyMap() if pfilt(pdict['id'])),
            key=lambda x: x['id'])

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyString')

    def zenPropertyString(self, id):
        """Return the value of a device tree property as a string.
        """
        def displayLines(lines):
            return '\n'.join(str(line) for line in lines)

        def displayPassword(password):
            return '*' * len(password)

        def displayOthers(other):
            return other

        displayFunctions = {'lines': displayLines, 'password': displayPassword}
        display = displayFunctions.get(self.getPropertyType(id), displayOthers)
        return display(self.getProperty(id, ''))

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropIsPassword')

    def zenPropIsPassword(self, id):
        """Is this field a password field.
        """
        passwordTypes = [
            'password', 'passwd', 'multilinecredentials', 'instancecredentials'
        ]
        return self.getPropertyType(id) in passwordTypes

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyPath')

    def zenPropertyPath(self, id):
        """Return the primaryId of where a device tree property is found.
        """
        ob = self._findParentWithProperty(id)
        if ob is None:
            path = None
        else:
            path = ob.getPrimaryId(self.getZenRootNode().getId())
        return path

    security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'setZenProperty')

    def setZenProperty(self, propname, propvalue, REQUEST=None):
        """Add or set the propvalue of the property propname on this node of
        the device Class tree.
        """
        ptype = self.getPropertyType(propname)
        if ptype == 'lines':
            dedupedList = []
            for x in propvalue:
                if x not in dedupedList:
                    dedupedList.append(x)
            propvalue = dedupedList
        if getattr(aq_base(self), propname, zenmarker) != zenmarker:
            self._updateProperty(propname, propvalue)
        else:
            if ptype in ("selection", 'multiple selection'):
                ptype = "string"
            if ptype in type_converters:
                propvalue = type_converters[ptype](propvalue)
            if ptype == "password" \
                    and propvalue == self.zenPropertyString(propname):
                # Don't save passwords that haven't changed
                # and don't save "*" passwords
                pass
            elif getattr(self, propname, None) != propvalue:
                self._setProperty(propname, propvalue, type=ptype)
        if REQUEST:
            return self.callZenScreen(REQUEST)

    security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'saveZenProperties')

    def saveZenProperties(self, pfilt=iszprop, REQUEST=None):
        """Save all ZenProperties found in the REQUEST.form object.
        """
        oldValues = {}
        newValues = {}
        maskFields = []
        for name, value in REQUEST.form.items():
            if pfilt(name):
                if self.zenPropIsPassword(name):
                    maskFields.append(name)
                    if self._onlystars(value):
                        continue
                oldValues[name] = self.getProperty(name)
                if name == 'zCollectorPlugins':
                    if tuple(getattr(self, name, ())) != tuple(value):
                        self.setZenProperty(name, value)
                else:
                    self.setZenProperty(name, value)
                newValues[name] = self.getProperty(name)

        if REQUEST:
            audit(('UI', getDisplayType(self), 'EditProperties'),
                  self,
                  data_=newValues,
                  oldData_=oldValues,
                  maskFields_=maskFields)
            IMessageSender(self).sendToBrowser(
                'Configuration Propeties Updated',
                'Configuration properties have been updated.')

        return self.callZenScreen(REQUEST)

    security.declareProtected(ZEN_ZPROPERTIES_EDIT, 'deleteZenProperty')

    def deleteZenProperty(self, propname=None, REQUEST=None):
        """
        Delete device tree properties from the this DeviceClass object.
        """
        if propname:
            try:
                self._delProperty(propname)
            except AttributeError:
                # Occasional object corruption where the propName is in
                # _properties but not set as an attribute. filter out the prop
                # and create a new _properties tuple
                newProps = [x for x in self._properties if x['id'] != propname]
                self._properties = tuple(newProps)
            except ValueError:
                raise ZenPropertyDoesNotExist()
        if REQUEST:
            if propname:
                audit(('UI', getDisplayType(self), 'DeleteZProperty'),
                      self,
                      property=propname)
            return self.callZenScreen(REQUEST)

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'zenPropertyOptions')

    def zenPropertyOptions(self, propname):
        """Provide a set of default options for a ZProperty.
        """
        unused(propname)
        return []

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'isLocal')

    def isLocal(self, propname):
        """Check to see if a name is local to our current context.
        """
        v = getattr(aq_base(self), propname, zenmarker)
        return v != zenmarker

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getOverriddenObjects')

    def getOverriddenObjects(self, propname, showDevices=False):
        """Get the objects that override a property somewhere below in the tree
        """
        if showDevices:
            objects = []
            for inst in self.getSubInstances('devices'):
                if inst.isLocal(propname) and inst not in objects:
                    objects.append(inst)
            for suborg in self.children():
                if suborg.isLocal(propname):
                    objects.append(suborg)
                for inst in suborg.getOverriddenObjects(propname, showDevices):
                    if inst not in objects:
                        objects.append(inst)
            return objects
        return [
            org for org in self.getSubOrganizers() if org.isLocal(propname)
        ]

    def _findParentWithProperty(self, id):
        """Returns self or the first acquisition parent that has a property
        with the id.  Returns None if no parent had the id.
        """
        return next(
            (ob for ob in aq_chain(self)
             if isinstance(ob, ZenPropertyManager) and ob.hasProperty(id)),
            None)

    def hasProperty(self, id, useAcquisition=False):
        """Override method in PropertyManager to support acquisition.
        """
        if useAcquisition:
            hasProp = self._findParentWithProperty(id) is not None
        else:
            hasProp = PropertyManager.hasProperty(self, id)
        return hasProp

    def getProperty(self, id, d=None):
        """Get property value and apply transformer.  Overrides method in
        Zope's PropertyManager class.  Acquire values from aquisiton parents
        if needed.
        """
        ob = self._findParentWithProperty(id)
        return d if (ob is None) else PropertyManager.getProperty(ob, id, d)

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getPropertyType')

    def getPropertyType(self, id):
        """Overrides methods from PropertyManager to support acquistion.
        """
        ob = self._findParentWithProperty(id)
        if ob is not None:
            return PropertyManager.getPropertyType(ob, id)

    security.declareProtected(ZEN_ZPROPERTIES_VIEW, 'getZ')

    def getZ(self, id, default=None):
        """Return the value of a zProperty on this object.  This method is
        used to lookup zProperties for a user with a role that doesn't have
        direct access to an attribute further up the acquisition path.  If the
        requested property is a password, then None is returned.

        @param id: id of zProperty
        @type id: string
        @return: Value of zProperty
        @permission: ZEN_ZPROPERTIES_VIEW

        >>> dmd.Devices.getZ('zSnmpPort')
        161
        >>> dmd.Devices.getZ('zSnmpAuthPassword')
        >>>
        """
        if self.hasProperty(id, useAcquisition=True) \
                and not self.zenPropIsPassword(id):
            return self.getProperty(id)
        return default

    def exportZProperties(self, exclusionList=()):
        """
        @param exclusionList: list of zproperties we do not want to export
        @type exclusionList: collection
        For this manager will return the following about each zProperty
        Will return the following about each Zen Property
        - id - identifier
        - islocal - if this object has a local definition
        - value - value for this object
        - valueAsString - string representation of the property
        - type - int string lines etc
        - path - where it is defined
        - options - acceptable values of this zProperty
        """
        props = []
        root = self.getDmdRoot(self.dmdRootName)
        for zId in self.zenPropertyIds():
            if zId in exclusionList:
                continue
            prop = self.exportZProperty(zId, root)
            if not self.zenPropIsPassword(zId):
                prop['value'] = self.getZ(zId)
            else:
                prop['value'] = self.zenPropertyString(zId)

            # look up the description and label from the root
            props.append(prop)

        return props

    def exportZProperty(self, zId, root=None):
        if not root:
            root = self.getDmdRoot(self.dmdRootName)
        return dict(id=zId,
                    islocal=self.hasProperty(zId),
                    type=self.getPropertyType(zId),
                    path=self.zenPropertyPath(zId),
                    options=self.zenPropertyOptions(zId),
                    category=getzPropertyCategory(zId),
                    value=None,
                    valueAsString=self.zenPropertyString(zId),
                    label=root.propertyLabel(zId),
                    description=root.propertyDescription(zId))
Example #10
0
class DiscussionTool(UniqueObject, SimpleItem, ActionProviderBase):

    __implements__ = (IOldstyleDiscussionTool,
                      ActionProviderBase.__implements__)

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

    security = ClassSecurityInfo()

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

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLFile('explainDiscussionTool', _dtmldir)

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

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

    security.declarePublic('isDiscussionAllowedFor')

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

    security.declarePrivate('listActions')

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

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

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

        return actions
Example #11
0
from DeviceOrganizer import DeviceOrganizer
from ZenPackable import ZenPackable


def manage_addSystem(context, id, description=None, REQUEST=None):
    """make a System"""
    d = System(id, description)
    context._setObject(id, d)

    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect(context.absolute_url_path() +
                                     '/manage_main')


addSystem = DTMLFile('dtml/addSystem', globals())


class System(DeviceOrganizer, ZenPackable):
    """
    System class is a device organizer that represents a business system.
    May need to manage "services" as well so that more sophisticated 
    dependencies can be tracked.
    """

    # Organizer configuration
    dmdRootName = "Systems"

    portal_type = meta_type = 'System'

    event_key = "System"
Example #12
0
class CatalogTool(UniqueObject, ZCatalog, ActionProviderBase):
    """ This is a ZCatalog that filters catalog queries.
    """

    __implements__ = (ICatalogTool, ActionProviderBase.__implements__)

    id = 'portal_catalog'
    meta_type = 'CMF Catalog'
    _actions = ()

    security = ClassSecurityInfo()

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

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

        if not hasattr(self, 'Vocabulary'):
            # As of 2.6, the Catalog no longer adds a vocabulary in itself
            from Products.PluginIndexes.TextIndex.Vocabulary import Vocabulary
            vocabulary = Vocabulary('Vocabulary', 'Vocabulary', globbing=1)
            self._setObject('Vocabulary', vocabulary)

        self._initIndexes()

    #
    #   Subclass extension interface
    #
    security.declarePublic('enumerateIndexes')  # Subclass can call

    def enumerateIndexes(self):
        #   Return a list of ( index_name, type ) pairs for the initial
        #   index set.
        #   id is depricated and may go away, use getId!
        return (('Title', 'TextIndex'), ('Subject', 'KeywordIndex'),
                ('Description', 'TextIndex'), ('Creator', 'FieldIndex'),
                ('SearchableText', 'TextIndex'), ('Date', 'FieldIndex'),
                ('Type', 'FieldIndex'), ('created', 'FieldIndex'),
                ('effective', 'FieldIndex'), ('expires', 'FieldIndex'),
                ('modified', 'FieldIndex'), ('allowedRolesAndUsers',
                                             'KeywordIndex'),
                ('review_state', 'FieldIndex'), ('in_reply_to', 'FieldIndex'),
                ('meta_type', 'FieldIndex'), ('id', 'FieldIndex'),
                ('getId', 'FieldIndex'), ('path', 'PathIndex'), ('portal_type',
                                                                 'FieldIndex'))

    security.declarePublic('enumerateColumns')

    def enumerateColumns(self):
        #   Return a sequence of schema names to be cached.
        #   id is depricated and may go away, use getId!
        return ('Subject', 'Title', 'Description', 'Type', 'review_state',
                'Creator', 'Date', 'getIcon', 'created', 'effective',
                'expires', 'modified', 'CreationDate', 'EffectiveDate',
                'ExpiresDate', 'ModificationDate', 'id', 'getId',
                'portal_type')

    def _initIndexes(self):
        base = aq_base(self)
        if hasattr(base, 'addIndex'):
            # Zope 2.4
            addIndex = self.addIndex
        else:
            # Zope 2.3 and below
            addIndex = self._catalog.addIndex
        if hasattr(base, 'addColumn'):
            # Zope 2.4
            addColumn = self.addColumn
        else:
            # Zope 2.3 and below
            addColumn = self._catalog.addColumn

        # Content indexes
        self._catalog.indexes.clear()
        for index_name, index_type in self.enumerateIndexes():
            addIndex(index_name, index_type)

        # Cached metadata
        self._catalog.names = ()
        self._catalog.schema.clear()
        for column_name in self.enumerateColumns():
            addColumn(column_name)

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLFile('explainCatalogTool', _dtmldir)

    #
    #   'portal_catalog' interface methods
    #

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

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

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

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

            self._convertQuery(kw)

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

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

    __call__ = searchResults

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

    manage_catalogFind = DTMLFile('catalogFind', _dtmldir)

    def catalog_object(self, object, uid, idxs=[]):
        # Wraps the object with workflow and accessibility
        # information just before cataloging.
        wf = getattr(self, 'portal_workflow', None)
        if wf is not None:
            vars = wf.getCatalogVariablesFor(object)
        else:
            vars = {}
        w = IndexableObjectWrapper(vars, object)
        ZCatalog.catalog_object(self, w, uid, idxs)

    security.declarePrivate('indexObject')

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

    security.declarePrivate('unindexObject')

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

    security.declarePrivate('reindexObject')

    def reindexObject(self, object, idxs=[]):
        '''Update catalog after object data has changed.
        The optional idxs argument is a list of specific indexes
        to update (all of them by default).
        '''
        url = self.__url(object)
        if idxs != []:
            # Filter out invalid indexes.
            valid_indexes = self._catalog.indexes.keys()
            idxs = [i for i in idxs if i in valid_indexes]
        self.catalog_object(object, url, idxs=idxs)
Example #13
0
class TopicIndex(Persistent, SimpleItem):
    """A TopicIndex maintains a set of FilteredSet objects.

    Every FilteredSet object consists of an expression and and IISet with all
    Ids of indexed objects that eval with this expression to 1.
    """

    __implements__ = (PluggableIndex.PluggableIndexInterface, )
    implements(ITopicIndex, IPluggableIndex)

    meta_type = "TopicIndex"
    query_options = ('query', 'operator')

    manage_options = ({
        'label': 'FilteredSets',
        'action': 'manage_main',
        'help': ('TopicIndex', 'TopicIndex_searchResults.stx')
    }, )

    def __init__(self, id, caller=None):
        self.id = id
        self.filteredSets = OOBTree()
        self.operators = ('or', 'and')
        self.defaultOperator = 'or'

    def getId(self):
        return self.id

    def clear(self):
        for fs in self.filteredSets.values():
            fs.clear()

    def index_object(self, docid, obj, threshold=100):
        """ hook for (Z)Catalog """
        for fid, filteredSet in self.filteredSets.items():
            filteredSet.index_object(docid, obj)
        return 1

    def unindex_object(self, docid):
        """ hook for (Z)Catalog """

        for fs in self.filteredSets.values():
            try:
                fs.unindex_object(docid)
            except KeyError:
                LOG.debug('Attempt to unindex document'
                          ' with id %s failed' % docid)
        return 1

    def numObjects(self):
        return "n/a"

    def search(self, filter_id):
        if self.filteredSets.has_key(filter_id):
            return self.filteredSets[filter_id].getIds()

    def _apply_index(self, request, cid=''):
        """ hook for (Z)Catalog
            'request' --  mapping type (usually {"topic": "..." }
            'cid' -- ???
        """

        record = parseIndexRequest(request, self.id, self.query_options)
        if record.keys is None: return None

        operator = record.get('operator', self.defaultOperator).lower()
        if operator == 'or': set_func = union
        else: set_func = intersection

        res = None
        for filter_id in record.keys:
            rows = self.search(filter_id)
            res = set_func(res, rows)

        if res:
            return res, (self.id, )
        else:
            return IITreeSet(), (self.id, )

    def uniqueValues(self, name=None, withLength=0):
        """ needed to be consistent with the interface """
        return self.filteredSets.keys()

    def getEntryForObject(self, docid, default=_marker):
        """ Takes a document ID and returns all the information we have
            on that specific object.
        """
        return self.filteredSets.keys()

    def addFilteredSet(self, filter_id, typeFilteredSet, expr):
        # Add a FilteredSet object.
        if self.filteredSets.has_key(filter_id):
            raise KeyError,\
                'A FilteredSet with this name already exists: %s' % filter_id
        self.filteredSets[filter_id] = \
            FilteredSet.factory(filter_id, typeFilteredSet, expr)

    def delFilteredSet(self, filter_id):
        # Delete the FilteredSet object specified by 'filter_id'.
        if not self.filteredSets.has_key(filter_id):
            raise KeyError,\
                'no such FilteredSet:  %s' % filter_id
        del self.filteredSets[filter_id]

    def clearFilteredSet(self, filter_id):
        # Clear the FilteredSet object specified by 'filter_id'.
        if not self.filteredSets.has_key(filter_id):
            raise KeyError,\
                'no such FilteredSet:  %s' % filter_id
        self.filteredSets[filter_id].clear()

    def manage_addFilteredSet(self, filter_id, typeFilteredSet, expr, URL1, \
            REQUEST=None,RESPONSE=None):
        """ add a new filtered set """

        if len(filter_id) == 0: raise RuntimeError, 'Length of ID too short'
        if len(expr) == 0: raise RuntimeError, 'Length of expression too short'

        self.addFilteredSet(filter_id, typeFilteredSet, expr)

        if RESPONSE:
            RESPONSE.redirect(URL1 + '/manage_workspace?'
                              'manage_tabs_message=FilteredSet%20added')

    def manage_delFilteredSet(self, filter_ids=[], URL1=None, \
            REQUEST=None,RESPONSE=None):
        """ delete a list of FilteredSets"""

        for filter_id in filter_ids:
            self.delFilteredSet(filter_id)

        if RESPONSE:
            RESPONSE.redirect(URL1 + '/manage_workspace?'
                              'manage_tabs_message=FilteredSet(s)%20deleted')

    def manage_saveFilteredSet(self,filter_id, expr, URL1=None,\
            REQUEST=None,RESPONSE=None):
        """ save expression for a FilteredSet """

        self.filteredSets[filter_id].setExpression(expr)

        if RESPONSE:
            RESPONSE.redirect(URL1 + '/manage_workspace?'
                              'manage_tabs_message=FilteredSet(s)%20updated')

    def getIndexSourceNames(self):
        """ return names of indexed attributes """
        return ('n/a', )

    def manage_clearFilteredSet(self, filter_ids=[], URL1=None, \
            REQUEST=None,RESPONSE=None):
        """  clear a list of FilteredSets"""

        for filter_id in filter_ids:
            self.clearFilteredSet(filter_id)

        if RESPONSE:
            RESPONSE.redirect(URL1 + '/manage_workspace?'
                              'manage_tabs_message=FilteredSet(s)%20cleared')

    manage = manage_main = DTMLFile('dtml/manageTopicIndex', globals())
    manage_main._setName('manage_main')
    editFilteredSet = DTMLFile('dtml/editFilteredSet', globals())
Example #14
0
            RESPONSE.redirect(URL1 + '/manage_workspace?'
                              'manage_tabs_message=FilteredSet(s)%20updated')

    def getIndexSourceNames(self):
        """ return names of indexed attributes """
        return ('n/a', )

    def manage_clearFilteredSet(self, filter_ids=[], URL1=None, \
            REQUEST=None,RESPONSE=None):
        """  clear a list of FilteredSets"""

        for filter_id in filter_ids:
            self.clearFilteredSet(filter_id)

        if RESPONSE:
            RESPONSE.redirect(URL1 + '/manage_workspace?'
                              'manage_tabs_message=FilteredSet(s)%20cleared')

    manage = manage_main = DTMLFile('dtml/manageTopicIndex', globals())
    manage_main._setName('manage_main')
    editFilteredSet = DTMLFile('dtml/editFilteredSet', globals())


manage_addTopicIndexForm = DTMLFile('dtml/addTopicIndex', globals())


def manage_addTopicIndex(self, id, REQUEST=None, RESPONSE=None, URL3=None):
    """Add a TopicIndex"""
    return self.manage_addIndex(id, 'TopicIndex', extra=None, \
                REQUEST=REQUEST, RESPONSE=RESPONSE, URL1=URL3)
Example #15
0
class WorkflowTool(UniqueObject, Folder):
    """ Mediator tool, mapping workflow objects 
    """
    id = 'portal_workflow'
    meta_type = 'CMF Workflow Tool'
    __implements__ = portal_workflow

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

    security = ClassSecurityInfo()

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

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLFile('explainWorkflowTool', _dtmldir)

    if AUTO_MIGRATE_WORKFLOW_TOOLS:

        def __setstate__(self, state):
            # Adds default_workflow to persistent WorkflowTool instances.
            # This is temporary!
            WorkflowTool.inheritedAttribute('__setstate__')(self, state)
            if not self.__dict__.has_key('default_workflow'):
                try:
                    from Products.CMFDefault import DefaultWorkflow
                except ImportError:
                    pass
                else:
                    self.default_workflow = (
                        DefaultWorkflow.DefaultWorkflowDefinition(
                            'default_workflow'))
                    self._objects = self._objects + (
                        {
                            'id': 'default_workflow',
                            'meta_type': self.default_workflow.meta_type
                        }, )

    _manage_addWorkflowForm = DTMLFile('addWorkflow', _dtmldir)

    security.declareProtected(ManagePortal, 'manage_addWorkflowForm')

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

    security.declareProtected(ManagePortal, 'manage_addWorkflow')

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

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

    _manage_selectWorkflows = DTMLFile('selectWorkflows', _dtmldir)

    security.declareProtected(ManagePortal, 'manage_selectWorkflows')

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

    security.declareProtected(ManagePortal, 'manage_changeWorkflows')

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

    #
    #   portal_workflow implementation.
    #
    security.declarePrivate('getCatalogVariablesFor')

    def getCatalogVariablesFor(self, ob):
        """ Returns a mapping of the catalog variables that apply to ob.

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

    security.declarePrivate('listActions')

    def listActions(self, info):
        """ Returns a list of actions to be displayed to the user.

        o Invoked by the portal_actions tool.
        
        o Allows workflows to include actions to be displayed in the
          actions box.

        o Object actions are supplied by workflows that apply to the object.
        
        o Global actions are supplied by all workflows.
        """
        chain = self.getChainFor(info.content)
        did = {}
        actions = []
        for wf_id in chain:
            did[wf_id] = 1
            wf = self.getWorkflowById(wf_id)
            if wf is not None:
                a = wf.listObjectActions(info)
                if a is not None:
                    actions.extend(a)
                a = wf.listGlobalActions(info)
                if a is not None:
                    actions.extend(a)

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

    security.declarePublic('getActionsFor')

    def getActionsFor(self, ob):
        """ Return a list of action dictionaries for 'ob', just as though
            queried via 'ActionsTool.listFilteredActionsFor'.
        """
        return self.listActions(WorkflowInformation(ob))

    security.declarePublic('doActionFor')

    def doActionFor(self, ob, action, wf_id=None, *args, **kw):
        """ Execute the given workflow action for the object.
        
        o Invoked by user interface code.

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

    security.declarePublic('getInfoFor')

    def getInfoFor(self, ob, name, default=_marker, wf_id=None, *args, **kw):
        """ Return a given workflow-specific property for an object.
        
        o Invoked by user interface code.
        
        o Allows the user to request information provided by the workflow.
        
        o The workflow object must perform its own security checks.
        """
        if wf_id is None:
            wfs = self.getWorkflowsFor(ob)
            if wfs is None:
                if default is _marker:
                    raise WorkflowException('No workflows found.')
                else:
                    return default
            found = 0
            for wf in wfs:
                if wf.isInfoSupported(ob, name):
                    found = 1
                    break
            if not found:
                if default is _marker:
                    raise WorkflowException(
                        'No workflow provides "%s" information.' % name)
                else:
                    return default
        else:
            wf = self.getWorkflowById(wf_id)
            if wf is None:
                if default is _marker:
                    raise WorkflowException(
                        'Requested workflow definition not found.')
                else:
                    return default
        res = apply(wf.getInfoFor, (ob, name, default) + args, kw)
        if res is _marker:
            raise WorkflowException('Could not get info: %s' % name)
        return res

    security.declarePrivate('notifyCreated')

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

    security.declarePrivate('notifyBefore')

    def notifyBefore(self, ob, action):
        """ Notifies all applicable workflows of an action before it
            happens, allowing veto by exception.
            
        o Unless an exception is thrown, either a notifySuccess() or
          notifyException() can be expected later on.

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

    security.declarePrivate('notifySuccess')

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

    security.declarePrivate('notifyException')

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

    security.declarePrivate('getHistoryOf')

    def getHistoryOf(self, wf_id, ob):
        """ Return the history of an object.
        
        o Invoked by workflow definitions.
        """
        if hasattr(aq_base(ob), 'workflow_history'):
            wfh = ob.workflow_history
            return wfh.get(wf_id, None)
        return ()

    security.declarePrivate('getStatusOf')

    def getStatusOf(self, wf_id, ob):
        """ Return the last entry of a workflow history.

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

    security.declarePrivate('setStatusOf')

    def setStatusOf(self, wf_id, ob, status):
        """ Append an entry to the workflow history.

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

    #
    #   Administration methods
    #
    security.declareProtected(ManagePortal, 'setDefaultChain')

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

        self._default_chain = tuple(ids)

    security.declareProtected(ManagePortal, 'setChainForPortalTypes')

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

        if type(chain) is type(''):
            chain = map(lambda x: x.strip(), chain.split(','))

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

    security.declareProtected(ManagePortal, 'updateRoleMappings')

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

    security.declarePrivate('getWorkflowById')

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

    security.declarePrivate('getDefaultChainFor')

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

        return ()

    security.declarePrivate('getChainFor')

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

        if pt is None:
            return ()

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

    security.declarePrivate('getWorkflowIds')

    def getWorkflowIds(self):
        """ Return the list of workflow ids.
        """
        wf_ids = []

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

        return tuple(wf_ids)

    security.declareProtected(ManagePortal, 'getWorkflowsFor')

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

    security.declarePrivate('wrapWorkflowMethod')

    def wrapWorkflowMethod(self, ob, method_id, func, args, kw):
        """ To be invoked only by WorkflowCore.
            Allows a workflow definition to wrap a WorkflowMethod.
        """
        wf = None
        wfs = self.getWorkflowsFor(ob)
        if wfs:
            for w in wfs:
                if (hasattr(w, 'isWorkflowMethodSupported')
                        and w.isWorkflowMethodSupported(ob, method_id)):
                    wf = w
                    break
        else:
            wfs = ()
        if wf is None:
            # No workflow wraps this method.
            return apply(func, args, kw)
        return self._invokeWithNotification(wfs, ob, method_id,
                                            wf.wrapWorkflowMethod,
                                            (ob, method_id, func, args, kw),
                                            {})

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

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

    security.declarePrivate('_invokeWithNotification')

    def _invokeWithNotification(self, wfs, ob, action, func, args, kw):
        """ Private utility method:  call 'func', and deal with exceptions
            indicating that the object has been deleted or moved.
        """
        reindex = 1
        for w in wfs:
            w.notifyBefore(ob, action)
        try:
            res = apply(func, args, kw)
        except ObjectDeleted, ex:
            res = ex.getResult()
            reindex = 0
        except ObjectMoved, ex:
            res = ex.getResult()
            ob = ex.getNewObject()
from ZenModelRM import ZenModelRM

def manage_addServiceClass(context, id=None, REQUEST = None):
    """make a device class"""
    if id:
        sc = ServiceClass(id)
        context._setObject(id, sc)
        sc = context._getOb(id)
        sc.createCatalog()
        sc.buildZProperties()

    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect(context.absolute_url() + '/manage_main') 

addServiceClass = DTMLFile('dtml/addServiceClass',globals())

class ServiceClass(ZenModelRM, Commandable, ZenPackable):
    zope.interface.implements(IIndexed)
    meta_type = "ServiceClass"
    dmdRootName = "Services"
    default_catalog = "serviceSearch"

    name = ""
    serviceKeys = ()
    description = ""
    port = 0 #FIXME prevent failures when ServiceClass is added manually
    
    _properties = (
        {'id':'name', 'type':'string', 'mode':'w'},
        {'id':'serviceKeys', 'type':'lines', 'mode':'w'},
Example #17
0
    adminNewsEditCMS = DTMLFile('dtml/manage_editAdminNewsCMS', globals())
    checkActive = DTMLFile('dtml/manage_adminNewscheckActive', globals())
    delete = DTMLFile('dtml/manage_deleteAdminNews', globals())


#Constructor pages. Only used when the product is added to a folder.


def manage_addAdminNewsAction(self,
                              id,
                              title='',
                              data='',
                              author='',
                              active=0,
                              tags='',
                              created=DateTime().strftime('%Y/%m/%d'),
                              RESPONSE=None):
    "Add a Blend Admin News to a folder"
    id = id.lower()
    id = id.lstrip()
    id = id.rstrip()
    id = id.replace(' ', '_')
    self._setObject(id,
                    AdminNews(id, title, data, author, active, tags, created))
    RESPONSE.redirect('../../../adminNews_html')


manage_addAdminNews = DTMLFile('dtml/manage_addAdminNews', globals())

InitializeClass(AdminNews)
Example #18
0
class LockTool(UniqueObject, SimpleItemWithProperties):
    __doc__ = __doc__ # copy from module
    id = 'portal_lock'
    meta_type = 'Portal Lock Tool'

    security = ClassSecurityInfo()

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

    # With auto_version on, locking automatically causes a version checkout
    # and unlocking automatically causes a checkin.  This is one form
    # of autoversioning described in the DeltaV introduction.
    # http://www.webdav.org/deltav/WWW10/deltav-intro.htm
    auto_version = 1
    timeout_days = 14  # 2 weeks

    _properties = (
        {'id': 'auto_version', 'type': 'boolean', 'mode': 'w',
         'label': 'Auto checkout and checkin using portal_versions'},
        {'id': 'timeout_days', 'type': 'int', 'mode': 'w',
         'label': 'Lock timeout in days'},
        )

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview' )
    manage_overview = DTMLFile('explainLockTool', _wwwdir)

    #
    #   'LockTool' interface methods
    #

    security.declarePublic('lock')
    def lock(self, object):
        '''Locks an object'''
        if not _checkPermission(LockObjects, object):
            raise LockingError, 'Inadequate permissions to lock %s' % object
        locker = self.locker(object)
        if locker:
            raise LockingError, '%s is already locked' % pathOf(object)

        if self.auto_version:
            vt = getToolByName(self, 'portal_versions', None)
            if vt is not None:
                if (vt.isUnderVersionControl(object)
                    and not vt.isCheckedOut(object)):
                    object = vt.checkout(object)

        user = getSecurityManager().getUser()
        lockitem = LockItem(user, timeout=(self.timeout_days * 86400))
        object.wl_setLock(lockitem.getLockToken(), lockitem)


    security.declarePublic('breaklock')
    def breaklock(self, object, message=''):
        """emergency breaklock...."""
        locker = self.locker(object)
        if not _checkPermission(UnlockObjects, object):
            raise LockingError, ("You cannot unlock %s:  lock is held by %s" % 
                                 (pathOf(object), locker))
        object.wl_clearLocks()
        if self.auto_version:
            vt = getToolByName(self, 'portal_versions', None)
            if vt is not None:
                vt.checkin(object, message)

    security.declarePublic('unlock')
    def unlock(self, object, message=''):
        '''Unlocks an object'''
        if not _checkPermission(UnlockObjects, object):
            raise LockingError, "Inadequate permissions to unlock %s" % object

        locker = self.locker(object)
        if not locker:
            raise LockingError, ("Unlocking an unlocked item: %s" %
                                 pathOf(object))

        user = getSecurityManager().getUser()
        if user.getId() != locker:
            raise LockingError, ("Cannot unlock %s: lock is held by %s" %
                                 (pathOf(object), locker))

        # According to WriteLockInterface, we shouldn't call
        # wl_clearLocks(), but it seems like the right thing to do anyway.
        object.wl_clearLocks()

        if self.auto_version:
            vt = getToolByName(self, 'portal_versions', None)
            if vt is not None:
                vt.checkin(object, message)


    security.declarePublic('locker')
    def locker(self, object):
        '''Returns the locker of an object'''
        if not WriteLockInterface.isImplementedBy(object):
            raise LockingError, "%s is not lockable" % pathOf(object)

        values = object.wl_lockValues()
        if not values:
            return ''
        for lock in values:
            if lock.isValid():
                creator = lock.getCreator()
                if creator:
                    return creator[1]  # The user id without the path
        # All of the locks are expired or invalid
        return ''


    security.declarePublic('isLockedOut')
    def isLockedOut(self, object):
        '''Returns a true value if the current user is locked out.'''
        locker_id = self.locker(object)
        if locker_id:
            uid = getSecurityManager().getUser().getId()
            if uid != locker_id:
                return 1
        return 0


    security.declarePublic('locked')
    def locked(self, object):
        '''Returns true if an object is locked.

        Also accepts non-lockable objects, always returning 0.'''
        if not WriteLockInterface.isImplementedBy(object):
            return 0
        return not not self.locker(object)

    security.declarePublic('isLockable')
    def isLockable(self, object):
        """Return true if object supports locking, regardless of lock
           state or whether the current user can actually lock."""
        return WriteLockInterface.isImplementedBy(object)

    security.declarePublic('canLock')
    def canLock(self, object):
        """Returns true if the current user can lock the given object."""
        if self.locked(object):
            return 0
        if not WriteLockInterface.isImplementedBy(object):
            return 0
        if _checkPermission(LockObjects, object):
            return 1
        return 0


    security.declarePublic('canUnlock')
    def canUnlock(self, object):
        """Returns true if the current user can unlock the given object."""
        if not self.locked(object):
            return 0
        if self.isLockedOut(object):
            return 0
        if _checkPermission(UnlockObjects, object):
            return 1
        return 0


    security.declarePublic('canChange')
    def canChange(self, object):
        """Returns true if the current user can change the given object."""
        if not WriteLockInterface.isImplementedBy(object):
            if self.isLockedOut(object):
                return 0
        if not _checkPermission(ModifyPortalContent, object):
            return 0
        vt = getToolByName(self, 'portal_versions', None)
        if vt is not None:
            if (vt.isUnderVersionControl(object)
                and not vt.isCheckedOut(object)):
                return 0
        return 1
Example #19
0
            return value
        if type(value) == type(''):
            dt_obj = DateTime(value)
            value = dt_obj.millis() / 1000 / 60  # flatten to minutes
        if isinstance(value, DateTime):
            value = value.millis() / 1000 / 60  # flatten to minutes
        result = int(value)
        if isinstance(result, long):  # this won't work (Python 2.3)
            raise OverflowError('%s is not within the range of dates allowed'
                                'by a DateRangeIndex' % value)
        return result


InitializeClass(DateRangeIndex)

manage_addDateRangeIndexForm = DTMLFile('addDateRangeIndex', _dtmldir)


def manage_addDateRangeIndex(self,
                             id,
                             extra=None,
                             REQUEST=None,
                             RESPONSE=None,
                             URL3=None):
    """
        Add a date range index to the catalog, using the incredibly icky
        double-indirection-which-hides-NOTHING.
    """
    return self.manage_addIndex(id, 'DateRangeIndex', extra, REQUEST, RESPONSE,
                                URL3)
Example #20
0
__version__ = '$Revision: 1.52 $'[11:-2]
from Globals import Persistent, DTMLFile, MessageDialog, HTML
import OFS.SimpleItem, Acquisition
from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from AccessControl.Permissions import change_external_methods
from AccessControl.Permissions import view_management_screens
from AccessControl.Permissions import view as View
import AccessControl.Role, sys, os, stat, traceback
from OFS.SimpleItem import pretty_tb
from App.Extensions import getObject, getPath, FuncCode
from Globals import DevelopmentMode
from App.Management import Navigation
from ComputedAttribute import ComputedAttribute

manage_addExternalMethodForm = DTMLFile('dtml/methodAdd', globals())


def manage_addExternalMethod(self, id, title, module, function, REQUEST=None):
    """Add an external method to a folder

    Un addition to the standard object-creation arguments,
    'id' and title, the following arguments are defined:

        function -- The name of the python function. This can be a
          an ordinary Python function, or a bound method.

        module -- The name of the file containing the function
          definition.

        The module normally resides in the 'Extensions'
Example #21
0
class DiscussionTool(UniqueObject, SimpleItem):
    """ Links content to discussions.
    """

    implements(IDiscussionTool)

    id = 'portal_discussion'
    meta_type = 'Default Discussion Tool'

    security = ClassSecurityInfo()

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

    #
    #   ZMI methods
    #
    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLFile('explainDiscussionTool', _dtmldir)

    #
    #   'portal_discussion' interface methods
    #

    security.declarePublic('overrideDiscussionFor')

    def overrideDiscussionFor(self, content, allowDiscussion):
        """ Override discussability for the given object or clear the setting.
        """
        if not _checkPermission(ModifyPortalContent, content):
            raise AccessControl_Unauthorized

        if allowDiscussion is None or allowDiscussion == 'None':
            disc_flag = getattr(aq_base(content), 'allow_discussion', _marker)
            if disc_flag is not _marker:
                try:
                    del content.allow_discussion
                except AttributeError:
                    # https://bugs.launchpad.net/zope-cmf/+bug/162532
                    pass
        else:
            content.allow_discussion = bool(allowDiscussion)

    security.declarePublic('getDiscussionFor')

    def getDiscussionFor(self, content):
        """ Get DiscussionItemContainer for content, create it if necessary.
        """
        if not self.isDiscussionAllowedFor(content):
            raise DiscussionNotAllowed

        if not IDiscussionResponse.providedBy(content) and \
                getattr( aq_base(content), 'talkback', None ) is None:
            # Discussion Items use the DiscussionItemContainer object of the
            # related content item, so only create one for other content items
            self._createDiscussionFor(content)

        return content.talkback  # Return wrapped talkback

    security.declarePublic('isDiscussionAllowedFor')

    def isDiscussionAllowedFor(self, content):
        """ Get boolean indicating whether discussion is allowed for content.
        """
        if hasattr(aq_base(content), 'allow_discussion'):
            return bool(content.allow_discussion)
        typeInfo = content.getTypeInfo()
        if typeInfo:
            return bool(typeInfo.allowDiscussion())
        return False

    #
    #   Utility methods
    #
    security.declarePrivate('_createDiscussionFor')

    def _createDiscussionFor(self, content):
        """ Create DiscussionItemContainer for content, if allowed.
        """
        if not self.isDiscussionAllowedFor(content):
            raise DiscussionNotAllowed

        content.talkback = DiscussionItemContainer()
        return content.talkback
Example #22
0
class ExternalMethod(OFS.SimpleItem.Item, Persistent, Acquisition.Explicit,
                     AccessControl.Role.RoleManager, Navigation):
    """Web-callable functions that encapsulate external python functions.

    The function is defined in an external file.  This file is treated
    like a module, but is not a module.  It is not imported directly,
    but is rather read and evaluated.  The file must reside in the
    'Extensions' subdirectory of the Zope installation, or in an
    'Extensions' subdirectory of a product directory.

    Due to the way ExternalMethods are loaded, it is not *currently*
    possible to use Python modules that reside in the 'Extensions'
    directory.  It is possible to load modules found in the
    'lib/python' directory of the Zope installation, or in
    packages that are in the 'lib/python' directory.

    """

    meta_type = 'External Method'

    security = ClassSecurityInfo()
    security.declareObjectProtected(View)

    func_defaults = ComputedAttribute(lambda self: self.getFuncDefaults())
    func_code = ComputedAttribute(lambda self: self.getFuncCode())

    ZopeTime = Acquisition.Acquired
    HelpSys = Acquisition.Acquired
    manage_page_header = Acquisition.Acquired

    manage_options = ((
        {
            'label': 'Properties',
            'action': 'manage_main',
            'help': ('ExternalMethod', 'External-Method_Properties.stx')
        },
        {
            'label': 'Test',
            'action': '',
            'help': ('ExternalMethod', 'External-Method_Try-It.stx')
        },
    ) + OFS.SimpleItem.Item.manage_options +
                      AccessControl.Role.RoleManager.manage_options)

    def __init__(self, id, title, module, function):
        self.id = id
        self.manage_edit(title, module, function)

    security.declareProtected(view_management_screens, 'manage_main')
    manage_main = DTMLFile('dtml/methodEdit', globals())

    security.declareProtected(change_external_methods, 'manage_edit')

    def manage_edit(self, title, module, function, REQUEST=None):
        """Change the external method

        See the description of manage_addExternalMethod for a
        descriotion of the arguments 'module' and 'function'.

        Note that calling 'manage_edit' causes the "module" to be
        effectively reloaded.  This is useful during debugging to see
        the effects of changes, but can lead to problems of functions
        rely on shared global data.
        """
        title = str(title)
        module = str(module)
        function = str(function)

        self.title = title
        if module[-3:] == '.py': module = module[:-3]
        elif module[-4:] == '.pyc': module = module[:-4]
        self._module = module
        self._function = function
        self.getFunction(1)
        if REQUEST:
            message = "External Method Uploaded."
            return self.manage_main(self, REQUEST, manage_tabs_message=message)

    def getFunction(self, reload=0):

        f = getObject(self._module, self._function, reload)
        if hasattr(f, 'im_func'): ff = f.im_func
        else: ff = f

        self._v_func_defaults = ff.func_defaults
        self._v_func_code = FuncCode(ff, f is not ff)

        self._v_f = f

        return f

    def reloadIfChanged(self):
        # If the file has been modified since last loaded, force a reload.
        ts = os.stat(self.filepath())[stat.ST_MTIME]
        if (not hasattr(self, '_v_last_read') or (ts != self._v_last_read)):
            self._v_f = self.getFunction(1)
            self._v_last_read = ts

    if DevelopmentMode:
        # In development mode we do an automatic reload
        # if the module code changed
        def getFuncDefaults(self):
            self.reloadIfChanged()
            if not hasattr(self, '_v_func_defaults'):
                self._v_f = self.getFunction()
            return self._v_func_defaults

        def getFuncCode(self):
            self.reloadIfChanged()
            if not hasattr(self, '_v_func_code'):
                self._v_f = self.getFunction()
            return self._v_func_code
    else:

        def getFuncDefaults(self):
            if not hasattr(self, '_v_func_defaults'):
                self._v_f = self.getFunction()
            return self._v_func_defaults

        def getFuncCode(self):
            if not hasattr(self, '_v_func_code'):
                self._v_f = self.getFunction()
            return self._v_func_code

    security.declareProtected(View, '__call__')

    def __call__(self, *args, **kw):
        """Call an ExternalMethod

        Calling an External Method is roughly equivalent to calling
        the original actual function from Python.  Positional and
        keyword parameters can be passed as usual.  Note however that
        unlike the case of a normal Python method, the "self" argument
        must be passed explicitly.  An exception to this rule is made
        if:

        - The supplied number of arguments is one less than the
          required number of arguments, and

        - The name of the function\'s first argument is 'self'.

        In this case, the URL parent of the object is supplied as the
        first argument.
        """

        filePath = self.filepath()
        if filePath == None:
            raise RuntimeError,\
                "external method could not be called " \
                "because it is None"

        if not os.path.exists(filePath):
            raise RuntimeError,\
                "external method could not be called " \
                "because the file does not exist"

        if DevelopmentMode:
            self.reloadIfChanged()

        if hasattr(self, '_v_f'):
            f = self._v_f
        else:
            f = self.getFunction()

        __traceback_info__ = args, kw, self._v_func_defaults

        try:
            return f(*args, **kw)
        except TypeError, v:
            tb = sys.exc_info()[2]
            try:
                if ((self._v_func_code.co_argcount -
                     len(self._v_func_defaults or ()) - 1 == len(args))
                        and self._v_func_code.co_varnames[0] == 'self'):
                    return f(self.aq_parent.this(), *args, **kw)

                raise TypeError, v, tb
            finally:
                tb = None
Example #23
0
class Document(PortalContent, DefaultDublinCoreImpl):
    """A Document - Handles both StructuredText and HTML.
    """

    implements(IMutableDocument, IDocument, IDAVAware)
    __implements__ = (z2IMutableDocument, z2IDocument,
                      PortalContent.__implements__,
                      DefaultDublinCoreImpl.__implements__)

    meta_type = 'Document'
    effective_date = expiration_date = None
    cooked_text = text = text_format = ''
    _size = 0
    _isDiscussable = 1

    _stx_level = 1  # Structured text level

    _last_safety_belt_editor = ''
    _last_safety_belt = ''
    _safety_belt = ''

    security = ClassSecurityInfo()

    def __init__(self, id, title='', description='', text_format='', text=''):
        DefaultDublinCoreImpl.__init__(self)
        self.id = id
        self.title = title
        self.description = description
        self._edit(text=text, text_format=text_format)
        self.setFormat(text_format)

    security.declareProtected(ModifyPortalContent, 'manage_edit')
    manage_edit = DTMLFile('zmi_editDocument', _dtmldir)

    security.declareProtected(ModifyPortalContent, 'manage_editDocument')

    def manage_editDocument(self, text, text_format, file='', REQUEST=None):
        """ A ZMI (Zope Management Interface) level editing method """
        Document.edit(self, text_format=text_format, text=text, file=file)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(
                self.absolute_url() + '/manage_edit' +
                '?manage_tabs_message=Document+updated')

    def _edit(self, text, text_format='', safety_belt=''):
        """ Edit the Document and cook the body.
        """
        if not self._safety_belt_update(safety_belt=safety_belt):
            msg = _(u'Intervening changes from elsewhere detected. '
                    u'Please refetch the document and reapply your changes. '
                    u'(You may be able to recover your version using the '
                    u"browser 'back' button, but will have to apply them to "
                    u'a freshly fetched copy.)')
            raise EditingConflict(msg)

        self.text = text
        self._size = len(text)

        if not text_format:
            text_format = self.text_format
        if text_format == 'html':
            self.cooked_text = text
        elif text_format == 'plain':
            self.cooked_text = html_quote(text).replace('\n', '<br />')
        else:
            self.cooked_text = HTML(text, level=self._stx_level, header=0)

    #
    #   IMutableDocument method
    #

    security.declareProtected(ModifyPortalContent, 'edit')

    def edit(self, text_format, text, file='', safety_belt=''):
        """ Update the document.

        To add webDav support, we need to check if the content is locked, and if
        so return ResourceLockedError if not, call _edit.

        Note that this method expects to be called from a web form, and so
        disables header processing
        """
        self.failIfLocked()
        if file and (type(file) is not type('')):
            contents = file.read()
            if contents:
                text = contents
        if html_headcheck(text) and text_format.lower() != 'plain':
            text = bodyfinder(text)
        self.setFormat(text_format)
        self._edit(text=text, text_format=text_format, safety_belt=safety_belt)
        self.reindexObject()

    security.declareProtected(ModifyPortalContent, 'setMetadata')

    def setMetadata(self, headers):
        headers['Format'] = self.Format()
        new_subject = keywordsplitter(headers)
        headers['Subject'] = new_subject or self.Subject()
        new_contrib = contributorsplitter(headers)
        headers['Contributors'] = new_contrib or self.Contributors()
        haveheader = headers.has_key
        for key, value in self.getMetadataHeaders():
            if not haveheader(key):
                headers[key] = value
        self._editMetadata(
            title=headers['Title'],
            subject=headers['Subject'],
            description=headers['Description'],
            contributors=headers['Contributors'],
            effective_date=headers['Effective_date'],
            expiration_date=headers['Expiration_date'],
            format=headers['Format'],
            language=headers['Language'],
            rights=headers['Rights'],
        )

    security.declarePrivate('guessFormat')

    def guessFormat(self, text):
        """ Simple stab at guessing the inner format of the text """
        if html_headcheck(text): return 'html'
        else: return 'structured-text'

    security.declarePrivate('handleText')

    def handleText(self, text, format=None, stx_level=None):
        """ Handles the raw text, returning headers, body, format """
        headers = {}
        if not format:
            format = self.guessFormat(text)
        if format == 'html':
            parser = SimpleHTMLParser()
            parser.feed(text)
            headers.update(parser.metatags)
            if parser.title:
                headers['Title'] = parser.title
            body = bodyfinder(text)
        else:
            headers, body = parseHeadersBody(text, headers)
            if stx_level:
                self._stx_level = stx_level
        return headers, body, format

    security.declarePublic('getMetadataHeaders')

    def getMetadataHeaders(self):
        """Return RFC-822-style header spec."""
        hdrlist = DefaultDublinCoreImpl.getMetadataHeaders(self)
        hdrlist.append(('SafetyBelt', self._safety_belt))
        return hdrlist

    security.declarePublic('SafetyBelt')

    def SafetyBelt(self):
        """Return the current safety belt setting.
        For web form hidden button."""
        return self._safety_belt

    def _safety_belt_update(self, safety_belt=''):
        """Check validity of safety belt and update tracking if valid.

        Return 0 if safety belt is invalid, 1 otherwise.

        Note that the policy is deliberately lax if no safety belt value is
        present - "you're on your own if you don't use your safety belt".

        When present, either the safety belt token:
         - ... is the same as the current one given out, or
         - ... is the same as the last one given out, and the person doing the
           edit is the same as the last editor."""

        this_belt = safety_belt
        this_user = getSecurityManager().getUser().getId()

        if (  # we have a safety belt value:
                this_belt
                # and the current object has a safety belt (ie - not freshly made)
                and (self._safety_belt is not None)
                # and the safety belt doesn't match the current one:
                and (this_belt != self._safety_belt)
                # and safety belt and user don't match last safety belt and user:
                and not ((this_belt == self._last_safety_belt) and
                         (this_user == self._last_safety_belt_editor))):
            # Fail.
            return 0

        # We qualified - either:
        #  - the edit was submitted with safety belt stripped, or
        #  - the current safety belt was used, or
        #  - the last one was reused by the last person who did the last edit.
        # In any case, update the tracking.

        self._last_safety_belt_editor = this_user
        self._last_safety_belt = this_belt
        self._safety_belt = str(self._p_mtime)

        return 1

    ### Content accessor methods

    #
    #   IContentish method
    #

    security.declareProtected(View, 'SearchableText')

    def SearchableText(self):
        """ Used by the catalog for basic full text indexing """
        return "%s %s %s" % (self.Title(), self.Description(),
                             self.EditableBody())

    #
    #   IDocument methods
    #

    security.declareProtected(View, 'CookedBody')

    def CookedBody(self, stx_level=None, setlevel=0):
        """ Get the "cooked" (ready for presentation) form of the text.

        The prepared basic rendering of an object.  For Documents, this
        means pre-rendered structured text, or what was between the
        <BODY> tags of HTML.

        If the format is html, and 'stx_level' is not passed in or is the
        same as the object's current settings, return the cached cooked
        text.  Otherwise, recook.  If we recook and 'setlevel' is true,
        then set the recooked text and stx_level on the object.
        """
        if (self.text_format == 'html' or self.text_format == 'plain'
                or (stx_level is None) or (stx_level == self._stx_level)):
            return self.cooked_text
        else:
            cooked = HTML(self.text, level=stx_level, header=0)
            if setlevel:
                self._stx_level = stx_level
                self.cooked_text = cooked
            return cooked

    security.declareProtected(View, 'EditableBody')

    def EditableBody(self):
        """ Get the "raw" (as edited) form of the text.

        The editable body of text.  This is the raw structured text, or
        in the case of HTML, what was between the <BODY> tags.
        """
        return self.text

    #
    #   IDublinCore method
    #

    security.declareProtected(View, 'Format')

    def Format(self):
        """ Dublin Core Format element - resource format.
        """
        if self.text_format == 'html':
            return 'text/html'
        else:
            return 'text/plain'

    #
    #   IMutableDublinCore method
    #

    security.declareProtected(ModifyPortalContent, 'setFormat')

    def setFormat(self, format):
        """ Set text format and Dublin Core resource format.
        """
        value = str(format)
        old_value = self.text_format

        if value == 'text/html' or value == 'html':
            self.text_format = 'html'
        elif value == 'text/plain':
            if self.text_format not in ('structured-text', 'plain'):
                self.text_format = 'structured-text'
        elif value == 'plain':
            self.text_format = 'plain'
        else:
            self.text_format = 'structured-text'

        # Did the format change? We might need to re-cook the content.
        if value != old_value:
            if html_headcheck(self.text) and value != 'plain':
                self.text = bodyfinder(self.text)

            self._edit(self.text,
                       text_format=self.text_format,
                       safety_belt=self._safety_belt)

    ## FTP handlers
    security.declareProtected(ModifyPortalContent, 'PUT')

    def PUT(self, REQUEST, RESPONSE):
        """ Handle HTTP (and presumably FTP?) PUT requests """
        self.dav__init(REQUEST, RESPONSE)
        self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1)
        body = REQUEST.get('BODY', '')
        headers, body, format = self.handleText(text=body)
        safety_belt = headers.get('SafetyBelt', '')
        if REQUEST.get_header('Content-Type', '') == 'text/html':
            text_format = 'html'
        else:
            text_format = format

        try:
            self.setFormat(text_format)
            self.setMetadata(headers)
            self._edit(text=body, safety_belt=safety_belt)
        except EditingConflict, msg:
            # XXX Can we get an error msg through?  Should we be raising an
            #     exception, to be handled in the FTP mechanism?  Inquiring
            #     minds...
            transaction.abort()
            RESPONSE.setStatus(450)
            return RESPONSE
        except ResourceLockedError, msg:
            transaction.abort()
            RESPONSE.setStatus(423)
            return RESPONSE
Example #24
0
from Products.ZenRelations.RelSchema import *
from Products.ZenUtils.ZenTales import talesEval

from ZenModelRM import ZenModelRM


def manage_addRRDGraph(context, id, REQUEST=None):
    """make a RRDGraph"""
    graph = RRDGraph(id)
    context._setObject(graph.id, graph)
    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect(context.absolute_url_path() +
                                     '/manage_main')


addRRDGraph = DTMLFile('dtml/addRRDGraph', globals())


class RRDGraph(ZenModelRM):

    meta_type = 'RRDGraph'

    security = ClassSecurityInfo()

    dsnames = []
    sequence = 0
    height = 100
    width = 500
    threshmap = []
    units = ""
    log = False
Example #25
0
class Document(PortalContent, DefaultDublinCoreImpl):
    """ A Document - Handles both StructuredText and HTML """

    __implements__ = (PortalContent.__implements__,
                      DefaultDublinCoreImpl.__implements__)

    meta_type = 'Document'
    effective_date = expiration_date = None
    text_format = ''
    _isDiscussable = 1

    _stx_level = 1  # Structured text level

    _last_safety_belt_editor = ''
    _last_safety_belt = ''
    _safety_belt = ''

    # Declarative security (replaces __ac_permissions__)
    security = ClassSecurityInfo()

    def __init__(self, id, title='', description='', text_format='', text=''):
        DefaultDublinCoreImpl.__init__(self)
        self.id = id
        self.title = title
        self.description = description
        self.text = text
        self.text_format = text_format
        self.edit(text_format=text_format, text=text)

    security.declareProtected(CMFCorePermissions.ModifyPortalContent,
                              'manage_edit')
    manage_edit = DTMLFile('zmi_editDocument', _dtmldir)

    security.declareProtected(CMFCorePermissions.ModifyPortalContent,
                              'manage_editDocument')

    def manage_editDocument(self, text_format, text, file='', REQUEST=None):
        """ A ZMI (Zope Management Interface) level editing method """
        self._edit(text_format, text, file)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(
                self.absolute_url() + '/manage_edit' +
                '?manage_tabs_message=Document+updated')

    def _edit(self, text_format, text, file='', safety_belt=''):
        """ Edit the Document - Parses headers and cooks the body"""
        self.text = text
        headers = {}
        if file and (type(file) is not type('')):
            contents = file.read()
            if contents:
                text = self.text = contents

        headers, body, cooked, format = self.handleText(text, text_format)

        if not safety_belt:
            safety_belt = headers.get('SafetyBelt', '')
        if not self._safety_belt_update(safety_belt=safety_belt):
            msg = ("Intervening changes from elsewhere detected."
                   " Please refetch the document and reapply your changes."
                   " (You may be able to recover your version using the"
                   " browser 'back' button, but will have to apply them"
                   " to a freshly fetched copy.)")
            raise 'EditingConflict', msg

        self.text_format = format
        self.cooked_text = cooked
        self.text = body

        headers['Format'] = self.Format()
        new_subject = keywordsplitter(headers)
        headers['Subject'] = new_subject or self.Subject()
        haveheader = headers.has_key
        for key, value in self.getMetadataHeaders():
            if key != 'Format' and not haveheader(key):
                headers[key] = value

        self.editMetadata(
            title=headers['Title'],
            subject=headers['Subject'],
            description=headers['Description'],
            contributors=headers['Contributors'],
            effective_date=headers['Effective_date'],
            expiration_date=headers['Expiration_date'],
            format=headers['Format'],
            language=headers['Language'],
            rights=headers['Rights'],
        )

    security.declareProtected(CMFCorePermissions.ModifyPortalContent, 'edit')
    edit = WorkflowAction(_edit)

    security.declarePrivate('guessFormat')

    def guessFormat(self, text):
        """ Simple stab at guessing the inner format of the text """
        if utils.html_headcheck(text): return 'html'
        else: return 'structured-text'

    security.declarePrivate('handleText')

    def handleText(self, text, format=None, stx_level=None):
        """ Handles the raw text, returning headers, body, cooked, format """
        headers = {}
        body = cooked = text
        level = stx_level or self._stx_level

        if not format:
            format = self.guessFormat(text)

        if format == 'html':
            parser = SimpleHTMLParser()
            parser.feed(text)
            headers.update(parser.metatags)
            if parser.title:
                headers['Title'] = parser.title
            bodyfound = bodyfinder(text)
            if bodyfound:
                cooked = body = bodyfound
        else:
            headers, body = parseHeadersBody(text, headers)
            cooked = _format_stx(text=body, level=level)
            self._stx_level = level

        return headers, body, cooked, format

    security.declarePublic('getMetadataHeaders')

    def getMetadataHeaders(self):
        """Return RFC-822-style header spec."""
        hdrlist = DefaultDublinCoreImpl.getMetadataHeaders(self)
        hdrlist.append(('SafetyBelt', self._safety_belt))
        return hdrlist

    security.declarePublic('SafetyBelt')

    def SafetyBelt(self):
        """Return the current safety belt setting.
        For web form hidden button."""
        return self._safety_belt

    def _safety_belt_update(self, safety_belt=''):
        """Check validity of safety belt and update tracking if valid.

        Return 0 if safety belt is invalid, 1 otherwise.

        Note that the policy is deliberately lax if no safety belt value is
        present - "you're on your own if you don't use your safety belt".

        When present, either the safety belt token:
         - ... is the same as the current one given out, or
         - ... is the same as the last one given out, and the person doing the
           edit is the same as the last editor."""

        this_belt = safety_belt
        this_user = getSecurityManager().getUser().getUserName()

        if (  # we have a safety belt value:
                this_belt
                # and the current object has a safety belt (ie - not freshly made)
                and (self._safety_belt is not None)
                # and the safety belt doesn't match the current one:
                and (this_belt != self._safety_belt)
                # and safety belt and user don't match last safety belt and user:
                and not ((this_belt == self._last_safety_belt) and
                         (this_user == self._last_safety_belt_editor))):
            # Fail.
            return 0

        # We qualified - either:
        #  - the edit was submitted with safety belt stripped, or
        #  - the current safety belt was used, or
        #  - the last one was reused by the last person who did the last edit.
        # In any case, update the tracking.

        self._last_safety_belt_editor = this_user
        self._last_safety_belt = this_belt
        self._safety_belt = str(self._p_mtime)

        return 1

    ### Content accessor methods
    security.declareProtected(CMFCorePermissions.View, 'SearchableText')

    def SearchableText(self):
        """ Used by the catalog for basic full text indexing """
        return "%s %s %s" % (self.title, self.description, self.text)

    security.declareProtected(CMFCorePermissions.View, 'CookedBody')

    def CookedBody(self, stx_level=None, setlevel=0):
        """\
        The prepared basic rendering of an object.  For Documents, this
        means pre-rendered structured text, or what was between the
        <BODY> tags of HTML.

        If the format is html, and 'stx_level' is not passed in or is the
        same as the object's current settings, return the cached cooked
        text.  Otherwise, recook.  If we recook and 'setlevel' is true,
        then set the recooked text and stx_level on the object.
        """
        if (self.text_format == 'html' or (stx_level is None)
                or (stx_level == self._stx_level)):
            return self.cooked_text
        else:
            cooked = _format_stx(self.text, stx_level)
            if setlevel:
                self._stx_level = stx_level
                self.cooked_text = cooked
            return cooked

    security.declareProtected(CMFCorePermissions.View, 'EditableBody')

    def EditableBody(self):
        """\
        The editable body of text.  This is the raw structured text, or
        in the case of HTML, what was between the <BODY> tags.
        """
        return self.text

    security.declareProtected(CMFCorePermissions.View, 'Description')

    def Description(self):
        """ Dublin core description, also important for indexing """
        return self.description

    security.declareProtected(CMFCorePermissions.View, 'Format')

    def Format(self):
        """ Returns a content-type style format of the underlying source """
        if self.text_format == 'html':
            return 'text/html'
        else:
            return 'text/plain'

    security.declareProtected(CMFCorePermissions.ModifyPortalContent,
                              'setFormat')

    def setFormat(self, value):
        value = str(value)
        if value == 'text/html':
            self.text_format = 'html'
        else:
            self.text_format = 'structured-text'

    setFormat = WorkflowAction(setFormat)

    ## FTP handlers
    security.declareProtected(CMFCorePermissions.ModifyPortalContent, 'PUT')

    def PUT(self, REQUEST, RESPONSE):
        """ Handle HTTP (and presumably FTP?) PUT requests """
        self.dav__init(REQUEST, RESPONSE)
        body = REQUEST.get('BODY', '')
        guessedformat = REQUEST.get_header('Content-Type', 'text/plain')
        ishtml = (guessedformat == 'text/html') or utils.html_headcheck(body)

        if ishtml: self.setFormat('text/html')
        else: self.setFormat('text/plain')

        try:
            self.edit(text_format=self.text_format, text=body)
        except 'EditingConflict', msg:
            # XXX Can we get an error msg through?  Should we be raising an
            #     exception, to be handled in the FTP mechanism?  Inquiring
            #     minds...
            get_transaction().abort()
            RESPONSE.setStatus(450)
            return RESPONSE

        RESPONSE.setStatus(204)
        return RESPONSE
Example #26
0
def manage_addIpNetwork(context, id, netmask=24, REQUEST = None, version=4):
    """make a IpNetwork"""
    net = IpNetwork(id, netmask=netmask, version=version)
    context._setObject(net.id, net)
    if id.endswith("Networks"):
        net = context._getOb(net.id)
        net.dmdRootName = id
        net.buildZProperties()
        net.createCatalog()
        net.initialize_network_cache(net)
        #manage_addZDeviceDiscoverer(context)
    if REQUEST is not None:
        REQUEST['RESPONSE'].redirect(context.absolute_url_path()+'/manage_main')


addIpNetwork = DTMLFile('dtml/addIpNetwork',globals())


# When an IP is added the default location will be
# into class A->B->C network tree
defaultNetworkTree = (32,)

class IpNetwork(DeviceOrganizer, IpNetworkIndexable):
    """IpNetwork object"""

    implements(IObjectEventsSubscriber)

    isInTree = True

    buildLinks = True
Example #27
0
class MetadataTool(UniqueObject, SimpleItem, ActionProviderBase):

    __implements__ = (IMetadataTool, ActionProviderBase.__implements__)

    id = 'portal_metadata'
    meta_type = 'Default Metadata Tool'
    _actions = ()

    #
    #   Default values.
    #
    publisher = ''
    element_specs = None
    #initial_values_hook = None
    #validation_hook     = None

    security = ClassSecurityInfo()

    def __init__(
            self,
            publisher=None
        #, initial_values_hook=None
        #, validation_hook=None
        ,
            element_specs=DEFAULT_ELEMENT_SPECS):

        self.editProperties(publisher
                            #, initial_values_hook
                            #, validation_hook
                            )

        self.element_specs = PersistentMapping()

        for name, is_multi_valued in element_specs:
            self.element_specs[name] = ElementSpec(is_multi_valued)

    #
    #   ZMI methods
    #
    manage_options = (
        ActionProviderBase.manage_options +
        ({
            'label': 'Overview',
            'action': 'manage_overview'
        }, {
            'label': 'Properties',
            'action': 'propertiesForm'
        }, {
            'label': 'Elements',
            'action': 'elementPoliciesForm'
        }
         # TODO     , { 'label'      : 'Types'
         #            , 'action'     : 'typesForm'
         #            }
         ) + SimpleItem.manage_options)

    security.declareProtected(ManagePortal, 'manage_overview')
    manage_overview = DTMLFile('explainMetadataTool', _dtmldir)

    security.declareProtected(ManagePortal, 'propertiesForm')
    propertiesForm = DTMLFile('metadataProperties', _dtmldir)

    security.declareProtected(ManagePortal, 'editProperties')

    def editProperties(
            self,
            publisher=None
        # TODO , initial_values_hook=None
        # TODO , validation_hook=None
        ,
            REQUEST=None):
        """
            Form handler for "tool-wide" properties (including list of
            metadata elements).
        """
        if publisher is not None:
            self.publisher = publisher

        # TODO self.initial_values_hook = initial_values_hook
        # TODO self.validation_hook = validation_hook

        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                         '/propertiesForm' +
                                         '?manage_tabs_message=Tool+updated.')

    security.declareProtected(ManagePortal, 'elementPoliciesForm')
    elementPoliciesForm = DTMLFile('metadataElementPolicies', _dtmldir)

    security.declareProtected(ManagePortal, 'addElementPolicy')

    def addElementPolicy(self,
                         element,
                         content_type,
                         is_required,
                         supply_default,
                         default_value,
                         enforce_vocabulary,
                         allowed_vocabulary,
                         REQUEST=None):
        """
            Add a type-specific policy for one of our elements.
        """
        if content_type == '<default>':
            content_type = None

        spec = self.getElementSpec(element)
        spec.addPolicy(content_type)
        policy = spec.getPolicy(content_type)
        policy.edit(is_required, supply_default, default_value,
                    enforce_vocabulary, allowed_vocabulary)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                         '/elementPoliciesForm' + '?element=' +
                                         element +
                                         '&manage_tabs_message=Policy+added.')

    security.declareProtected(ManagePortal, 'removeElementPolicy')

    def removeElementPolicy(self, element, content_type, REQUEST=None):
        """
            Remvoe a type-specific policy for one of our elements.
        """
        if content_type == '<default>':
            content_type = None

        spec = self.getElementSpec(element)
        spec.removePolicy(content_type)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(
                self.absolute_url() + '/elementPoliciesForm' + '?element=' +
                element + '&manage_tabs_message=Policy+removed.')

    security.declareProtected(ManagePortal, 'updateElementPolicy')

    def updateElementPolicy(self,
                            element,
                            content_type,
                            is_required,
                            supply_default,
                            default_value,
                            enforce_vocabulary,
                            allowed_vocabulary,
                            REQUEST=None):
        """
            Update a policy for one of our elements ('content_type'
            will be '<default>' when we edit the default).
        """
        if content_type == '<default>':
            content_type = None
        spec = self.getElementSpec(element)
        policy = spec.getPolicy(content_type)
        policy.edit(is_required, supply_default, default_value,
                    enforce_vocabulary, allowed_vocabulary)
        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(
                self.absolute_url() + '/elementPoliciesForm' + '?element=' +
                element + '&manage_tabs_message=Policy+updated.')

    #
    #   Element spec manipulation.
    #
    security.declareProtected(ManagePortal, 'listElementSpecs')

    def listElementSpecs(self):
        """
            Return a list of ElementSpecs representing
            the elements managed by the tool.
        """
        res = []
        for k, v in self.element_specs.items():
            res.append((k, v.__of__(self)))
        return res

    security.declareProtected(ManagePortal, 'getElementSpec')

    def getElementSpec(self, element):
        """
            Return an ElementSpec representing the tool's knowledge
            of 'element'.
        """
        return self.element_specs[element].__of__(self)

    security.declareProtected(ManagePortal, 'addElementSpec')

    def addElementSpec(self, element, is_multi_valued, REQUEST=None):
        """
            Add 'element' to our list of managed elements.
        """
        # Don't replace.
        if self.element_specs.has_key(element):
            return

        self.element_specs[element] = ElementSpec(is_multi_valued)

        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                         '/propertiesForm' +
                                         '?manage_tabs_message=Element+' +
                                         element + '+added.')

    security.declareProtected(ManagePortal, 'removeElementSpec')

    def removeElementSpec(self, element, REQUEST=None):
        """
            Remove 'element' from our list of managed elements.
        """
        del self.element_specs[element]

        if REQUEST is not None:
            REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                         '/propertiesForm' +
                                         '?manage_tabs_message=Element+' +
                                         element + '+removed.')

    security.declareProtected(ManagePortal, 'listPolicies')

    def listPolicies(self, typ=None):
        """
            Show all policies for a given content type, or the default
            if None.
        """
        result = []
        for element, spec in self.listElementSpecs():
            result.append((element, spec.getPolicy(typ)))
        return result

    #
    #   'portal_metadata' interface
    #
    security.declarePrivate('getFullName')

    def getFullName(self, userid):
        """
            Convert an internal userid to a "formal" name, if
            possible, perhaps using the 'portal_membership' tool.

            Used to map userid's for Creator, Contributor DCMI
            queries.
        """
        return userid  # TODO: do lookup here

    security.declarePublic('getPublisher')

    def getPublisher(self):
        """
            Return the "formal" name of the publisher of the
            portal.
        """
        return self.publisher

    security.declarePublic('listAllowedVocabulary')

    def listAllowedVocabulary(self, element, content=None, content_type=None):
        """
            List allowed keywords for a given portal_type, or all
            possible keywords if none supplied.
        """
        spec = self.getElementSpec(element)
        if content_type is None and content:
            content_type = content.getPortalTypeName()
        return spec.getPolicy(content_type).allowedVocabulary()

    security.declarePublic('listAllowedSubjects')

    def listAllowedSubjects(self, content=None, content_type=None):
        """
            List allowed keywords for a given portal_type, or all
            possible keywords if none supplied.
        """
        return self.listAllowedVocabulary('Subject', content, content_type)

    security.declarePublic('listAllowedFormats')

    def listAllowedFormats(self, content=None, content_type=None):
        """
            List the allowed 'Content-type' values for a particular
            portal_type, or all possible formats if none supplied.
        """
        return self.listAllowedVocabulary('Format', content, content_type)

    security.declarePublic('listAllowedLanguages')

    def listAllowedLanguages(self, content=None, content_type=None):
        """
            List the allowed language values.
        """
        return self.listAllowedVocabulary('Language', content, content_type)

    security.declarePublic('listAllowedRights')

    def listAllowedRights(self, content=None, content_type=None):
        """
            List the allowed values for a "Rights"
            selection list;  this gets especially important where
            syndication is involved.
        """
        return self.listAllowedVocabulary('Rights', content, content_type)

    security.declareProtected(ModifyPortalContent, 'setInitialMetadata')

    def setInitialMetadata(self, content):
        """
            Set initial values for content metatdata, supplying
            any site-specific defaults.
        """
        for element, policy in self.listPolicies(content.getPortalTypeName()):

            if not getattr(content, element)():

                if policy.supplyDefault():
                    setter = getattr(content, 'set%s' % element)
                    setter(policy.defaultValue())
                elif policy.isRequired():
                    raise MetadataError, \
                          'Metadata element %s is required.' % element

        # TODO:  Call initial_values_hook, if present

    security.declareProtected(View, 'validateMetadata')

    def validateMetadata(self, content):
        """
            Enforce portal-wide policies about DCI, e.g.,
            requiring non-empty title/description, etc.  Called
            by the CMF immediately before saving changes to the
            metadata of an object.
        """
        for element, policy in self.listPolicies(content.getPortalTypeName()):

            value = getattr(content, element)()
            if not value and policy.isRequired():
                raise MetadataError, \
                        'Metadata element %s is required.' % element

            if value and policy.enforceVocabulary():
                values = policy.isMultiValued() and value or [value]
                for value in values:
                    if not value in policy.allowedVocabulary():
                        raise MetadataError, \
                        'Value %s is not in allowed vocabulary for ' \
                        'metadata element %s.' % ( value, element )
Example #28
0
class MajorMinorPredicate(SimpleItem):
    """
        Predicate matching on 'major/minor' content types.
        Empty major or minor implies wildcard (all match).
    """
    major = minor = None
    PREDICATE_TYPE = 'major_minor'

    security = ClassSecurityInfo()

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

    security.declareProtected(ManagePortal, 'getMajorType')

    def getMajorType(self, join=string.join):
        """
        """
        if self.major is None:
            return 'None'
        return join(self.major)

    security.declareProtected(ManagePortal, 'getMinorType')

    def getMinorType(self, join=string.join):
        """
        """
        if self.minor is None:
            return 'None'
        return join(self.minor)

    security.declareProtected(ManagePortal, 'edit')

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

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

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

        self.major = major
        self.minor = minor

    #
    #   ContentTypeRegistryPredicate interface
    #
    security.declareObjectPublic()

    def __call__(self, name, typ, body, SLASH_SPLIT=re.compile('/')):
        """
            Return true if the rule matches, else false.
        """
        if self.major is None:
            return 0

        if self.minor is None:
            return 0

        typ = typ or '/'
        if not '/' in typ:
            typ = typ + '/'
        major, minor = SLASH_SPLIT.split(typ)

        if self.major and not major in self.major:
            return 0

        if self.minor and not minor in self.minor:
            return 0

        return 1

    security.declareProtected(ManagePortal, 'getTypeLabel')

    def getTypeLabel(self):
        """
            Return a human-readable label for the predicate type.
        """
        return self.PREDICATE_TYPE

    security.declareProtected(ManagePortal, 'predicateWidget')
    predicateWidget = DTMLFile('majorMinorWidget', _dtmldir)
Example #29
0
class UndoTool(UniqueObject, SimpleItem, ActionProviderBase):
    """ This tool is used to undo changes.
    """

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

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

    security = ClassSecurityInfo()

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

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

    def listUndoableTransactionsFor(self,
                                    object,
                                    first_transaction=None,
                                    last_transaction=None,
                                    PrincipiaUndoBatchSize=None):
        '''Lists all transaction IDs the user is allowed to undo.
        '''
        # arg list for undoable_transactions() changed in Zope 2.2.
        portal = queryUtility(ISiteRoot)
        if site is None:
            # fallback
            portal = self.aq_inner.aq_parent

        transactions = portal.undoable_transactions(
            first_transaction=first_transaction,
            last_transaction=last_transaction,
            PrincipiaUndoBatchSize=PrincipiaUndoBatchSize)
        for t in transactions:
            # Ensure transaction ids don't have embedded LF.
            t['id'] = t['id'].replace('\n', '')
        if not _checkPermission(ManagePortal, portal):
            # Filter out transactions done by other members of the portal.
            user_id = _getAuthenticatedUser(self).getId()
            transactions = filter(lambda record, user_id=user_id: record[
                'user_name'].split()[-1] == user_id,
                                  transactions)
        return transactions

    security.declarePublic('undo')

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

        xids = {}  # set of allowed transaction IDs

        allowed = self.listUndoableTransactionsFor(object)

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

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

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

        object.manage_undo_transactions(transaction_info)
Example #30
0
class ContentTypeRegistry(SimpleItem):
    """
        Registry for rules which map PUT args to a CMF Type Object.
    """
    meta_type = 'Content Type Registry'
    id = 'content_type_registry'

    manage_options = ({
        'label': 'Predicates',
        'action': 'manage_predicates'
    }, {
        'label': 'Test',
        'action': 'manage_testRegistry'
    }) + SimpleItem.manage_options

    security = ClassSecurityInfo()

    def __init__(self):
        self.predicate_ids = ()
        self.predicates = PersistentMapping()

    #
    #   ZMI
    #
    security.declarePublic('listPredicateTypes')

    def listPredicateTypes(self):
        """
        """
        return map(lambda x: x[0], _predicate_types)

    security.declareProtected(ManagePortal, 'manage_predicates')
    manage_predicates = DTMLFile('registryPredList', _dtmldir)

    security.declareProtected(ManagePortal, 'doAddPredicate')

    def doAddPredicate(self, predicate_id, predicate_type, REQUEST):
        """
        """
        self.addPredicate(predicate_id, predicate_type)
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=Predicate+added.')

    security.declareProtected(ManagePortal, 'doUpdatePredicate')

    def doUpdatePredicate(self, predicate_id, predicate, typeObjectName,
                          REQUEST):
        """
        """
        self.updatePredicate(predicate_id, predicate, typeObjectName)
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=Predicate+updated.')

    security.declareProtected(ManagePortal, 'doMovePredicateUp')

    def doMovePredicateUp(self, predicate_id, REQUEST):
        """
        """
        predicate_ids = list(self.predicate_ids)
        ndx = predicate_ids.index(predicate_id)
        if ndx == 0:
            msg = "Predicate+already+first."
        else:
            self.reorderPredicate(predicate_id, ndx - 1)
            msg = "Predicate+moved."
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=%s' % msg)

    security.declareProtected(ManagePortal, 'doMovePredicateDown')

    def doMovePredicateDown(self, predicate_id, REQUEST):
        """
        """
        predicate_ids = list(self.predicate_ids)
        ndx = predicate_ids.index(predicate_id)
        if ndx == len(predicate_ids) - 1:
            msg = "Predicate+already+last."
        else:
            self.reorderPredicate(predicate_id, ndx + 1)
            msg = "Predicate+moved."
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=%s' % msg)

    security.declareProtected(ManagePortal, 'doRemovePredicate')

    def doRemovePredicate(self, predicate_id, REQUEST):
        """
        """
        self.removePredicate(predicate_id)
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_predicates' +
                                     '?manage_tabs_message=Predicate+removed.')

    security.declareProtected(ManagePortal, 'manage_testRegistry')
    manage_testRegistry = DTMLFile('registryTest', _dtmldir)

    security.declareProtected(ManagePortal, 'doTestRegistry')

    def doTestRegistry(self, name, content_type, body, REQUEST):
        """
        """
        typeName = self.findTypeName(name, content_type, body)
        if typeName is None:
            typeName = '<unknown>'
        REQUEST['RESPONSE'].redirect(self.absolute_url() +
                                     '/manage_testRegistry' +
                                     '?testResults=Type:%s' %
                                     urllib.quote(typeName))

    #
    #   Predicate manipulation
    #
    security.declarePublic('getPredicate')

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

    security.declarePublic('listPredicates')

    def listPredicates(self):
        """
            Return a sequence of tuples,
            '( id, ( predicate, typeObjectName ) )'
            for all predicates in the registry 
        """
        result = []
        for predicate_id in self.predicate_ids:
            result.append((predicate_id, self.predicates[predicate_id]))
        return tuple(result)

    security.declarePublic('getTypeObjectName')

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

    security.declareProtected(ManagePortal, 'addPredicate')

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

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

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

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

    security.declareProtected(ManagePortal, 'addPredicate')

    def updatePredicate(self, predicate_id, predicate, typeObjectName):
        """
            Update a predicate in this element.
        """
        if not predicate_id in self.predicate_ids:
            raise ValueError, "Unknown predicate: %s" % predicate_id

        predObj = self.predicates[predicate_id][0]
        mapply(predObj.edit, (), predicate.__dict__)
        self.assignTypeName(predicate_id, typeObjectName)

    security.declareProtected(ManagePortal, 'removePredicate')

    def removePredicate(self, predicate_id):
        """
            Remove a predicate from the registry.
        """
        del self.predicates[predicate_id]
        idlist = list(self.predicate_ids)
        ndx = idlist.index(predicate_id)
        idlist = idlist[:ndx] + idlist[ndx + 1:]
        self.predicate_ids = tuple(idlist)

    security.declareProtected(ManagePortal, 'reorderPredicate')

    def reorderPredicate(self, predicate_id, newIndex):
        """
            Move a given predicate to a new location in the list.
        """
        idlist = list(self.predicate_ids)
        ndx = idlist.index(predicate_id)
        pred = idlist[ndx]
        idlist = idlist[:ndx] + idlist[ndx + 1:]
        idlist.insert(newIndex, pred)
        self.predicate_ids = tuple(idlist)

    security.declareProtected(ManagePortal, 'assignTypeName')

    def assignTypeName(self, predicate_id, typeObjectName):
        """
            Bind the given predicate to a particular type object.
        """
        pred, oldTypeObjName = self.predicates[predicate_id]
        self.predicates[predicate_id] = (pred, typeObjectName)

    #
    #   ContentTypeRegistry interface
    #
    def findTypeName(self, name, typ, body):
        """
            Perform a lookup over a collection of rules, returning the
            the name of the Type object corresponding to name/typ/body.
            Return None if no match found.
        """
        for predicate_id in self.predicate_ids:
            pred, typeObjectName = self.predicates[predicate_id]
            if pred(name, typ, body):
                return typeObjectName

        return None
Example #31
0
class VariableDefinition(SimpleItem):
    """Variable definition"""

    meta_type = 'Workflow Variable'

    security = ClassSecurityInfo()
    security.declareObjectProtected(ManagePortal)

    description = ''
    for_catalog = 1
    for_status = 1
    default_value = ''
    default_expr = None  # Overrides default_value if set
    info_guard = None
    update_always = 1

    manage_options = ({'label': 'Properties', 'action': 'manage_properties'}, )

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

    def getDefaultExprText(self):
        if not self.default_expr:
            return ''
        else:
            return self.default_expr.text

    def getInfoGuard(self):
        if self.info_guard is not None:
            return self.info_guard
        else:
            return Guard().__of__(self)  # Create a temporary guard.

    def getInfoGuardSummary(self):
        res = None
        if self.info_guard is not None:
            res = self.info_guard.getSummary()
        return res

    _properties_form = DTMLFile('variable_properties', _dtmldir)

    def manage_properties(self, REQUEST, manage_tabs_message=None):
        '''
        '''
        return self._properties_form(
            REQUEST,
            management_view='Properties',
            manage_tabs_message=manage_tabs_message,
        )

    def setProperties(self,
                      description,
                      default_value='',
                      default_expr='',
                      for_catalog=0,
                      for_status=0,
                      update_always=0,
                      props=None,
                      REQUEST=None):
        '''
        '''
        self.description = str(description)
        self.default_value = str(default_value)
        if default_expr:
            self.default_expr = Expression(default_expr)
        else:
            self.default_expr = None

        g = Guard()
        if g.changeFromProperties(props or REQUEST):
            self.info_guard = g
        else:
            self.info_guard = None
        self.for_catalog = bool(for_catalog)
        self.for_status = bool(for_status)
        self.update_always = bool(update_always)
        if REQUEST is not None:
            return self.manage_properties(REQUEST, 'Properties changed.')
Example #32
0
class PythonScript(Script, Historical, Cacheable):
    """Web-callable scripts written in a safe subset of Python.

    The function may include standard python code, so long as it does
    not attempt to use the "exec" statement or certain restricted builtins.
    """

    __implements__ = (WriteLockInterface, )
    meta_type = 'Script (Python)'
    _proxy_roles = ()

    _params = _body = ''
    errors = warnings = ()
    _v_change = 0

    manage_options = (
        {'label':'Edit',
         'action':'ZPythonScriptHTML_editForm',
         'help': ('PythonScripts', 'PythonScript_edit.stx')},
        ) + BindingsUI.manage_options + (
        {'label':'Test',
         'action':'ZScriptHTML_tryForm',
         'help': ('PythonScripts', 'PythonScript_test.stx')},
        {'label':'Proxy',
         'action':'manage_proxyForm',
         'help': ('OFSP','DTML-DocumentOrMethod_Proxy.stx')},
        ) + Historical.manage_options + SimpleItem.manage_options + \
        Cacheable.manage_options

    def __init__(self, id):
        self.id = id
        self.ZBindings_edit(defaultBindings)
        self._makeFunction()

    security = AccessControl.ClassSecurityInfo()

    security.declareObjectProtected('View')
    security.declareProtected('View', '__call__')

    security.declareProtected('View management screens',
                              'ZPythonScriptHTML_editForm', 'manage_main',
                              'read', 'ZScriptHTML_tryForm',
                              'PrincipiaSearchSource', 'document_src',
                              'params', 'body', 'get_filepath')

    ZPythonScriptHTML_editForm = DTMLFile('www/pyScriptEdit', globals())
    manage = manage_main = ZPythonScriptHTML_editForm
    ZPythonScriptHTML_editForm._setName('ZPythonScriptHTML_editForm')

    security.declareProtected('Change Python Scripts',
                              'ZPythonScriptHTML_editAction',
                              'ZPythonScript_setTitle', 'ZPythonScript_edit',
                              'ZPythonScriptHTML_upload',
                              'ZPythonScriptHTML_changePrefs')

    def ZPythonScriptHTML_editAction(self, REQUEST, title, params, body):
        """Change the script's main parameters."""
        self.ZPythonScript_setTitle(title)
        self.ZPythonScript_edit(params, body)
        message = "Saved changes."
        return self.ZPythonScriptHTML_editForm(self,
                                               REQUEST,
                                               manage_tabs_message=message)

    def ZPythonScript_setTitle(self, title):
        title = str(title)
        if self.title != title:
            self.title = title
            self.ZCacheable_invalidate()

    def ZPythonScript_edit(self, params, body):
        self._validateProxy()
        if self.wl_isLocked():
            raise ResourceLockedError, "The script is locked via WebDAV."
        if type(body) is not type(''):
            body = body.read()
        if self._params <> params or self._body <> body or self._v_change:
            self._params = str(params)
            self.write(body)

    def ZPythonScriptHTML_upload(self, REQUEST, file=''):
        """Replace the body of the script with the text in file."""
        if self.wl_isLocked():
            raise ResourceLockedError, "The script is locked via WebDAV."

        if type(file) is not type(''):
            if not file: raise ValueError, 'File not specified'
            file = file.read()

        self.write(file)
        message = 'Saved changes.'
        return self.ZPythonScriptHTML_editForm(self,
                                               REQUEST,
                                               manage_tabs_message=message)

    def ZPythonScriptHTML_changePrefs(self,
                                      REQUEST,
                                      height=None,
                                      width=None,
                                      dtpref_cols="100%",
                                      dtpref_rows="20"):
        """Change editing preferences."""
        dr = {"Taller": 5, "Shorter": -5}.get(height, 0)
        dc = {"Wider": 5, "Narrower": -5}.get(width, 0)
        if isinstance(height, int): dtpref_rows = height
        if isinstance(width, int) or \
           isinstance(width, str) and width.endswith('%'):
            dtpref_cols = width
        rows = str(max(1, int(dtpref_rows) + dr))
        cols = str(dtpref_cols)
        if cols.endswith('%'):
            cols = str(min(100, max(25, int(cols[:-1]) + dc))) + '%'
        else:
            cols = str(max(35, int(cols) + dc))
        e = (DateTime("GMT") + 365).rfc822()
        setCookie = REQUEST["RESPONSE"].setCookie
        setCookie("dtpref_rows", rows, path='/', expires=e)
        setCookie("dtpref_cols", cols, path='/', expires=e)
        REQUEST.other.update({"dtpref_cols": cols, "dtpref_rows": rows})
        return self.manage_main(self, REQUEST)

    def ZScriptHTML_tryParams(self):
        """Parameters to test the script with."""
        param_names = []
        for name in self._params.split(','):

            name = name.strip()
            if name and name[0] != '*' and re.match('\w', name):
                param_names.append(name.split('=', 1)[0].strip())
        return param_names

    def manage_historyCompare(self,
                              rev1,
                              rev2,
                              REQUEST,
                              historyComparisonResults=''):
        return PythonScript.inheritedAttribute('manage_historyCompare')(
            self,
            rev1,
            rev2,
            REQUEST,
            historyComparisonResults=html_diff(rev1.read(), rev2.read()))

    def __setstate__(self, state):
        Script.__setstate__(self, state)
        if (getattr(self, 'Python_magic', None) != Python_magic
                or getattr(self, 'Script_magic', None) != Script_magic):
            global _log_complaint
            if _log_complaint:
                LOG.info(_log_complaint)
                _log_complaint = 0
            # Changes here won't get saved, unless this Script is edited.
            body = self._body.rstrip()
            if body:
                self._body = body + '\n'
            self._compile()
            self._v_change = 1
        elif self._code is None:
            self._v_ft = self._v_f = None
        else:
            self._newfun(marshal.loads(self._code))

    def _compiler(self, *args, **kw):
        return RestrictedPython.compile_restricted_function(*args, **kw)

    def _compile(self):
        bind_names = self.getBindingAssignments().getAssignedNamesInOrder()
        r = self._compiler(self._params,
                           self._body or 'pass',
                           self.id,
                           self.meta_type,
                           globalize=bind_names)
        code = r[0]
        errors = r[1]
        self.warnings = tuple(r[2])
        if errors:
            self._code = None
            self._v_ft = self._v_f = None
            self._setFuncSignature((), (), 0)
            # Fix up syntax errors.
            filestring = '  File "<string>",'
            for i in range(len(errors)):
                line = errors[i]
                if line.startswith(filestring):
                    errors[i] = line.replace(filestring, '  Script', 1)
            self.errors = errors
            return

        self._code = marshal.dumps(code)
        self.errors = ()
        f = self._newfun(code)
        fc = f.func_code
        self._setFuncSignature(f.func_defaults, fc.co_varnames, fc.co_argcount)
        self.Python_magic = Python_magic
        self.Script_magic = Script_magic
        self._v_change = 0

    def _newfun(self, code):
        g = get_safe_globals()
        g['_getattr_'] = guarded_getattr
        g['__debug__'] = __debug__
        g['__name__'] = None

        l = {}
        exec code in g, l
        self._v_f = f = l.values()[0]
        self._v_ft = (f.func_code, g, f.func_defaults or ())
        return f

    def _makeFunction(self, dummy=0):  # CMFCore.FSPythonScript uses dummy arg.
        self.ZCacheable_invalidate()
        self._compile()
        if not (aq_parent(self) is None or hasattr(self, '_filepath')):
            # It needs a _filepath, and has an acquisition wrapper.
            self._filepath = self.get_filepath()

    def _editedBindings(self):
        if getattr(self, '_v_ft', None) is not None:
            self._makeFunction()

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

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

        #__traceback_info__ = bound_names, args, kw, self.func_defaults

        ft = self._v_ft
        if ft is None:
            __traceback_supplement__ = (PythonScriptTracebackSupplement, self)
            raise RuntimeError, '%s %s has errors.' % (self.meta_type, self.id)

        fcode, g, fadefs = ft
        g = g.copy()
        if bound_names is not None:
            g.update(bound_names)
        g['__traceback_supplement__'] = (PythonScriptTracebackSupplement, self,
                                         -1)
        g['__file__'] = getattr(self, '_filepath', None) or self.get_filepath()
        f = new.function(fcode, g, None, fadefs)

        result = f(*args, **kw)
        if keyset is not None:
            # Store the result in the cache.
            self.ZCacheable_set(result, keywords=keyset)
        return result

    def manage_afterAdd(self, item, container):
        if item is self:
            self._filepath = self.get_filepath()

    def manage_beforeDelete(self, item, container):
        # shut up deprecation warnings
        pass

    def manage_afterClone(self, item):
        # shut up deprecation warnings
        pass

    def get_filepath(self):
        return self.meta_type + ':' + '/'.join(self.getPhysicalPath())

    def manage_haveProxy(self, r):
        return r in self._proxy_roles

    def _validateProxy(self, roles=None):
        if roles is None: roles = self._proxy_roles
        if not roles: return
        user = getSecurityManager().getUser()
        if user is not None and user.allowed(self, roles):
            return
        raise Forbidden, (
            'You are not authorized to change <em>%s</em> '
            'because you do not have proxy roles.\n<!--%s, %s-->' %
            (self.id, user, roles))

    security.declareProtected('Change proxy roles', 'manage_proxyForm',
                              'manage_proxy')

    manage_proxyForm = DTMLFile('www/pyScriptProxy', globals())

    @postonly
    def manage_proxy(self, roles=(), REQUEST=None):
        "Change Proxy Roles"
        self._validateProxy(roles)
        self._validateProxy()
        self.ZCacheable_invalidate()
        self._proxy_roles = tuple(roles)
        if REQUEST:
            return MessageDialog(title='Success!',
                                 message='Your changes have been saved',
                                 action='manage_main')

    security.declareProtected('Change Python Scripts', 'PUT', 'manage_FTPput',
                              'write', 'manage_historyCopy',
                              'manage_beforeHistoryCopy',
                              'manage_afterHistoryCopy')

    def PUT(self, REQUEST, RESPONSE):
        """ Handle HTTP PUT requests """
        self.dav__init(REQUEST, RESPONSE)
        self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1)
        self.write(REQUEST.get('BODY', ''))
        RESPONSE.setStatus(204)
        return RESPONSE

    manage_FTPput = PUT

    def write(self, text):
        """ Change the Script by parsing a read()-style source text. """
        self._validateProxy()
        mdata = self._metadata_map()
        bindmap = self.getBindingAssignments().getAssignedNames()
        bup = 0

        st = 0
        try:
            while 1:
                # Find the next non-empty line
                m = _nonempty_line.search(text, st)
                if not m:
                    # There were no non-empty body lines
                    body = ''
                    break
                line = m.group(0).strip()
                if line[:2] != '##':
                    # We have found the first line of the body
                    body = text[m.start(0):]
                    break

                st = m.end(0)
                # Parse this header line
                if len(line) == 2 or line[2] == ' ' or '=' not in line:
                    # Null header line
                    continue
                k, v = line[2:].split('=', 1)
                k = k.strip().lower()
                v = v.strip()
                if not mdata.has_key(k):
                    raise SyntaxError, 'Unrecognized header line "%s"' % line
                if v == mdata[k]:
                    # Unchanged value
                    continue

                # Set metadata value
                if k == 'title':
                    self.title = v
                elif k == 'parameters':
                    self._params = v
                elif k[:5] == 'bind ':
                    bindmap[_nice_bind_names[k[5:]]] = v
                    bup = 1

            body = body.rstrip()
            if body:
                body = body + '\n'
            if body != self._body:
                self._body = body
            if bup:
                self.ZBindings_edit(bindmap)
            else:
                self._makeFunction()
        except:
            LOG.error('write failed', exc_info=sys.exc_info())
            raise

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

    def _metadata_map(self):
        m = {
            'title': self.title,
            'parameters': self._params,
        }
        bindmap = self.getBindingAssignments().getAssignedNames()
        for k, v in _nice_bind_names.items():
            m['bind ' + k] = bindmap.get(v, '')
        return m

    def read(self):
        """ Generate a text representation of the Script source.

        Includes specially formatted comment lines for parameters,
        bindings, and the title.
        """
        # Construct metadata header lines, indented the same as the body.
        m = _first_indent.search(self._body)
        if m: prefix = m.group(0) + '##'
        else: prefix = '##'

        hlines = ['%s %s "%s"' % (prefix, self.meta_type, self.id)]
        mm = self._metadata_map().items()
        mm.sort()
        for kv in mm:
            hlines.append('%s=%s' % kv)
        if self.errors:
            hlines.append('')
            hlines.append(' Errors:')
            for line in self.errors:
                hlines.append('  ' + line)
        if self.warnings:
            hlines.append('')
            hlines.append(' Warnings:')
            for line in self.warnings:
                hlines.append('  ' + line)
        hlines.append('')
        return ('\n' + prefix).join(hlines) + '\n' + self._body

    def params(self):
        return self._params

    def body(self):
        return self._body

    def get_size(self):
        return len(self.read())

    getSize = get_size

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

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

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