[Zope3-checkins] CVS: Zope3/src/zope/app/browser/workflow/stateful - definition_edit.pt:1.1 testobject.zcml:1.1 configure.zcml:1.4 definition.py:1.5 instance.py:1.6 instance_manage.pt:1.4

Stephan Richter srichter@cosmos.phy.tufts.edu
Thu, 31 Jul 2003 11:02:03 -0400


Update of /cvs-repository/Zope3/src/zope/app/browser/workflow/stateful
In directory cvs.zope.org:/tmp/cvs-serv10755/src/zope/app/browser/workflow/stateful

Modified Files:
	configure.zcml definition.py instance.py instance_manage.pt 
Added Files:
	definition_edit.pt testobject.zcml 
Log Message:
Implemented relevant data for Processes (read workflows). You can specify
a schema which contains the fields that should be available as relevant 
data. Once the schema is set, you are able to specify "get" and "set" 
permissions for each field. That;s it for the setup.

When you then create a Content Object that uses the process definition for
which you declared the schema, you will see that there is a form in the 
'Workflows' tab of this content object that allows you to manipulate the
releavant data.

I also enhanced the XML Import/Export to support relevant data and their 
permissions. 

The easiest way to check all this functionality out is to uncomment the 
include directives in browser/workflow/stateful/configure.zcml and 
workflow/stateful/configure.zcml (both at the end of the file).

This completes my code and status review of the workflow package, which I
think is now ready for the beta.


=== Added File Zope3/src/zope/app/browser/workflow/stateful/definition_edit.pt ===
<html metal:use-macro="views/standard_macros/page">
 
  <head>
    <title>Process Definition <-> Content Type Registry</title>
  </head>
 
  <body><div metal:fill-slot="body">
 
    <p tal:define="status view/update"
       tal:condition="status"
       tal:content="status" />

    <form action="./@@edit.html" method="POST">
      <h3>Set Workflow-Relevant Data Schema</h3>
      <div class="row" 
           tal:content="structure view/relevantDataSchema_widget/row" />
      <div class="row">
        <div class="controls" style="width: 100%"> 
          <input type="submit" value="Refresh" 
              i18n:attributes="value refresh-button" />
          <input type="submit" value="Set Schema" name="UPDATE_SUBMIT" />
         </div>
      </div>

      <tal:block define="widgets view/getPermissionWidgets"
                 condition="widgets">
        <h3>Map permissions to Schema fields</h3>
  
        <tal:block repeat="widget widgets">
          <h5 tal:content="string:${widget/fieldName} (${widget/fieldName})">
            FieldName (Field Title)
          </h5>
          <div class="row" tal:replace="structure widget/getter/row">
            <div class="label">Get Permission</div>
            <div class="field">
    
            </div>
          </div>
          <div class="row" tal:replace="structure widget/setter/row">
            <div class="label">Set Permission</div>
            <div class="field">
    
            </div>
          </div>
        </tal:block>
        <div class="row">
          <div class="controls" style="width: 100%"> 
            <input type="submit" value="Refresh" 
                i18n:attributes="value refresh-button" />
            <input type="submit" value="Change" name="CHANGE" />
           </div>
        </div>
      </tal:block>

    </form>
 
  </div></body>
 
</html>

=== Added File Zope3/src/zope/app/browser/workflow/stateful/testobject.zcml ===
<zopeConfigure
   xmlns="http://namespaces.zope.org/zope"
   xmlns:browser="http://namespaces.zope.org/browser">

  <browser:addform
      label="Add Test Object"
      name="AddTestObject"
      schema="zope.app.workflow.stateful.testobject.ITestObject"
      content_factory="zope.app.workflow.stateful.testobject.TestObject"
      permission="zope.ManageContent"
      menu="add_content" title="Test Object"/>

  <browser:editform
      schema="zope.app.workflow.stateful.testobject.ITestObject"
      for="zope.app.workflow.stateful.testobject.ITestObject"
      label="Change Test Object"
      name="edit.html"
      permission="zope.ManageContent"
      menu="zmi_views" title="Edit" />

</zopeConfigure>


=== Zope3/src/zope/app/browser/workflow/stateful/configure.zcml 1.3 => 1.4 ===
--- Zope3/src/zope/app/browser/workflow/stateful/configure.zcml:1.3	Tue Jul 29 20:00:16 2003
+++ Zope3/src/zope/app/browser/workflow/stateful/configure.zcml	Thu Jul 31 11:01:26 2003
@@ -19,21 +19,22 @@
   "zope.app.browser.workflow.stateful.definition.StatefulProcessDefinitionView"
   permission="zope.ManageServices">
 
-  <browser:page name="index.html" template="definition_index.pt" />
+  <browser:page name="index.html" template="definition_index.pt"/>
 
 </browser:pages>
 
 <browser:editform
   schema="zope.app.interfaces.workflow.stateful.IStatefulProcessDefinition"
   name="edit.html"
-  menu="zmi_views"
-  label="Edit a Stateful ProcessDefinition"
+  template="definition_edit.pt"
+  class=".definition.RelevantDataSchemaEdit"
+  menu="zmi_views" title="Relevant Data Schema"
   permission="zope.workflow.ManageProcessDefinitions"
   />
 
 <browser:menuItems
-  for="zope.app.interfaces.workflow.stateful.IStatefulProcessDefinition"
-  menu="zmi_actions">
+    for="zope.app.interfaces.workflow.stateful.IStatefulProcessDefinition"
+    menu="zmi_actions">
   
   <browser:menuItem 
       title="Manage States" action="states/contents.html" />
@@ -162,17 +163,11 @@
   permission="zope.workflow.UseProcessInstances"
   class="zope.app.browser.workflow.stateful.instance.ManagementView">
 
-  <browser:page name="workflows.html" attribute="contents" />
+  <browser:page name="workflows.html" template="instance_manage.pt"
+                menu="zmi_views" title="Workflows"/>
   <browser:page name="fireTransition.html" attribute="fireTransition" />
 </browser:pages>
 
-<browser:menuItem
-  for="zope.app.interfaces.workflow.IProcessInstanceContainerAdaptable"
-  menu="zmi_views"
-  title="Workflows"
-  action="workflows.html"
-  />
-
 
 <browser:pages
   for="zope.app.interfaces.container.IContentContainer"
@@ -183,12 +178,14 @@
 </browser:pages>
 
 
-<!-- uhm .. this seems to be to generic in its definition
-     and not really nice as well .. -->
+<!-- uhm ... this seems to be too generic in its definition
+     and not really nice as well. -->
 <adapter
     factory=".filteradapter.FilterAdapter"
     provides=".interfaces.IContentFilterAdapter"
     for="zope.app.interfaces.annotation.IAttributeAnnotatable"
     permission="zope.View" />       <!-- XXX is this permission right? -->
+
+<!--include file="testobject.zcml"/-->
 
 </zopeConfigure>


=== Zope3/src/zope/app/browser/workflow/stateful/definition.py 1.4 => 1.5 ===
--- Zope3/src/zope/app/browser/workflow/stateful/definition.py:1.4	Sat Jun 21 17:22:08 2003
+++ Zope3/src/zope/app/browser/workflow/stateful/definition.py	Thu Jul 31 11:01:27 2003
@@ -21,18 +21,22 @@
 from zope.publisher.browser import BrowserView
 from zope.app.browser.container.adding import Adding
 from zope.app.browser.form.submit import Update
+from zope.app.browser.form.editview import EditView
 from zope.app.workflow.stateful.definition import State, Transition
+from zope.schema import getFields
 
+from zope.app.security.permission import PermissionField
+from zope.security.checker import CheckerPublic
+from zope.security.proxy import trustedRemoveSecurityProxy
+from zope.app.form.utility import setUpWidget
 
 class StatesContainerAdding(Adding):
-    """Custom adding view for StatesContainer objects.
-    """
+    """Custom adding view for StatesContainer objects."""
     menu_id = "add_stateful_states"
 
 
 class TransitionsContainerAdding(Adding):
-    """Custom adding view for TransitionsContainer objects.
-    """
+    """Custom adding view for TransitionsContainer objects."""
     menu_id = "add_stateful_transitions"
 
     def getProcessDefinition(self):
@@ -41,14 +45,13 @@
 
 # XXX Temporary ...
 class StateAddFormHelper:
-
     # XXX Hack to prevent from displaying an empty addform
     def __call__(self, template_usage=u'', *args, **kw):
         if not len(self.fieldNames):
             self.request.form[Update] = 'submitted'
             return self.update()
-        return super(StateAddFormHelper, self).__call__(template_usage, *args, **kw)
-
+        return super(StateAddFormHelper, self).__call__(template_usage,
+                                                        *args, **kw)
 
 
 class StatefulProcessDefinitionView(BrowserView):
@@ -57,6 +60,69 @@
         return """I'm a stateful ProcessInstance"""
 
 
+class RelevantDataSchemaEdit(EditView):
+
+    def __init__(self, context, request):
+        super(RelevantDataSchemaEdit, self).__init__(context, request)
+        self.buildPermissionWidgets()
+
+    def buildPermissionWidgets(self):
+        schema = self.context.relevantDataSchema
+        if schema is not None:
+            for name, field in getFields(schema).items():
+                # Try to get current settings
+                if self.context.schemaPermissions.has_key(name):
+                    get_perm, set_perm = self.context.schemaPermissions[name]
+                else:
+                    get_perm, set_perm = None, None
+
+                # Create the Accessor Permission Widget for this field
+                permField = PermissionField(
+                    __name__=name+'_get_perm',
+                    title=u"Accessor Permission",
+                    default=CheckerPublic,
+                    required=False)
+                setUpWidget(self, name+'_get_perm', permField, value=get_perm)
+
+                # Create the Mutator Permission Widget for this field
+                permField = PermissionField(
+                    __name__=name+'_set_perm',
+                    title=u"Mutator Permission",
+                    default=CheckerPublic,
+                    required=False)
+                setUpWidget(self, name+'_set_perm', permField, value=set_perm)
+
+    def update(self):
+        status = ''
+
+        if Update in self.request:
+            status = super(RelevantDataSchemaEdit, self).update()
+            self.buildPermissionWidgets()
+        elif 'CHANGE' in self.request:
+            schema = self.context.relevantDataSchema
+            perms = trustedRemoveSecurityProxy(self.context.schemaPermissions)
+            for name, field in getFields(schema).items():
+                getPerm = getattr(self, name+'_get_perm_widget').getData()
+                setPerm = getattr(self, name+'_set_perm_widget').getData()
+                perms[name] = (getPerm, setPerm)
+            status = 'Fields permissions mapping updated.'
+
+        return status
+
+    def getPermissionWidgets(self):
+        schema = self.context.relevantDataSchema
+        if schema is None:
+            return None
+        info = []
+        for name, field in getFields(schema).items():
+            field = trustedRemoveSecurityProxy(field)
+            info.append(
+                {'fieldName': name,
+                 'fieldTitle': field.title,
+                 'getter': getattr(self, name+'_get_perm_widget'),
+                 'setter': getattr(self, name+'_set_perm_widget')} )
+        return info
+        
 
 class AddState(BrowserView):
 
@@ -68,6 +134,7 @@
 
 class AddTransition(BrowserView):
 
+    # XXX This could and should be handled by a Vocabulary Field/Widget 
     def getStateNames(self):
         pd = self.context.getProcessDefinition()
         states = removeAllProxies(pd.getStateNames())


=== Zope3/src/zope/app/browser/workflow/stateful/instance.py 1.5 => 1.6 ===
--- Zope3/src/zope/app/browser/workflow/stateful/instance.py:1.5	Tue Jun  3 18:46:18 2003
+++ Zope3/src/zope/app/browser/workflow/stateful/instance.py	Thu Jul 31 11:01:27 2003
@@ -17,6 +17,8 @@
 """
 __metaclass__ = type
 
+from zope.app.browser.form.submit import Update
+from zope.app.form.utility import setUpWidget, applyWidgetsChanges
 from zope.app.interfaces.dublincore import IZopeDublinCore
 from zope.app.interfaces.workflow import IProcessInstanceContainer
 from zope.app.interfaces.workflow import IProcessInstanceContainerAdaptable
@@ -26,11 +28,24 @@
 from zope.context import getWrapperData
 from zope.proxy import removeAllProxies
 from zope.publisher.browser import BrowserView
+from zope.security.proxy import trustedRemoveSecurityProxy
+from zope.schema import getFields
  
 class ManagementView(BrowserView):
 
     __used_for__ = IProcessInstanceContainerAdaptable
 
+    def __init__(self, context, request):
+        super(ManagementView, self).__init__(context, request)
+        workflow = self._getSelWorkflow() 
+        schema = workflow.data.getSchema()
+        for name, field in getFields(schema).items():
+            # setUpWidget() does not mutate the field, so it is ok.
+            field = trustedRemoveSecurityProxy(field)
+            setUpWidget(self, name, field,
+                        value=getattr(workflow.data, name))
+        
+
     def _extractContentInfo(self, item):
         id, processInstance = item
         info = {}
@@ -43,9 +58,6 @@
         return map(self._extractContentInfo,
                    getAdapter(self.context, IProcessInstanceContainer).items())
 
-    contents = ViewPageTemplateFile('instance_manage.pt')
-    contentsMacros = contents
-
     def getWorkflowTitle(self):
         pi = self._getSelWorkflow()
         if pi is None:
@@ -59,7 +71,6 @@
         if pi is None:
             return info
 
-        
         pd = self._getProcessDefinition(pi)
         clean_pd = removeAllProxies(pd)
 
@@ -114,3 +125,22 @@
         return ws.getProcessDefinition(processInstance.processDefinitionName)
 
 
+    def widgets(self):
+        schema = self._getSelWorkflow().data.getSchema()
+        return [getattr(self, name+'_widget')
+                for name in getFields(schema).keys()]
+
+    
+    def update(self):
+        status = ''
+
+        if Update in self.request:
+            workflow = self._getSelWorkflow() 
+            schema = trustedRemoveSecurityProxy(workflow.data.getSchema())
+            changed = applyWidgetsChanges(
+                self, workflow.data, schema, names=getFields(schema).keys(),
+                exclude_readonly=True)
+            if changed:
+                status = u'Updated Workflow Data.'
+
+        return status


=== Zope3/src/zope/app/browser/workflow/stateful/instance_manage.pt 1.3 => 1.4 ===
--- Zope3/src/zope/app/browser/workflow/stateful/instance_manage.pt:1.3	Wed Jun 25 17:18:57 2003
+++ Zope3/src/zope/app/browser/workflow/stateful/instance_manage.pt	Thu Jul 31 11:01:27 2003
@@ -4,11 +4,14 @@
     </head>
     <body>
       <div metal:fill-slot="body">
+        <h3>Workflow Options</h3>
+        <br/>
         <div metal:define-macro="contents">
           <div metal:define-macro="contents_selectWorkflow"
                tal:define="workflow request/workflow | nothing">
             <div tal:condition="not:workflow" tal:omit-tag="">
-              <form name="containerContentsForm" method="get" action="@@workflows.html" 
+              <form name="containerContentsForm" method="get" 
+                    action="@@workflows.html" 
                     tal:define="container_contents view/listContentInfo"
                     tal:condition="container_contents">
                 Workflow: 
@@ -17,7 +20,7 @@
                           tal:attributes="value workflow/id"
                           tal:content="workflow/name"></option>
                 </select>
-                <input type="submit" value="choose" />
+                &nbsp;<input type="submit" value="Choose" />
               </form>
             </div>
             <div tal:condition="workflow" tal:omit-tag="">
@@ -46,9 +49,33 @@
                        tal:attributes="value trans/name"/>
                 <span tal:replace="trans/title"/><br />
               </div>
-              <input type="submit" value="do it" />
+              <input type="submit" value="Make Transition" />
               </form>
         </div>
+       
+        <h3>Workflow-relevant Data</h3>
+
+        <p tal:define="status view/update"
+           tal:condition="status"
+           tal:content="status" />
+
+        <form name="." method="POST"> 
+          <div class="row" tal:repeat="widget view/widgets"
+              tal:content="structure widget/row">
+            <div class="label">Name</div>
+            <div class="field"><input type="text" style="width:100%" /></div>
+          </div>
+
+          <div class="row">
+            <div class="controls">
+              <input type="submit" value="Refresh" 
+                  i18n:attributes="value refresh-button" />
+              <input type="submit" name="UPDATE_SUBMIT" value="Submit" 
+                  i18n:attributes="value submit-button"/>
+            </div>
+          </div>
+        </form> 
+    
       </div>
     </body>
   </html>