コード例 #1
0
def manage_addActionForm(self):
    """Form for adding a new CMF Action object.
    """
    profiles = []

    stool = getToolByName(self, 'portal_setup', None)
    if stool:
        for info in stool.listContextInfos():
            action_paths = []
            context = stool._getImportContext(info['id'])
            body = context.readDataFile('actions.xml')
            if body is None:
                continue
            root = parseString(body).documentElement
            for node in root.childNodes:
                if node.nodeName != 'object':
                    continue
                action_paths += _extractChildren(node)
            action_paths.sort()
            profiles.append({
                'id': info['id'],
                'title': info['title'],
                'action_paths': tuple(action_paths)
            })

    template = PageTemplateResource('www/addAction.zpt',
                                    globals()).__of__(self)
    return template(profiles=tuple(profiles))
コード例 #2
0
def addConfiguredSiteForm(dispatcher):
    """ Wrap the PTF in 'dispatcher', including 'profile_registry' in options.
    """
    wrapped = PageTemplateResource( 'www/siteAddForm.zpt', globals()
                                  ).__of__( dispatcher )

    base_profiles = []
    extension_profiles = []

    for info in profile_registry.listProfileInfo():
        if info.get('type') == EXTENSION:
            extension_profiles.append(info)
        else:
            base_profiles.append(info)

    return wrapped( base_profiles=tuple(base_profiles),
                    extension_profiles =tuple(extension_profiles) )
コード例 #3
0
class CalendarTool (UniqueObject, SimpleItem):
    """ a calendar tool for encapsualting how calendars work and are displayed """
    id = 'portal_calendar'
    meta_type= 'CMF Calendar Tool'
    security = ClassSecurityInfo()

    calendar_types = ('Event',)
    calendar_states = ('published',)
    use_session = ''

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

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

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

    security.declareProtected( ManagePortal, 'edit_configuration' )
    def edit_configuration(self, show_types, use_session, show_states=None):
        """ Change the configuration of the calendar tool """
        self.calendar_types = tuple(show_types)
        self.use_session = use_session
        if show_states is not None:
            self.calendar_states = tuple(show_states)
        if hasattr(self.REQUEST, 'RESPONSE'):
            self.REQUEST.RESPONSE.redirect('manage_configure')

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

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

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

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

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

        return daysByWeek

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

        events=self.catalog_getevents(year, month)

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

            weeks.append(days)

        return weeks

    security.declarePublic('catalog_getevents')
    def catalog_getevents(self, year, month):
        """ given a year and month return a list of days that have events """
        year=int(year)
        month=int(month)
        last_day=calendar.monthrange(year, month)[1]
        first_date=self.getBeginAndEndTimes(1, month, year)[0]
        last_date=self.getBeginAndEndTimes(last_day, month, year)[1]

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

        # compile a list of the days that have events
        eventDays={}
        for daynumber in range(1, 32): # 1 to 31
            eventDays[daynumber] = {'eventslist':[], 'event':0, 'day':daynumber}
        includedevents = []
        for result in query:
            if result.getRID() in includedevents:
                break
            else:
                includedevents.append(result.getRID())
            event={}
            # we need to deal with events that end next month
            if  result.end.month() != month:
                # doesn't work for events that last ~12 months
                # fix it if it's a problem, otherwise ignore
                eventEndDay = last_day
                event['end'] = None
            else:
                eventEndDay = result.end.day()
                event['end'] = result.end.Time()
            # and events that started last month
            if result.start.month() != month:  # same as above re: 12 month thing
                eventStartDay = 1
                event['start'] = None
            else:
                eventStartDay = result.start.day()
                event['start'] = result.start.Time()

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

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

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

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

    security.declarePublic('getEventsForThisDay')
    def getEventsForThisDay(self, thisDay):
        """ given an exact day return ALL events that:
            A) Start on this day  OR
            B) End on this day  OR
            C) Start before this day  AND  end after this day"""

        catalog = self.portal_catalog
        day, month, year = ( int(thisDay.day())
                           , int(thisDay.month())
                           , int(thisDay.year())
                           )

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

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

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

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

        # Unique the results
        results = []
        rids = []
        for item in query:
            rid = item.getRID()
            if not rid in rids:
                results.append(item)
                rids.append(rid)

        def sort_function(x,y):
            z = cmp(x.start,y.start)
            if not z:
                return cmp(x.end,y.end)
            return z

        # Sort by start date
        results.sort(sort_function)

        return results

    security.declarePublic('getPreviousMonth')
    def getPreviousMonth(self, month, year):
        # given any particular year and month, this method will return a 
        # datetime object for one month prior

        try: month=int(month)
        except: raise "Calendar Type Error", month
        try: year=int(year)
        except: raise "Calendar Type Error", year

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

        return DateTime(year, month, 1)

    security.declarePublic('getNextMonth')
    def getNextMonth(self, month, year):
        # given any particular year and month, this method will return a datetime object
        # for one month after

        try: month=int(month)
        except: raise "Calendar Type Error", month
        try: year=int(year)
        except: raise "Calendar Type Error", year

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

        return DateTime(year, month, 1)

    security.declarePublic('getBeginAndEndTimes')
    def getBeginAndEndTimes(self, day, month, year):
        # Given any day, month and year this method returns 2 DateTime objects
        # That represent the exact start and the exact end of that particular day.

        day=int(day)
        month=int(month)
        year=int(year)

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

        return (begin, end)
コード例 #4
0
class WorkflowUIMixin:
    '''
    '''

    security = ClassSecurityInfo()

    security.declareProtected(ManagePortal, 'manage_properties')
    manage_properties = DTMLResource('dtml/workflow_properties', globals())
    manage_groups = PageTemplateResource('dtml/workflow_groups.pt', globals())

    security.declareProtected(ManagePortal, 'setProperties')
    def setProperties(self, title, manager_bypass=0, props=None, REQUEST=None):
        """Sets basic properties.
        """
        self.title = str(title)
        self.manager_bypass = manager_bypass and 1 or 0
        g = Guard()
        if g.changeFromProperties(props or REQUEST):
            self.creation_guard = g
        else:
            self.creation_guard = None
        if REQUEST is not None:
            return self.manage_properties(
                REQUEST, manage_tabs_message='Properties changed.')

    _permissions_form = DTMLResource('dtml/workflow_permissions', globals())

    security.declareProtected(ManagePortal, 'manage_permissions')
    def manage_permissions(self, REQUEST, manage_tabs_message=None):
        """Displays the form for choosing which permissions to manage.
        """
        return self._permissions_form(REQUEST,
                                      management_view='Permissions',
                                      manage_tabs_message=manage_tabs_message,
                                      )

    security.declareProtected(ManagePortal, 'addManagedPermission')
    def addManagedPermission(self, p, REQUEST=None):
        """Adds to the list of permissions to manage.
        """
        if p in self.permissions:
            raise ValueError, 'Already a managed permission: ' + p
        if REQUEST is not None and p not in self.getPossiblePermissions():
            raise ValueError, 'Not a valid permission name:' + p
        self.permissions = self.permissions + (p,)
        if REQUEST is not None:
            return self.manage_permissions(
                REQUEST, manage_tabs_message='Permission added.')

    security.declareProtected(ManagePortal, 'delManagedPermissions')
    def delManagedPermissions(self, ps, REQUEST=None):
        """Removes from the list of permissions to manage.
        """
        if ps:
            l = list(self.permissions)
            for p in ps:
                l.remove(p)
            self.permissions = tuple(l)
        if REQUEST is not None:
            return self.manage_permissions(
                REQUEST, manage_tabs_message='Permission(s) removed.')

    security.declareProtected(ManagePortal, 'getPossiblePermissions')
    def getPossiblePermissions(self):
        """Returns the list of all permissions that can be managed.
        """
        # possible_permissions is in AccessControl.Role.RoleManager.
        return list(self.possible_permissions())

    security.declareProtected(ManagePortal, 'getGroups')
    def getGroups(self):
        """Returns the names of groups managed by this workflow.
        """
        return tuple(self.groups)

    security.declareProtected(ManagePortal, 'getAvailableGroups')
    def getAvailableGroups(self):
        """Returns a list of available group names.
        """
        gf = aq_get( self, '__allow_groups__', None, 1 )
        if gf is None:
            return ()
        try:
            groups = gf.searchGroups()
        except AttributeError:
            return ()
        else:
            return [g['id'] for g in groups]

    security.declareProtected(ManagePortal, 'addGroup')
    def addGroup(self, group, RESPONSE=None):
        """Adds a group by name.
        """
        if group not in self.getAvailableGroups():
            raise ValueError(group)
        self.groups = self.groups + (group,)
        if RESPONSE is not None:
            RESPONSE.redirect(
                "%s/manage_groups?manage_tabs_message=Added+group."
                % self.absolute_url())

    security.declareProtected(ManagePortal, 'delGroups')
    def delGroups(self, groups, RESPONSE=None):
        """Removes groups by name.
        """
        self.groups = tuple([g for g in self.groups if g not in groups])
        if RESPONSE is not None:
            RESPONSE.redirect(
                "%s/manage_groups?manage_tabs_message=Groups+removed."
                % self.absolute_url())

    security.declareProtected(ManagePortal, 'getAvailableRoles')
    def getAvailableRoles(self):
        """Returns the acquired roles mixed with base_cms roles.
        """
        roles = list(self.valid_roles())
        for role in getDefaultRolePermissionMap().keys():
            if role not in roles:
                roles.append(role)
        roles.sort()
        return roles

    security.declareProtected(ManagePortal, 'getRoles')
    def getRoles(self):
        """Returns the list of roles managed by this workflow.
        """
        roles = self.roles
        if roles is not None:
            return roles
        roles = getDefaultRolePermissionMap().keys()
        if roles:
            # Map the base_cms roles by default.
            roles.sort()
            return roles
        return self.valid_roles()

    security.declareProtected(ManagePortal, 'setRoles')
    def setRoles(self, roles, RESPONSE=None):
        """Changes the list of roles mapped to groups by this workflow.
        """
        avail = self.getAvailableRoles()
        for role in roles:
            if role not in avail:
                raise ValueError(role)
        self.roles = tuple(roles)
        if RESPONSE is not None:
            RESPONSE.redirect(
                "%s/manage_groups?manage_tabs_message=Roles+changed."
                % self.absolute_url())

    security.declareProtected(ManagePortal, 'getGuard')
    def getGuard(self):
        """Returns the initiation guard.

        If no init guard has been created, returns a temporary object.
        """
        if self.creation_guard is not None:
            return self.creation_guard
        else:
            return Guard().__of__(self)  # Create a temporary guard.

    security.declarePublic('guardExprDocs')
    def guardExprDocs(self):
        """Returns documentation on guard expressions.
        """
        text = resource_string('doc/expressions.stx', globals())
        from DocumentTemplate.DT_Var import structured_text
        return structured_text(text)
コード例 #5
0
ファイル: workflow.py プロジェクト: bendavis78/zope
class WorkflowDefinitionConfigurator(Implicit):
    """ Synthesize XML description of site's workflows.
    """
    security = ClassSecurityInfo()

    def __init__(self, site):
        self._site = site

    security.declareProtected(ManagePortal, 'getWorkflowInfo')

    def getWorkflowInfo(self, workflow_id):
        """ Return a mapping describing a given workflow.

        o Keys in the mappings:

          'id' -- the ID of the workflow within the tool

          'meta_type' -- the workflow's meta_type

          'title' -- the workflow's title property

        o See '_extractDCWorkflowInfo' below for keys present only for
          DCWorkflow definitions.

        """
        workflow_tool = getToolByName(self._site, 'portal_workflow')
        workflow = workflow_tool.getWorkflowById(workflow_id)

        workflow_info = {
            'id': workflow_id,
            'meta_type': workflow.meta_type,
            'title': workflow.title_or_id()
        }

        if workflow.meta_type == DCWorkflowDefinition.meta_type:
            self._extractDCWorkflowInfo(workflow, workflow_info)

        return workflow_info

    security.declareProtected(ManagePortal, 'generateWorkflowXML')

    def generateWorkflowXML(self, workflow_id):
        """ Pseudo API.
        """
        info = self.getWorkflowInfo(workflow_id)

        if info['meta_type'] != DCWorkflowDefinition.meta_type:
            return None

        return self._workflowConfig(workflow_id=workflow_id)

    security.declareProtected(ManagePortal, 'generateWorkflowScripts')

    def getWorkflowScripts(self, workflow_id):
        """ Get workflow scripts inforation
        """
        workflow_tool = getToolByName(self._site, 'portal_workflow')
        workflow = workflow_tool.getWorkflowById(workflow_id)

        if workflow.meta_type != DCWorkflowDefinition.meta_type:
            return []

        scripts = self._extractScripts(workflow)
        return scripts

    security.declareProtected(ManagePortal, 'parseWorkflowXML')

    def parseWorkflowXML(self, xml, encoding=None):
        """ Pseudo API.
        """
        dom = domParseString(xml)

        root = dom.getElementsByTagName('dc-workflow')[0]

        workflow_id = _getNodeAttribute(root, 'workflow_id', encoding)
        title = _getNodeAttribute(root, 'title', encoding)
        state_variable = _getNodeAttribute(root, 'state_variable', encoding)
        initial_state = _getNodeAttribute(root, 'initial_state', encoding)

        states = _extractStateNodes(root, encoding)
        transitions = _extractTransitionNodes(root, encoding)
        variables = _extractVariableNodes(root, encoding)
        worklists = _extractWorklistNodes(root, encoding)
        permissions = _extractPermissionNodes(root, encoding)
        scripts = _extractScriptNodes(root, encoding)

        return (workflow_id, title, state_variable, initial_state, states,
                transitions, variables, worklists, permissions, scripts)

    security.declarePrivate('_workflowConfig')
    _workflowConfig = PageTemplateResource('xml/wtcWorkflowExport.xml',
                                           globals(),
                                           __name__='workflowConfig')

    security.declarePrivate('_extractDCWorkflowInfo')

    def _extractDCWorkflowInfo(self, workflow, workflow_info):
        """ Append the information for a 'workflow' into 'workflow_info'

        o 'workflow' must be a DCWorkflowDefinition instance.

        o 'workflow_info' must be a dictionary.

        o The following keys will be added to 'workflow_info':

          'permissions' -- a list of names of permissions managed
            by the workflow

          'state_variable' -- the name of the workflow's "main"
            state variable

          'initial_state' -- the name of the state in the workflow
            in which objects start their lifecycle.

          'variable_info' -- a list of mappings describing the
            variables tracked by the workflow (see '_extractVariables').

          'state_info' -- a list of mappings describing the
            states tracked by the workflow (see '_extractStates').

          'transition_info' -- a list of mappings describing the
            transitions tracked by the workflow (see '_extractTransitions').

          'worklist_info' -- a list of mappings describing the
            worklists tracked by the workflow (see '_extractWorklists').

          'script_info' -- a list of mappings describing the scripts which
            provide added business logic (wee '_extractScripts').
        """
        workflow_info['filename'] = _getWorkflowFilename(workflow.getId())
        workflow_info['state_variable'] = workflow.state_var
        workflow_info['initial_state'] = workflow.initial_state
        workflow_info['permissions'] = workflow.permissions
        workflow_info['variable_info'] = self._extractVariables(workflow)
        workflow_info['state_info'] = self._extractStates(workflow)
        workflow_info['transition_info'] = self._extractTransitions(workflow)
        workflow_info['worklist_info'] = self._extractWorklists(workflow)
        workflow_info['script_info'] = self._extractScripts(workflow)

    security.declarePrivate('_extractVariables')

    def _extractVariables(self, workflow):
        """ Return a sequence of mappings describing DCWorkflow variables.

        o Keys for each mapping will include:

          'id' -- the variable's ID

          'description' -- a textual description of the variable

          'for_catalog' -- whether to catalog this variable

          'for_status' -- whether to ??? this variable (XXX)

          'update_always' -- whether to update this variable whenever
            executing a transition (xxX)

          'default_value' -- a default value for the variable (XXX)

          'default_expression' -- a TALES expression for the default value

          'guard_permissions' -- a list of permissions guarding access
            to the variable

          'guard_roles' -- a list of roles guarding access
            to the variable

          'guard_groups' -- a list of groups guarding the transition

          'guard_expr' -- an expression guarding access to the variable
        """
        result = []

        items = workflow.variables.objectItems()
        items.sort()

        for k, v in items:

            guard = v.getInfoGuard()

            default_type = _guessVariableType(v.default_value)

            info = {
                'id': k,
                'description': v.description,
                'for_catalog': bool(v.for_catalog),
                'for_status': bool(v.for_status),
                'update_always': bool(v.update_always),
                'default_value': v.default_value,
                'default_type': default_type,
                'default_expr': v.getDefaultExprText(),
                'guard_permissions': guard.permissions,
                'guard_roles': guard.roles,
                'guard_groups': guard.groups,
                'guard_expr': guard.getExprText()
            }

            result.append(info)

        return result

    security.declarePrivate('_extractStates')

    def _extractStates(self, workflow):
        """ Return a sequence of mappings describing DCWorkflow states.

        o Within the workflow mapping, each 'state_info' mapping has keys:

          'id' -- the state's ID

          'title' -- the state's title

          'description' -- the state's description

          'transitions' -- a list of IDs of transitions out of the state

          'permissions' -- a list of mappings describing the permission
            map for the state

          'groups' -- a list of ( group_id, (roles,) ) tuples describing the
            group-role assignments for the state

          'variables' -- a list of mapping for the variables
            to be set when entering the state.

        o Within the state_info mappings, each 'permissions' mapping
          has the keys:

          'name' -- the name of the permission

          'roles' -- a sequence of role IDs which have the permission

          'acquired' -- whether roles are acquired for the permission

        o Within the state_info mappings, each 'variable' mapping
          has the keys:

          'name' -- the name of the variable

          'type' -- the type of the value (allowed values are:
                    'string', 'datetime', 'bool', 'int')

          'value' -- the value to be set
        """
        result = []

        items = workflow.states.objectItems()
        items.sort()

        for k, v in items:

            groups = v.group_roles and list(v.group_roles.items()) or []
            groups = [x for x in groups if x[1]]
            groups.sort()

            variables = list(v.getVariableValues())
            variables.sort()

            v_info = []

            for v_name, value in variables:
                v_info.append({
                    'name': v_name,
                    'type': _guessVariableType(value),
                    'value': value
                })

            info = {
                'id': k,
                'title': v.title,
                'description': v.description,
                'transitions': v.transitions,
                'permissions': self._extractStatePermissions(v),
                'groups': groups,
                'variables': v_info
            }

            result.append(info)

        return result

    security.declarePrivate('_extractStatePermissions')

    def _extractStatePermissions(self, state):
        """ Return a sequence of mappings for the permissions in a state.

        o Each mapping has the keys:

          'name' -- the name of the permission

          'roles' -- a sequence of role IDs which have the permission

          'acquired' -- whether roles are acquired for the permission
        """
        result = []

        items = state.permission_roles.items()
        items.sort()

        for k, v in items:

            result.append({
                'name': k,
                'roles': v,
                'acquired': not isinstance(v, tuple)
            })

        return result

    security.declarePrivate('_extractTransitions')

    def _extractTransitions(self, workflow):
        """ Return a sequence of mappings describing DCWorkflow transitions.

        o Each mapping has the keys:

          'id' -- the transition's ID

          'title' -- the transition's ID

          'description' -- the transition's description

          'new_state_id' -- the ID of the state into which the transition
            moves an object

          'trigger_type' -- one of the following values, indicating how the
            transition is fired:

            - "AUTOMATIC" -> fired opportunistically whenever the workflow
               notices that its guard conditions permit

            - "USER" -> fired in response to user request

          'script_name' -- the ID of a script to be executed before
             the transition

          'after_script_name' -- the ID of a script to be executed after
             the transition

          'actbox_name' -- the name of the action by which the user
             triggers the transition

          'actbox_url' -- the URL of the action by which the user
             triggers the transition

          'actbox_category' -- the category of the action by which the user
             triggers the transition

          'variables' -- a list of ( id, expr ) tuples defining how variables
            are to be set during the transition

          'guard_permissions' -- a list of permissions guarding the transition

          'guard_roles' -- a list of roles guarding the transition

          'guard_groups' -- a list of groups guarding the transition

          'guard_expr' -- an expression guarding the transition

        """
        result = []

        items = workflow.transitions.objectItems()
        items.sort()

        for k, v in items:

            guard = v.getGuard()

            v_info = []

            for v_name, expr in v.getVariableExprs():
                v_info.append({'name': v_name, 'expr': expr})

            info = {
                'id': k,
                'title': v.title,
                'description': v.description,
                'new_state_id': v.new_state_id,
                'trigger_type': TRIGGER_TYPES[v.trigger_type],
                'script_name': v.script_name,
                'after_script_name': v.after_script_name,
                'actbox_name': v.actbox_name,
                'actbox_url': v.actbox_url,
                'actbox_category': v.actbox_category,
                'variables': v_info,
                'guard_permissions': guard.permissions,
                'guard_roles': guard.roles,
                'guard_groups': guard.groups,
                'guard_expr': guard.getExprText()
            }

            result.append(info)

        return result

    security.declarePrivate('_extractWorklists')

    def _extractWorklists(self, workflow):
        """ Return a sequence of mappings describing DCWorkflow transitions.

        o Each mapping has the keys:

          'id' -- the ID of the worklist

          'title' -- the title of the worklist

          'description' -- a textual description of the worklist

          'var_match' -- a list of ( key, value ) tuples defining
            the variables used to "activate" the worklist.

          'actbox_name' -- the name of the "action" corresponding to the
            worklist

          'actbox_url' -- the URL of the "action" corresponding to the
            worklist

          'actbox_category' -- the category of the "action" corresponding
            to the worklist

          'guard_permissions' -- a list of permissions guarding access
            to the worklist

          'guard_roles' -- a list of roles guarding access
            to the worklist

          'guard_expr' -- an expression guarding access to the worklist

        """
        result = []

        items = workflow.worklists.objectItems()
        items.sort()

        for k, v in items:

            guard = v.getGuard()

            var_match = [(id, v.getVarMatchText(id))
                         for id in v.getVarMatchKeys()]

            info = {
                'id': k,
                'title': v.title,
                'description': v.description,
                'var_match': var_match,
                'actbox_name': v.actbox_name,
                'actbox_url': v.actbox_url,
                'actbox_category': v.actbox_category,
                'guard_permissions': guard.permissions,
                'guard_roles': guard.roles,
                'guard_groups': guard.groups,
                'guard_expr': guard.getExprText()
            }

            result.append(info)

        return result

    security.declarePrivate('_extractScripts')

    def _extractScripts(self, workflow):
        """ Return a sequence of mappings describing DCWorkflow scripts.

        o Each mapping has the keys:

          'id' -- the ID of the script

          'meta_type' -- the title of the worklist

          'body' -- the text of the script

          'filename' -- the name of the file to / from which the script
            is stored / loaded
        """
        result = []

        items = workflow.scripts.objectItems()
        items.sort()

        for k, v in items:

            filename = _getScriptFilename(workflow.getId(), k, v.meta_type)

            info = {
                'id': k,
                'meta_type': v.meta_type,
                'body': v.read(),
                'filename': filename
            }

            result.append(info)

        return result
コード例 #6
0
ファイル: workflow.py プロジェクト: bendavis78/zope
    def _getExportTemplate(self):

        return PageTemplateResource('xml/wtcToolExport.xml', globals())
コード例 #7
0
        """ List the actions defined in this category and its subcategories.
        """
        actions = []

        for obj in self.objectValues():
            if IActionCategory.providedBy(obj):
                actions.extend(obj.listActions())
            elif IAction.providedBy(obj):
                actions.append(obj)

        return tuple(actions)


InitializeClass(ActionCategory)

manage_addActionCategoryForm = PageTemplateResource(
    'www/addActionCategory.zpt', globals())


def manage_addActionCategory(self, id, REQUEST=None):
    """Add a new CMF Action Category object with ID *id*.
    """
    obj = ActionCategory(id)
    self._setObject(id, obj)

    if REQUEST:
        return self.manage_main(self, REQUEST, update_menu=1)


class Action(SimpleItemWithProperties):
    """ Reference to an action.
    """
コード例 #8
0
ファイル: ActionIconsTool.py プロジェクト: bendavis78/zope
class ActionIconsTool(UniqueObject, SimpleItem):
    """ Map actions only icons.
    """
    meta_type = 'Action Icons Tool'
    id = 'portal_actionicons'

    security = ClassSecurityInfo()
    security.declareObjectProtected(View)

    def __init__(self):

        self.clearActionIcons()

    #
    #   Accessors
    #
    security.declareProtected(ManagePortal, 'listActionIcons')

    def listActionIcons(self):
        """ Return a sequence of mappings for action icons

        o Mappings are in the form: ( category, action ) -> icon,
          where category and action are strings and icon is an ActionIcon
          instance.
        """
        return [x.__of__(self) for x in self._icons]

    security.declareProtected(View, 'getActionInfo')

    def getActionInfo(self, category, action_id, context=None):
        """ Return a tuple, '(title, priority, icon ID), for the given action.

        o Raise a KeyError if no icon has been defined for the action.
        """
        ai = self._lookup[(category, action_id)]
        return (ai.getTitle(), ai.getPriority(), ai.getIconURL(context))

    security.declareProtected(View, 'queryActionInfo')

    def queryActionInfo(self, category, action_id, default=None, context=None):
        """ Return a tuple, '(title, priority, icon ID), for the given action.

        o Return 'default' if no icon has been defined for the action.
        """
        ai = self._lookup.get((category, action_id))
        return ai and (ai.getTitle(), ai.getPriority(),
                       ai.getIconURL(context)) or default

    security.declareProtected(View, 'getActionIcon')

    def getActionIcon(self, category, action_id, context=None):
        """ Return an icon ID for the given action.

        o Raise a KeyError if no icon has been defined for the action.

        o Context is an Expression context object, used to evaluate
          TALES expressions.
        """
        return self._lookup[(category, action_id)].getIconURL(context)

    security.declareProtected(View, 'queryActionIcon')

    def queryActionIcon(self, category, action_id, default=None, context=None):
        """ Return an icon ID for the given action.

        o Return 'default' if no icon has been defined for the action.

        o Context is an Expression context object, used to evaluate
          TALES expressions.
        """
        ai = self._lookup.get((category, action_id))
        return ai and ai.getIconURL(context) or default

    security.declareProtected(View, 'updateActionDicts')

    def updateActionDicts(self, categorized_actions, context=None):
        """ Update a set of dictionaries, adding 'title, 'priority', and
            'icon' keys.

        o S.b. passed a data structure like that returned from ActionsTool's
          'listFilteredActionsFor':

          - Dict mapping category -> seq. of dicts, where each of the
            leaf dicts must have 'category' and 'id' keys.

        o *Will* overwrite the 'title' key, if title is defined on the tool.

        o *Will* overwrite the 'priority' key.

        o *Will* overwrite the 'icon' key, if icon is defined on the tool

        o XXX:  Don't have a way to pass Expression context yet.
        """
        result = {}

        for category, actions in categorized_actions.items():

            new_actions = []

            for action in actions:

                action = action.copy()

                action_id = action.get('id')

                #  Hack around DCWorkflow's ID-less worklist actions.
                if action_id is None and action.get('category') == 'workflow':
                    action['id'] = action_id = action.get('name')

                if action_id:

                    info = self.queryActionInfo(category,
                                                action_id,
                                                context=context)
                    if info is not None:

                        title, priority, icon = info

                        if title is not None:
                            action['title'] = title

                        if priority is not None:
                            action['priority'] = priority

                        if icon is not None:
                            action['icon'] = icon

                new_actions.append(action)

            new_actions.sort(
                lambda x, y: cmp(x.get('priority', 0), y.get('priority', 0)))
            result[category] = new_actions

        return result

    __call__ = updateActionDicts

    #
    #   Mutators
    #
    security.declareProtected(ManagePortal, 'addActionIcon')

    def addActionIcon(self,
                      category,
                      action_id,
                      icon_expr,
                      title=None,
                      priority=0):
        """ Add an icon for the given action.

        o Raise KeyError if an icon has already been defined.
        """
        if self.queryActionInfo(category, action_id) is not None:
            raise KeyError, 'Duplicate definition!'

        icons = list(self._icons)
        icons.append(
            ActionIcon(category, action_id, icon_expr, title, priority))
        self._lookup[(category, action_id)] = icons[-1]
        self._icons = tuple(icons)

    security.declareProtected(ManagePortal, 'updateActionIcon')

    def updateActionIcon(self,
                         category,
                         action_id,
                         icon_expr,
                         title=None,
                         priority=0):
        """ Update the icon for the given action.

        o Raise KeyError if an icon has not already been defined.
        """
        if self._lookup.get((category, action_id)) is None:
            raise KeyError, 'No such definition!'

        icons = list(self._icons)
        for ai in icons:
            if (ai.getCategory() == category
                    and ai.getActionId() == action_id):
                ai.updateIconExpression(icon_expr)
                ai._title = title
                ai._priority = priority
                break
        else:
            raise KeyError, (category, action_id)
        self._icons = tuple(icons)

    security.declareProtected(ManagePortal, 'removeActionIcon')

    def removeActionIcon(self, category, action_id):
        """ Remove the icon for the given action.

        o Raise KeyError if an icon has not already been defined.
        """
        if self.queryActionInfo(category, action_id) is None:
            raise KeyError, 'No such definition (%s, %s)!' % (category,
                                                              action_id)

        icons = list(self._icons)
        icon = self._lookup[(category, action_id)]
        icons.remove(icon)
        del self._lookup[(category, action_id)]
        self._icons = tuple(icons)

    security.declareProtected(ManagePortal, 'clearActionIcons')

    def clearActionIcons(self):
        """ Remove all mappings from the tool.
        """
        self._icons = ()
        self._lookup = {}

    #
    #   ZMI
    #
    manage_options = ({
        'label': 'Icons',
        'action': 'manage_editActionIcons'
    }, ) + SimpleItem.manage_options

    security.declareProtected(ManagePortal, 'manage_editActionIcons')
    manage_editActionIcons = PageTemplateResource('www/aitEdit.zpt', globals())

    security.declareProtected(ManagePortal, 'manage_addActionIcon')

    def manage_addActionIcon(self, category, action_id, icon_expr, title,
                             priority, REQUEST):
        """ Add an icon for the given action via the ZMI.
        """
        self.addActionIcon(category, action_id, icon_expr, title, priority)

        REQUEST['RESPONSE'].redirect('%s/manage_editActionIcons'
                                     '?manage_tabs_message=Action+added.' %
                                     self.absolute_url())

    security.declareProtected(ManagePortal, 'manage_updateActionIcon')

    def manage_updateActionIcon(self, category, action_id, icon_expr, title,
                                priority, REQUEST):
        """ Update an icon for the given action via the ZMI.
        """
        self.updateActionIcon(category, action_id, icon_expr, title, priority)

        REQUEST['RESPONSE'].redirect('%s/manage_editActionIcons'
                                     '?manage_tabs_message=Action+updated.' %
                                     self.absolute_url())

    security.declareProtected(ManagePortal, 'manage_removeActionIcon')

    def manage_removeActionIcon(self, category, action_id, REQUEST):
        """ Remove the icon for the given action via the ZMI.
        """
        self.removeActionIcon(category, action_id)

        REQUEST['RESPONSE'].redirect('%s/manage_editActionIcons'
                                     '?manage_tabs_message=Action+removed.' %
                                     self.absolute_url())
コード例 #9
0
class UniqueIdHandlerTool(UniqueObject, SimpleItem, ActionProviderBase):

    __doc__ = __doc__ # copy from module

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

    id = 'portal_uidhandler'

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

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

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

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

    security = ClassSecurityInfo()

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

        # reindex
        catalog.reindexObject(obj)

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

        # reindex the object
        self._reindexObject(obj)

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

        return uid

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

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

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

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

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

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

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

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

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

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

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

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

        return result[0]

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

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

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

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

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

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

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

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

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

    security.declareProtected(ManagePortal, 'manage_queryObject')
    manage_queryObject = PageTemplateResource('www/queryUID.pt', globals())
コード例 #10
0
ファイル: utils.py プロジェクト: bendavis78/zope
class ExportConfiguratorBase(Implicit):
    """ Synthesize XML description.
    """
    security = ClassSecurityInfo()
    security.setDefaultAccess('allow')

    def __init__(self, site, encoding=None):

        self._site = site
        self._encoding = encoding
        self._template = self._getExportTemplate()

    security.declareProtected(ManagePortal, 'generateXML')

    def generateXML(self, **kw):
        """ Pseudo API.
        """
        return self._template(**kw)

    #
    #   generic object and property support
    #
    _ob_nodes = PageTemplateResource('xml/object_nodes.xml', globals())
    _prop_nodes = PageTemplateResource('xml/property_nodes.xml', globals())

    security.declareProtected(ManagePortal, 'generateObjectNodes')

    def generateObjectNodes(self, obj_infos):
        """ Pseudo API.
        """
        lines = self._ob_nodes(objects=obj_infos).splitlines()
        return '\n'.join(lines)

    security.declareProtected(ManagePortal, 'generatePropertyNodes')

    def generatePropertyNodes(self, prop_infos):
        """ Pseudo API.
        """
        lines = self._prop_nodes(properties=prop_infos).splitlines()
        return '\n'.join(lines)

    def _extractObject(self, obj):

        properties = []
        subobjects = []
        i18n_domain = getattr(obj, 'i18n_domain', None)

        if getattr(aq_base(obj), '_propertyMap'):
            for prop_map in obj._propertyMap():
                prop_info = self._extractProperty(obj, prop_map)
                if i18n_domain and prop_info['id'] in ('title', 'description'):
                    prop_info['i18ned'] = ''
                if prop_info['id'] != 'i18n_domain':
                    properties.append(prop_info)

        if getattr(aq_base(obj), 'objectValues'):
            for sub in obj.objectValues():
                subobjects.append(self._extractObject(sub))

        return {
            'id': obj.getId(),
            'meta_type': obj.meta_type,
            'i18n_domain': i18n_domain or None,
            'properties': tuple(properties),
            'subobjects': tuple(subobjects)
        }

    def _extractProperty(self, obj, prop_map):

        prop_id = prop_map['id']
        prop = obj.getProperty(prop_id)

        if isinstance(prop, tuple):
            prop_value = ''
            prop_elements = prop
        elif isinstance(prop, list):
            # Backward compat for old instances that stored
            # properties as list.
            prop_value = ''
            prop_elements = tuple(prop)
        else:
            prop_value = prop
            prop_elements = ()

        if 'd' in prop_map.get('mode', 'wd') and not prop_id == 'title':
            type = prop_map.get('type', 'string')
            select_variable = prop_map.get('select_variable', None)
        else:
            type = None
            select_variable = None

        return {
            'id': prop_id,
            'value': prop_value,
            'elements': prop_elements,
            'type': type,
            'select_variable': select_variable
        }
コード例 #11
0
ファイル: States.py プロジェクト: bendavis78/zope
class StateDefinition(SimpleItem):
    """State definition"""

    meta_type = 'Workflow State'

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

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

    security = ClassSecurityInfo()
    security.declareObjectProtected(ManagePortal)

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

    def getId(self):
        return self.id

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

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

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

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

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

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

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

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

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

    _properties_form = DTMLResource('dtml/state_properties', globals())

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

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

    _variables_form = DTMLResource('dtml/state_variables', globals())

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

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

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

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

        self.var_values[id] = value

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

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

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

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

        vv = self.var_values

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

    _permissions_form = DTMLResource('dtml/state_permissions', globals())

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

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

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

    manage_groups = PageTemplateResource('dtml/state_groups.pt', globals())

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