diff --git a/plugins/ktcore/KTCorePlugin.php b/plugins/ktcore/KTCorePlugin.php index ec39eb0..f47c362 100644 --- a/plugins/ktcore/KTCorePlugin.php +++ b/plugins/ktcore/KTCorePlugin.php @@ -92,6 +92,13 @@ class KTCorePlugin extends KTPlugin { 'KTAdminSectionNavigation', 'ktcore.portlets.adminnavigation', 'KTPortlets.php'); + // workflow triggers + $this->registerWorkflowTrigger('ktcore.workflowtriggers.permissionguard', 'PermissionGuardTrigger', 'KTWorkflowTriggers.inc.php'); + $this->registerWorkflowTrigger('ktcore.workflowtriggers.roleguard', 'RoleGuardTrigger', 'KTWorkflowTriggers.inc.php'); + $this->registerWorkflowTrigger('ktcore.workflowtriggers.groupguard', 'GroupGuardTrigger', 'KTWorkflowTriggers.inc.php'); + $this->registerWorkflowTrigger('ktcore.workflowtriggers.conditionguard', 'ConditionGuardTrigger', 'KTWorkflowTriggers.inc.php'); + + $this->setupAdmin(); } @@ -180,9 +187,6 @@ class KTCorePlugin extends KTPlugin { 'admin/manageCleanup.php', null); // plugins - - // workflow triggers - $this->registerWorkflowTrigger('ktcore.workflowtriggers.permissionguard', 'PermissionGuardTrigger', 'KTWorkflowTriggers.inc.php'); } } diff --git a/plugins/ktcore/KTWorkflowTriggers.inc.php b/plugins/ktcore/KTWorkflowTriggers.inc.php index 12fe1c6..ad6a05f 100644 --- a/plugins/ktcore/KTWorkflowTriggers.inc.php +++ b/plugins/ktcore/KTWorkflowTriggers.inc.php @@ -128,4 +128,289 @@ class PermissionGuardTrigger extends KTWorkflowTrigger { } } + +class RoleGuardTrigger extends KTWorkflowTrigger { + var $sNamespace = 'ktcore.workflowtriggers.roleguard'; + var $sFriendlyName; + var $sDescription; + var $oTriggerInstance; + var $aConfig = array(); + + // generic requirements - both can be true + var $bIsGuard = true; + var $bIsAction = false; + + function RoleGuardTrigger() { + $this->sFriendlyName = _kt("Role Restrictions"); + $this->sDescription = _kt("Prevents users who do not have the specified role from using this transition."); + } + + // override the allow transition hook. + function allowTransition($oDocument, $oUser) { + if (!$this->isLoaded()) { + return true; + } + + $iRoleId = $this->aConfig['role_id']; + $oRole = Role::get($this->aConfig['role_id']); + if (PEAR::isError($oRole)) { + return true; // fail safe for cases where the role is deleted. + } + + if ($iRoleId) { + $bHaveRole = false; + // handle the magic roles + if ($iRoleId == -3) { + // everyone: just accept + $bHaveRole = true; + } else if (($iRoleId == -4) && !$oUser->isAnonymous()) { + // authenticated + $bHaveRole = true; + } else { + $oRoleAllocation = DocumentRoleAllocation::getAllocationsForDocumentAndRole($oDocument->getId(), $iRoleId); + if ($oRoleAllocation == null) { // no role allocation on the doc - check the folder. + $oRoleAllocation = RoleAllocation::getAllocationsForFolderAndRole($oDocument->getParentID(), $iRoleId); + } + // if that's -also- null + if ($oRoleAllocation == null) { // no role allocation, no fulfillment. + $bHaveRole = false; + } else if ($oRoleAllocation->hasMember($oUser)) { + $bHaveRole = false; + } + } + + if (!$bHaveRole) { + continue; + } + } + + return true; + } + + function displayConfiguration($args) { + // permissions + $aKeyedRoles = array(); + $aRoles = Role::getList(); + foreach ($aRoles as $oRole) { $aKeyedRoles[$oRole->getId()] = $oRole->getName(); } + + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate("ktcore/workflowtriggers/roles"); + $aTemplateData = array( + "context" => $this, + "roles" => $aKeyedRoles, + "current_role" => KTUtil::arrayGet($this->aConfig, 'role_id'), + 'args' => $args, + ); + return $oTemplate->render($aTemplateData); + } + + function saveConfiguration() { + $role_id = KTUtil::arrayGet($_REQUEST, 'role_id', null); + $oRole = Role::get($role_id); + if (PEAR::isError($oRole)) { + // silenty ignore + $role_id = null; + // $_SESSION['ktErrorMessages'][] = _kt('Unable to use the role you specified.'); + } + + $config = array(); + $config['role_id'] = $role_id; + + $this->oTriggerInstance->setConfig($config); + $res = $this->oTriggerInstance->update(); + + return $res; + } + + function getConfigDescription() { + if (!$this->isLoaded()) { + return _kt('This trigger has no configuration.'); + } + // the actual permissions are stored in the array. + $perms = array(); + if (empty($this->aConfig) || is_null($this->aConfig['role_id'])) { + return _kt('No role is required to perform this transition'); + } + $oRole = Role::get($this->aConfig['role_id']); + if (PEAR::isError($oRole)) { + return _kt('The role required for this trigger has been deleted, so anyone can perform this action.'); + } else { + return sprintf(_kt("The user will require the %s role."), htmlentities($oRole->getName(), ENT_NOQUOTES, 'UTF-8')); + } + } +} + + +class GroupGuardTrigger extends KTWorkflowTrigger { + var $sNamespace = 'ktcore.workflowtriggers.groupguard'; + var $sFriendlyName; + var $sDescription; + var $oTriggerInstance; + var $aConfig = array(); + + // generic requirements - both can be true + var $bIsGuard = true; + var $bIsAction = false; + + function GroupGuardTrigger() { + $this->sFriendlyName = _kt("Group Restrictions"); + $this->sDescription = _kt("Prevents users who are not members of the specified group from using this transition."); + } + + // override the allow transition hook. + function allowTransition($oDocument, $oUser) { + if (!$this->isLoaded()) { + return true; + } + + $iGroupId = $this->aConfig['group_id']; + $oGroup = Group::get($this->aConfig['group_id']); + if (PEAR::isError($oGroup)) { + return true; // fail safe for cases where the role is deleted. + } + $res = KTGroupUtil::getMembershipReason($oUser, $oGroup); + if (PEAR::isError($res) || is_empty($res)) { // broken setup, or no reason + return false; + } else { + return true; + } + } + + function displayConfiguration($args) { + // permissions + $aKeyedGroups = array(); + $aGroups = Group::getList(); + foreach ($aGroups as $oGroup) { $aKeyedGroups[$oGroup->getId()] = $oGroup->getName(); } + + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate("ktcore/workflowtriggers/group"); + $aTemplateData = array( + "context" => $this, + "groups" => $aKeyedGroups, + "current_group" => KTUtil::arrayGet($this->aConfig, 'group_id'), + 'args' => $args, + ); + return $oTemplate->render($aTemplateData); + } + + function saveConfiguration() { + $group_id = KTUtil::arrayGet($_REQUEST, 'group_id', null); + $oGroup = Group::get($group_id); + if (PEAR::isError($oGroup)) { + // silenty ignore + $group_id = null; + // $_SESSION['ktErrorMessages'][] = _kt('Unable to use the group you specified.'); + } + + $config = array(); + $config['group_id'] = $group_id; + + $this->oTriggerInstance->setConfig($config); + $res = $this->oTriggerInstance->update(); + + return $res; + } + + function getConfigDescription() { + if (!$this->isLoaded()) { + return _kt('This trigger has no configuration.'); + } + // the actual permissions are stored in the array. + $perms = array(); + if (empty($this->aConfig) || is_null($this->aConfig['group_id'])) { + return _kt('No group is required to perform this transition'); + } + $oGroup = Group::get($this->aConfig['group_id']); + if (PEAR::isError($oGroup)) { + return _kt('The group required for this trigger has been deleted, so anyone can perform this action.'); + } else { + return sprintf(_kt("The user must be a member of the group \"%s\"."), htmlentities($oGroup->getName(), ENT_NOQUOTES, 'UTF-8')); + } + } +} + + +class ConditionGuardTrigger extends KTWorkflowTrigger { + var $sNamespace = 'ktcore.workflowtriggers.conditionguard'; + var $sFriendlyName; + var $sDescription; + var $oTriggerInstance; + var $aConfig = array(); + + // generic requirements - both can be true + var $bIsGuard = true; + var $bIsAction = false; + + function ConditionGuardTrigger() { + $this->sFriendlyName = _kt("Conditional Restrictions"); + $this->sDescription = _kt("Prevents this transition from occuring if the condition specified is not met for the document."); + } + + // override the allow transition hook. + function allowTransition($oDocument, $oUser) { + if (!$this->isLoaded()) { + return true; + } + + $iConditionId = $this->aConfig['condition_id']; + $oCondition = KTSavedSearch::get($this->aConfig['condition_id']); + if (PEAR::isError($oCondition)) { + return true; // fail safe for cases where the role is deleted. + } + return KTSearchUtil::testConditionOnDocument($iConditionId, $oDocument); + } + + function displayConfiguration($args) { + // permissions + $aKeyedConditions = array(); + $aConditions = KTSavedSearch::getConditions(); + foreach ($aConditions as $oCondition) { $aKeyedConditions[$oCondition->getId()] = $oCondition->getName(); } + + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate("ktcore/workflowtriggers/condition"); + $aTemplateData = array( + "context" => $this, + "conditions" => $aKeyedConditions, + "current_group" => KTUtil::arrayGet($this->aConfig, 'group_id'), + 'args' => $args, + ); + return $oTemplate->render($aTemplateData); + } + + function saveConfiguration() { + $condition_id = KTUtil::arrayGet($_REQUEST, 'condition_id', null); + $oCondition = KTSavedSearch::get($condition_id); + if (PEAR::isError($oCondition)) { + // silenty ignore + $condition_id = null; + // $_SESSION['ktErrorMessages'][] = _kt('Unable to use the group you specified.'); + } + + $config = array(); + $config['condition_id'] = $condition_id; + + $this->oTriggerInstance->setConfig($config); + $res = $this->oTriggerInstance->update(); + + return $res; + } + + function getConfigDescription() { + if (!$this->isLoaded()) { + return _kt('This trigger has no configuration.'); + } + // the actual permissions are stored in the array. + $perms = array(); + if (empty($this->aConfig) || is_null($this->aConfig['condition_id'])) { + return _kt('No condition must be fulfilled before this transition becomes available.'); + } + $oCondition = KTSavedSearch::get($this->aConfig['condition_id']); + if (PEAR::isError($oCondition)) { + return _kt('The condition required for this trigger has been deleted, so it is always available.'); + } else { + return sprintf(_kt("The document must match condition \"%s\"."), htmlentities($oCondition->getName(), ENT_NOQUOTES, 'UTF-8')); + } + } +} + ?> \ No newline at end of file diff --git a/plugins/ktcore/admin/workflows.php b/plugins/ktcore/admin/workflows.php index 46eb8ae..d491318 100755 --- a/plugins/ktcore/admin/workflows.php +++ b/plugins/ktcore/admin/workflows.php @@ -663,8 +663,10 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { } $aOptions['vocab'] = $vocab; $add_transition_fields[] = new KTLookupWidget(_kt('Destination State'), _kt('Once this transition is complete, which state should the document be in?'), 'fTargetStateId', $oWorkflow->getStartStateId(), $this->oPage, true, null, null, $aOptions); + /* $aOptions = array(); $vocab = array(); + $vocab[0] = _kt('None'); foreach($aInfo['permissions'] as $permission) { $vocab[$permission->getId()] = $permission->getHumanName(); } @@ -687,7 +689,7 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { } $aOptions['vocab'] = $vocab; $add_transition_fields[] = new KTLookupWidget(_kt('Guard Role.'), _kt('Which role must the user have in order to follow this transition?'), 'fRoleId', NULL, $this->oPage, false, null, null, $aOptions); - + if (!empty($aConditions)) { $aOptions = array(); $vocab = array(); @@ -698,7 +700,7 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { $aOptions['vocab'] = $vocab; $edit_fields[] = new KTLookupWidget(_kt('Guard Condition.'), _kt('Which condition (stored search) must be satisfied before the transition can take place?'), 'fConditionId', NULL, $this->oPage, false, null, null, $aOptions); } - + */ $oTemplate->setData(array( @@ -1448,6 +1450,42 @@ class KTWorkflowDispatcher extends KTAdminDispatcher { exit(0); } + function do_deleteTrigger() { + $aRequest = $this->oValidator->validateDict($_REQUEST, array( + 'fWorkflowId' => array('type' => 'workflow'), + 'fTransitionId' => array('type' => 'workflowtransition'), + )); + $oWorkflow =& $this->oValidator->validateWorkflow($_REQUEST['fWorkflowId']); + $oTransition =& $this->oValidator->validateWorkflowTransition($_REQUEST['fTransitionId']); + $oTriggerInstance =& KTWorkflowTriggerInstance::get($_REQUEST['fTriggerInstanceId']); + if (PEAR::isError($oTriggerInstance)) { + $this->errorRedirectTo('editTransition', _kt('Unable to load trigger.'), 'fWorkflowId=' . $oWorkflow->getId() . '&fTransitionId=' . $oTransition->getId()); + exit(0); + } + + // grab the transition ns from the request. + $KTWFTriggerReg =& KTWorkflowTriggerRegistry::getSingleton(); + + $this->startTransaction(); + + $oTrigger = $KTWFTriggerReg->getWorkflowTrigger($oTriggerInstance->getNamespace()); + if (PEAR::isError($oTrigger)) { + $this->errorRedirectTo('editTransition', _kt('Unable to load trigger.'), 'fWorkflowId=' . $oWorkflow->getId() . '&fTransitionId=' . $oTransition->getId()); + exit(0); + } + $oTrigger->loadConfig($oTriggerInstance); + + $res = $oTriggerInstance->delete(); + if (PEAR::isError($res)) { + $this->errorRedirectTo('editTransition', _kt('Unable to delete trigger: ') . $res->getMessage(), 'fWorkflowId=' . $oWorkflow->getId() . '&fTransitionId=' . $oTransition->getId()); + exit(0); + } + + $this->successRedirectTo('editTransition', _kt('Trigger deleted.'), 'fWorkflowId=' . $oWorkflow->getId() . '&fTransitionId=' . $oTransition->getId()); + exit(0); + } + + // }}} } diff --git a/templates/ktcore/workflow/editTransition.smarty b/templates/ktcore/workflow/editTransition.smarty index c2e365a..163afb5 100644 --- a/templates/ktcore/workflow/editTransition.smarty +++ b/templates/ktcore/workflow/editTransition.smarty @@ -71,8 +71,8 @@ requirement.{/i18n}
{i18n}No actions are performed when this transition occurs.{/i18n}
| {i18n}Trigger{/i18n} | +{i18n}Configuration{/i18n} | +{i18n}Edit{/i18n} | +{i18n}Delete{/i18n} | +
|---|---|---|---|
| {$oTrigger->getName()} | +{$oTrigger->getConfigDescription()} | +edit | +x | +