Child pages
  • Grouper provision multiple groups with Rice workflow example
Skip to end of metadata
Go to start of metadata

This is an example of a Kuali edoclite that will auto-provision the requestor into the requested groups at the end of the workflow.  Note in Rice you will have approvals etc before the end, this example just shows the provisioning so there is only one approval

Screenshot of Kuali form

Note, this is the default template, you will customize this for your institution



Screenshot of HTML

This is the part of the form that is not the boilerplate form part



HTML to start with

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Provision multiple groups</title>
<style type="text/css">

  html, body, td {
    font-family:Tahoma,Arial,Helvetica,sans-serif;
    font-size:11px;
  }

  h1 {
    font-size:22px;
    line-height:22px;
  }

  h2 {
    border-bottom:1px solid #6699CC;
    color:#990000;
    font-size:16px;
    font-weight:bold;
    line-height:20px;
    width:650px;
  }

  .formTable td {
    padding:2px 0;
  }

  .formTable td.fieldLabel {
    color:#011F5B;
    text-align:right;
    vertical-align:top;
    width:238px;
    font-weight:bold;
  }

  .formTable td.fieldAsterisk {
    color:#990000;
    text-align:left;
    width:12px;
    vertical-align:top;
  }

  .formTable td.fieldInfo {
    text-align:left;
    width:auto;
  }

  .extraInstruct {
    color:#6E83AD;
    font-weight:bold;
  }

  p {
    width: 650px;
  }
</style>
</head>
<body>
  <h1>Example provision multiple groups</h1>
  <br /><br />

    <table border="0" cellspacing="0" cellpadding="0" class="formTable" width="640">

      <tr>
        <td class="fieldLabel">Select which groups are requested</td>
        <td valign="top" class="fieldAsterisk">*</td>
        <td class="fieldInfo" id="userId">

  <input type="checkbox" name="groupElementName0" value="some:group:name0">Group 0<br>
  <input type="checkbox" name="groupElementName1" value="some:group:name1">Group 1<br>

  </td>
      </tr>

      <tr>
        <td class="fieldLabel">Enabled date </td>
        <td valign="top" class="fieldAsterisk"></td>
        <td class="fieldInfo">
  <input type="text" name="enabledDate" /> <span class="extraInstruct">(e.g. 2001/02/03)</span>
  </td>
      </tr>

      <tr>
        <td class="fieldLabel">Disabled date</td>
        <td valign="top" class="fieldAsterisk"></td>
        <td class="fieldInfo">
  <input type="text" name="disabledDate" /> <span class="extraInstruct">(e.g. 2001/02/03)</span>
  </td>
      </tr>

    </table>


  <br /><br />

</body>
</html>

Groups

If you arent using grouper for groups in Rice, then ingest this xml in Rice.  Otherwise, create this group in our rice base folder in Grouper

<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="ns:workflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns:workflow resource:WorkflowData">
  <groups xmlns="ns:workflow/Group" xsi:schemaLocation="ns:workflow/Group resource:Group">
    <group>
      <namespace>KUALI</namespace>
      <name>sampleRouteToGroup1</name>
      <description>route to group1</description>
      <members>
        <principalName>user1</principalName>
        <principalName>user2</principalName>
      </members>
    </group>
  </groups>
</data>

Note, you will also have to create the groups that will be provisioned (from the HTML above), and grant access to the kuali rice grouper web service client user, e.g.

gsh 0% grouperSession = GrouperSession.startRootSession();
gsh 1% group0 = new GroupSave(grouperSession).assignName("some:group:name0").assignGroupNameToEdit("some:group:name0").assignCreateParentStemsIfNotExist(true).save();
gsh 2% group1 = new GroupSave(grouperSession).assignName("some:group:name1").assignGroupNameToEdit("some:group:name1").assignCreateParentStemsIfNotExist(true).save();
gsh 3% group0.grantPriv(SubjectFinder.findById("riceGrouper/server.school.edu", true), AccessPrivilege.UPDATE);
gsh 4% group0.grantPriv(SubjectFinder.findById("riceGrouper/server.school.edu", true), AccessPrivilege.READ);
gsh 5% group1.grantPriv(SubjectFinder.findById("riceGrouper/server.school.edu", true), AccessPrivilege.UPDATE);
gsh 6% group1.grantPriv(SubjectFinder.findById("riceGrouper/server.school.edu", true), AccessPrivilege.READ);

Rule template

Ingest this to Kuali Rice in the admin console.  This allows us to route to a group (not required for provisioning, just giving the workflow one hop)

<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="ns:workflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns:workflow resource:WorkflowData">
  <ruleTemplates xmlns="ns:workflow/RuleTemplate" xsi:schemaLocation="ns:workflow/RuleTemplate resource:RuleTemplate">
    <ruleTemplate>
      <name>sampleProvisionMultipleGroups.groupRuleTemplate</name>
      <description>Rule template for group to route to</description>
    </ruleTemplate>
  </ruleTemplates>
</data>

Doctype

Ingest this to Kuali Rice in the admin console.  This configures the nodes in the workflow and associated them with rules (i.e. in the group name let anyone in that group know the form is waiting for them, and let any of them approve it.  Note the post processor is the grouper rice post processor

<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="ns:workflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns:workflow resource:WorkflowData">
  <documentTypes xmlns="ns:workflow/DocumentType" xsi:schemaLocation="ns:workflow/DocumentType resource:DocumentType">
    <documentType>
      <name>sampleProvisionMultipleGroups.doctype</name>
      <description>sampleProvisionMultipleGroups doctype</description>
      <label>sampleProvisionMultipleGroups DocumentType</label>
      <postProcessorName>edu.internet2.middleware.grouperKimConnector.postProcessor.GrouperEdoclitePostProcessor</postProcessorName>
      <superUserGroupName namespace="KUALI">sampleRouteToGroup1</superUserGroupName>
      <defaultExceptionGroupName namespace="KUALI">sampleRouteToGroup1</defaultExceptionGroupName>
      <docHandler>${workflow.url}/EDocLite</docHandler>
      <active>true</active>
      <routingVersion>2</routingVersion>
      <routePaths>
        <routePath>
          <start name="Initiated" nextNode="groupNode" />
          <requests name="groupNode" />
        </routePath>
      </routePaths>
      <routeNodes>
        <start name="Initiated">
          <activationType>P</activationType>
          <mandatoryRoute>false</mandatoryRoute>
          <finalApproval>false</finalApproval>
        </start>
        <requests name="groupNode">
          <activationType>P</activationType>
          <ruleTemplate>sampleProvisionMultipleGroups.groupRuleTemplate</ruleTemplate>
          <mandatoryRoute>false</mandatoryRoute>
          <finalApproval>false</finalApproval>
        </requests>
      </routeNodes>
    </documentType>
  </documentTypes>
</data>

eDocLite

Ingest this xml into Kuali Rice which has the list of fields and HTML including the options which have the groups to add the requestor to

<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="ns:workflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns:workflow resource:WorkflowData">
  <edoclite xmlns="ns:workflow/EDocLite" xsi:schemaLocation="ns:workflow/EDocLite resource:EDocLite">
    <edl name="sampleProvisionMultipleGroups.form" title="sampleProvisionMultipleGroups">
      <security />
      <createInstructions>** Questions with an asterisk are required.</createInstructions>
      <instructions>** Questions with an asterisk are required.</instructions>
      <validations />
      <attributes />

      <fieldDef name="groupFieldDef0" title="Group 0">
        <display>
          <type>checkbox</type>
          <!-- note this will have a prefix: some:group:name0 -->
          <values title="">name0</values>
        </display>
      </fieldDef>
      <fieldDef name="groupFieldDef1" title="Group 1">
        <display>
          <type>checkbox</type>
          <!-- note this will have a prefix: some:group:name1 -->
          <values title="">name1</values>
        </display>
      </fieldDef>
      <fieldDef name="enabledDate" title="Enabled date">
        <display>
          <type>text</type>
          <meta>
            <name>size</name>
            <value>20</value>
          </meta>
        </display>
      </fieldDef>
      <fieldDef name="disabledDate" title="Disabled date">
        <display>
          <type>text</type>
          <meta>
            <name>size</name>
            <value>20</value>
          </meta>
        </display>
      </fieldDef>
    </edl>
    <style name="sampleProvisionMultipleGroups.style">
      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my-class="xalan://org.kuali.rice.kew.edl.WorkflowFunctions" version="1.0">
        <!-- widgets is simply more xslt that contains common functionality that greatly simplifies html rendering. It is somewhat complicated but does not require changes or full understanding unless enhancements are required.  -->
        <xsl:include href="widgets" />
        <xsl:output indent="yes" method="html" omit-xml-declaration="yes" version="4.01" />
        <!-- variables in the current version of xslt cannot be changed once set. Below they are set to various values often fed by java classes or to values contained in workflow xml. Not all of these are used in this form but are shown because often they can be useful. The ones prefixed with my-class are methods that are exposed by workflow to Edoclite.-->
        <xsl:variable name="actionable" select="/documentContent/documentState/actionable" />
        <xsl:variable name="docHeaderId" select="/documentContent/documentState/docId" />
        <xsl:variable name="editable" select="/documentContent/documentState/editable" />
        <xsl:variable name="globalReadOnly" select="/documentContent/documentState/editable != 'true'" />
        <xsl:variable name="docStatus" select="//documentState/workflowDocumentState/status" />
        <xsl:variable name="isAtNodeInitiated" select="my-class:isAtNode($docHeaderId, 'Initiated')" />
        <xsl:variable name="isPastInitiated" select="my-class:isNodeInPreviousNodeList('Initiated', $docHeaderId)" />
        <xsl:variable name="isUserInitiator" select="my-class:isUserInitiator($docHeaderId)" />
        <xsl:variable name="workflowUser" select="my-class:getWorkflowUser().authenticationUserId().id()" />
        <xsl:param name="overrideMain" select="'true'" />
        <!-- mainForm begins here. Execution of stylesheet begins here. It calls other templates which can call other templates. Position of templates beyond this point do not matter. -->
        <xsl:template name="mainForm">
          <html xmlns="">
            <head>
              <script type="text/javascript" src="../penn/jquery.js" />

              <script>
              $(document).ready(function(){

                 $('#edoclite').submit(function() {

                   //make sure there is at least one action checkbox checked
                   if ($('#groupsToAssign :checked').length == 0) {
                     alert('Please select a group to assign');
                     return false;
                   }

                   return true;
                 });

              });
              </script>


              <xsl:call-template name="htmlHead" />
<style type="text/css">

  html, body, td {
    font-family:Tahoma,Arial,Helvetica,sans-serif;
    font-size:11px;
  }

  h1 {
    font-size:22px;
    line-height:22px;
  }

  h2 {
    border-bottom:1px solid #6699CC;
    color:#990000;
    font-size:16px;
    font-weight:bold;
    line-height:20px;
    width:650px;
  }

  .formTable td {
    padding:2px 0;
  }

  .formTable td.fieldLabel {
    color:#011F5B;
    text-align:right;
    vertical-align:top;
    width:238px;
    font-weight:bold;
  }

  .formTable td.fieldAsterisk {
    color:#990000;
    text-align:left;
    width:12px;
    vertical-align:top;
  }

  .formTable td.fieldInfo {
    text-align:left;
    width:auto;
  }

  p {
    width: 650px;
  }

  .extraInstruct {
    color:#6E83AD;
    font-weight:bold;
  }

  div.mainDiv {
    width: 900px;
  }
</style>
            </head>
            <body onload="onPageLoad()">
              <xsl:call-template name="errors" />
              <!-- the header is usefule because it tells the user whether they are in 'Editing' mode or 'Read Only' mode. -->
              <xsl:call-template name="header" />
              <xsl:call-template name="instructions" />
              <xsl:variable name="formTarget" select="'EDocLite'" />
              <!-- validateOnSubmit is a function in edoclite1.js which also supports edloclite forms and can be somewhat complicated but does not require modification unless enhancements are required. -->
              <form action="{$formTarget}" enctype="multipart/form-data" id="edoclite" method="post" onsubmit="return validateOnSubmit(this)">
                <xsl:call-template name="hidden-params" />
                <xsl:call-template name="mainBody" />
                <xsl:call-template name="notes" />
                <br />
                <xsl:call-template name="buttons" />
                <br />
              </form>
              <xsl:call-template name="footer" />
            </body>
          </html>
        </xsl:template>
        <!-- mainBody template begins here. It calls other templates which can call other templates. Position of templates do not matter. -->
        <xsl:template name="mainBody">
          <!-- to debug, or see values of previously created, the uncomment the following line to see value of $docStatus rendered on form. -->
          <!-- $docStatus=<xsl:value-of select="$docStatus" /> -->
          <!-- rest of this all is within the form table -->
          <h1>Example provision multiple groups</h1>
          <br /><br />

            <table border="0" cellspacing="0" cellpadding="0" class="formTable" width="640">

              <tr>
                <td class="fieldLabel">Select which groups are requested</td>
                <td valign="top" class="fieldAsterisk">*</td>
                <td class="fieldInfo" id="groupsToAssign">

                  <xsl:call-template name="widget_render">
                    <xsl:with-param name="fieldName" select="'groupFieldDef0'" />
                    <xsl:with-param name="renderCmd" select="'input'" />
                    <xsl:with-param name="readOnly" select="$isPastInitiated" />
                  </xsl:call-template> Group 0<br />

                  <xsl:call-template name="widget_render">
                    <xsl:with-param name="fieldName" select="'groupFieldDef1'" />
                    <xsl:with-param name="renderCmd" select="'input'" />
                    <xsl:with-param name="readOnly" select="$isPastInitiated" />
                  </xsl:call-template> Group 1<br />


                </td>
              </tr>

              <tr>
                <td class="fieldLabel">Enabled date</td>
                <td valign="top" class="fieldAsterisk"></td>
                <td class="fieldInfo">

                  <xsl:call-template name="widget_render">
                    <xsl:with-param name="fieldName" select="'enabledDate'" />
                    <xsl:with-param name="renderCmd" select="'input'" />
                    <xsl:with-param name="readOnly" select="$isPastInitiated" />
                  </xsl:call-template> <xsl:call-template name="nbsp" />
                  <span class="extraInstruct">(e.g. 2001/02/03)</span>

                </td>
              </tr>

              <tr>
                <td class="fieldLabel">Disabled date</td>
                <td valign="top" class="fieldAsterisk"></td>
                <td class="fieldInfo">

                  <xsl:call-template name="widget_render">
                    <xsl:with-param name="fieldName" select="'disabledDate'" />
                    <xsl:with-param name="renderCmd" select="'input'" />
                    <xsl:with-param name="readOnly" select="$isPastInitiated" />
                  </xsl:call-template> <xsl:call-template name="nbsp" />
                  <span class="extraInstruct">(e.g. 2001/02/03)</span>

                </td>
              </tr>

            </table>


          <br /><br />



        </xsl:template>
        <xsl:template name="nbsp">
          <xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>
        </xsl:template>
      </xsl:stylesheet>
    </style>
    <association>
      <docType>sampleProvisionMultipleGroups.doctype</docType>
      <definition>sampleProvisionMultipleGroups.form</definition>
      <style>sampleProvisionMultipleGroups.style</style>
      <active>true</active>
    </association>
  </edoclite>
</data>

Rule

Ingest this rule in Kuali Rice so that this group is notified and allowed to approve the request at this node in the workflow

<?xml version="1.0" encoding="UTF-8"?>
<data xmlns="ns:workflow" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ns:workflow resource:WorkflowData">
  <rules xmlns="ns:workflow/Rule" xsi:schemaLocation="ns:workflow/Rule resource:Rule">
    <rule>
      <name>sampleProvisionMultipleGroups.groupRule</name>
      <documentType>sampleProvisionMultipleGroups.doctype</documentType>
      <ruleTemplate>sampleProvisionMultipleGroups.groupRuleTemplate</ruleTemplate>
      <description>Route to group</description>
      <responsibilities>
        <responsibility>
          <groupName namespace="KUALI">sampleRouteToGroup1</groupName>
          <actionRequested>A</actionRequested>
          <priority>1</priority>
        </responsibility>
      </responsibilities>
    </rule>
  </rules>
</data>

Grouper client properties

Configure the grouper client properties in Kuali Rice which tells the post processor that the document type above is linked to auto provision fields with a certain prefix

###############################
# configure postprocessor actions on document types.  The string "multipleProvisioning" ties the configs
# together, change that label for multiple

# doctype name that this applies to
kuali.edoclite.saveMembership.multipleProvisioning.docTypeName = sampleProvisionMultipleGroups.doctype

# regex of group allowed to assign to, extra layer of security, optional
kuali.edoclite.saveMembership.multipleProvisioning.groupRegex =

# list of allowed to assign to (comma separate), extra layer of security, optional,
#generally mutually exclusive with the groupRegex
kuali.edoclite.saveMembership.multipleProvisioning.allowedGroups = some:group:name0, some:group:name1

# edocliteFieldPrefix if checkboxes or textfields or whatever, put the prefix of the edoclite field here.
#so if the field prefix is "groups", then it will look for groups0, groups1, etc to groups200...
#the value of the field is the group to add to
kuali.edoclite.saveMembership.multipleProvisioning.edocliteFieldPrefix = groupFieldDef

#this will be prefixed to the entered group name so the whole stem doesnt
#have to be put on screen (also helps sandbox out the security)
kuali.edoclite.saveMembership.multipleProvisioning.enteredGroupNamePrefix = some:group:

# groups (comma separated) id or name which the initiator will be assigned to when the document is final
kuali.edoclite.saveMembership.multipleProvisioning.addMembershipToGroups =

# groups (comma separated) id or name which the initiator will be unassigned from when the document is final
kuali.edoclite.saveMembership.multipleProvisioning.removeMembershipFromGroups =

# email addresses (comma separated) that should get an admin email that this was done (or errors)
kuali.edoclite.saveMembership.multipleProvisioning.emailAdmins = address@school.edu

# delete date: yyyy/mm/dd or dd-Mon-yyyy
kuali.edoclite.saveMembership.multipleProvisioning.edocliteFieldGroupDisabledDate = disabledDate

# enable date: yyyy/mm/dd or dd-Mon-yyyy
kuali.edoclite.saveMembership.multipleProvisioning.edocliteFieldGroupEnabledDate = enabledDate


Result

After the form is submitted and approved (whatever the approval workflow is), then whatever checkboxes are checked, those groups will be assigned to the requestor:

gsh 9% hasMember("some:group:name0", "me");
true
gsh 10% hasMember("some:group:name1", "me");
true

Also, if there is an email address in "emailAdmins" config, then an email like this will be sent to as a confirmation to the admins of the form:

From: noreply@school.edu [mailto:noreply@school.edu]
Sent: Thursday, May 20, 2010 1:18 AM
To: Chris Hyzer
Subject: DEV:Grouper Rice auto-provision for document: sampleProvisionMultipleGroups.doctype


Subject: id: 12345678, name: Michael Christopher Hyzer
name: Michael Christopher Hyzer
description: Michael Christopher Hyzer (me, 12345678) (active) Staff - Isc Administrative Systems Tools And Technologies - Programmer Analyst Sr (also: Alumni)
PENNNAME: me
EMAIL: me@school.edu

Group addMember: some:group:name0 - SUCCESS
Group addMember: some:group:name1 - SUCCESS

sdf

  • No labels