diff --git a/gulliver/system/class.bootstrap.php b/gulliver/system/class.bootstrap.php index 1466842fa..d9b3f6498 100644 --- a/gulliver/system/class.bootstrap.php +++ b/gulliver/system/class.bootstrap.php @@ -225,6 +225,9 @@ class Bootstrap self::registerClass("cronFile", PATH_CLASSES . "class.plugin.php"); self::registerClass("pluginDetail", PATH_CLASSES . "class.pluginRegistry.php"); self::registerClass("PMPluginRegistry", PATH_CLASSES . "class.pluginRegistry.php"); + /*****feature-begins******/ + self::registerClass("PMFeatureRegistry", PATH_CLASSES . "class.featureRegistry.php"); + /*****feature-ends******/ self::registerClass("featuresDetail", PATH_CLASSES . "class.licensedFeatures.php"); self::registerClass("PMLicensedFeatures", PATH_CLASSES . "class.licensedFeatures.php"); self::registerClass("PMDashlet", PATH_CLASSES . "class.pmDashlet.php"); diff --git a/workflow/engine/Features/ActionsByEmail/ActionsByEmailFeature.php b/workflow/engine/Features/ActionsByEmail/ActionsByEmailFeature.php index 92f7925e2..948851927 100644 --- a/workflow/engine/Features/ActionsByEmail/ActionsByEmailFeature.php +++ b/workflow/engine/Features/ActionsByEmail/ActionsByEmailFeature.php @@ -1,30 +1,104 @@ sFriendlyName = 'Actions By Email'; + $this->sDescription = 'Actions by Email using variables as multiple choice actions delivered by email'; + $this->sFeatureFolder = 'ActionsByEmail'; + $this->sSetupPage = ''; + $this->iVersion = self::getFeatureVersion($namespace); + $this->aWorkspaces = null; + $this->aDependences = array(array('sClassName' => 'enterprise'), array('sClassName' => 'pmLicenseManager')); + $this->bPrivate = parent::registerEE($this->sFeatureFolder, $this->iVersion); + + return $result; + } + public function setup() { - + try { + // Register the extended tab for the task properties + //$this->registerTaskExtendedProperty('actionsByEmail/configActionsByEmail', "Actions by Email"); + //$this->registerTaskExtendedProperty('actionsByEmail/configActionsByEmail', 'Actions by Email'); + //$this->registerMenu('setup', 'menusetup.php'); + + // Register the trigger for the hook PM_CREATE_NEW_DELEGATION + if (!defined('PM_CREATE_NEW_DELEGATION')) { + throw new Exception('It might be using a version of ProcessMaker which is not totally compatible with this plugin, the minimun required version is 2.0.37'); + } + $this->registerTrigger(PM_CREATE_NEW_DELEGATION, 'sendActionsByEmail'); + + // Register the external step for the tracking form + //$this->registerStep('4939290144f0745f5ddb1d1019823738', 'externalStep', 'Actions by Email - Tracking Form'); // ToDo: For the next release + } catch (Exception $error) { + //G::SendMessageText($error->getMessage(), 'WARNING'); + } } - + public function install() { - + $this->checkTables(); } - + public function enable() { - + $this->checkTables(); } - + public function disable() { - + // Nothing to do for now + } + + /** + * This method get the version of this plugin, when the plugin is packaged in the tar.gz + * the file "version" in the plugin folder has this information for development purposes, + * we calculate the version using git commands, because the repository is in GIT + * + * @param String $namespace The namespace of the plugin + * @return String $version + */ + private static function getFeatureVersion($namespace) + { + return "2.0.20"; + } + + public function checkTables() + { + $con = Propel::getConnection('workflow'); + $stmt = $con->createStatement(); + // setting the path of the sql schema files + $filenameSql = PATH_PLUGINS . 'actionsByEmail/data/schema.sql'; + + // checking the existence of the schema file + if (!file_exists($filenameSql)) { + throw new Exception("File data/schema.sql doesn't exists"); + } + + // exploding the sql query in an array + $sql = explode(';', file_get_contents($filenameSql)); + + $stmt->executeQuery('SET FOREIGN_KEY_CHECKS = 0;'); + + // executing each query stored in the array + foreach ($sql as $sentence) { + if (trim($sentence) != '') { + $stmt->executeQuery($sentence); + } + } } } diff --git a/workflow/engine/classes/class.feature.php b/workflow/engine/classes/class.feature.php new file mode 100644 index 000000000..2eac323ee --- /dev/null +++ b/workflow/engine/classes/class.feature.php @@ -0,0 +1,377 @@ +. + * + * For more information, contact Colosa Inc, 2566 Le Jeune Rd., + * Coral Gables, FL, 33134, USA, or email info@colosa.com. + */ + +define('G_PLUGIN_CLASS', 1); +define('PM_CREATE_CASE', 1001); +define('PM_UPLOAD_DOCUMENT', 1002); +define('PM_CASE_DOCUMENT_LIST', 1003); +define('PM_BROWSE_CASE', 1004); +define('PM_NEW_PROCESS_LIST', 1005); +define('PM_NEW_PROCESS_SAVE', 1006); +define('PM_NEW_DYNAFORM_LIST', 1007); +define('PM_NEW_DYNAFORM_SAVE', 1008); +define('PM_EXTERNAL_STEP', 1009); +define('PM_CASE_DOCUMENT_LIST_ARR', 1010); +define('PM_LOGIN', 1011); +define('PM_UPLOAD_DOCUMENT_BEFORE', 1012); +define('PM_CREATE_NEW_DELEGATION', 1013); +define('PM_SINGLE_SIGN_ON', 1014); +define('PM_GET_CASES_AJAX_LISTENER', 1015); +define('PM_BEFORE_CREATE_USER', 1016); +define('PM_AFTER_LOGIN', 1017); +define('PM_HASH_PASSWORD', 1018); + +/** + * @package workflow.engine.classes + */ +class PMFeature +{ + public $sNamespace; + public $sClassName; + public $sFilename = null; + public $iVersion = 0; + public $sFriendlyName = null; + public $sFeatureFolder = ''; + public $aWorkspaces = null; + public $bPrivate = false; + + /** + * This function sets values to the plugin + * @param string $sNamespace + * @param string $sFilename + * @return void + */ + public function __construct($sNamespace, $sFilename = null) + { + $this->sNamespace = $sNamespace; + $this->sClassName = $sNamespace . 'Plugin'; + $this->sFeatureFolder = $sNamespace; + $this->sFilename = $sFilename; + } + + /** + * With this function we can register the MENU + * @param string $menuId + * @param string $menuFilename + * @return void + */ + public function registerMenu($menuId, $menuFilename) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $sMenuFilename = PATH_FEATURES . $this->sFeatureFolder . PATH_SEP . $menuFilename; + $oPluginRegistry->registerMenu($this->sNamespace, $menuId, $sMenuFilename); + } + + /** + * With this function we can register a dashlet class + * param + * @return void + */ + public function registerDashlets() + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerDashlets($this->sNamespace); + } + + /** + * With this function we can register the report + * param + * @return void + */ + public function registerReport() + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerReport($this->sNamespace); + } + + /** + * With this function we can register the pm's function + * param + * @return void + */ + public function registerPmFunction() + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerPmFunction($this->sNamespace); + } + + /** + * With this function we can set the company's logo + * param + * @return void + */ + public function setCompanyLogo($filename) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->setCompanyLogo($this->sNamespace, $filename); + } + + /** + * With this function we can register the pm's function + * param + * @return void + */ + public function redirectLogin($role, $pathMethod) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerRedirectLogin($this->sNamespace, $role, $pathMethod); + } + + /** + * Register a folder for methods + * + * @param unknown_type $sFolderName + */ + public function registerFolder($sFolderId, $sFolderName) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerFolder($this->sNamespace, $sFolderId, $sFolderName); + } + + /** + * With this function we can register the steps + * param + * @return void + */ + public function registerStep($sStepId, $sStepName, $sStepTitle, $sSetupStepPage = '') + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerStep( $this->sNamespace, $sStepId, $sStepName, $sStepTitle, $sSetupStepPage ); + } + + /** + * With this function we can register the triggers + * @param string $sTriggerId + * @param string $sTriggerName + * @return void + */ + public function registerTrigger($sTriggerId, $sTriggerName) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerTrigger($this->sNamespace, $sTriggerId, $sTriggerName); + } + + /** + * With this function we can delete a file + * @param string $sFilename + * @param string $bAbsolutePath + * @return void + */ + public function delete($sFilename, $bAbsolutePath = false) + { + if (!$bAbsolutePath) { + $sFilename = PATH_FEATURES . $this->sFeatureFolder . PATH_SEP . $sFilename; + } + @unlink($sFilename); + } + + /** + * With this function we can copy a files + * @param string $sSouce + * @param string $sTarget + * @param string $bSourceAbsolutePath + * @param string $bTargetAbsolutePath + * @return void + */ + public function copy($sSouce, $sTarget, $bSourceAbsolutePath = false, $bTargetAbsolutePath = false) + { + if (!$bSourceAbsolutePath) { + $sSouce = PATH_FEATURES . $this->sFeatureFolder . PATH_SEP . $sSouce; + } + if (!$bTargetAbsolutePath) { + $sTarget = PATH_FEATURES . $this->sFeatureFolder . PATH_SEP . $sTarget; + } + + G::verifyPath(dirname($sTarget), true); + @copy($sSouce, $sTarget); + } + + /** + * With this function we can rename a files + * @param string $sSouce + * @param string $sTarget + * @param string $bSourceAbsolutePath + * @param string $bTargetAbsolutePath + * @return void + */ + public function rename($sSouce, $sTarget, $bSourceAbsolutePath = false, $bTargetAbsolutePath = false) + { + if (!$bSourceAbsolutePath) { + $sSouce = PATH_FEATURES . $this->sFeatureFolder . PATH_SEP . $sSouce; + } + if (!$bTargetAbsolutePath) { + $sTarget = PATH_FEATURES . $this->sFeatureFolder . PATH_SEP . $sTarget; + } + + G::verifyPath(dirname($sTarget), true); + @chmod(dirname($sTarget), 0777); + @rename($sSouce, $sTarget); + } + + /** + * This function registers a page who is break + * @param string $pageId + * @param string $templateFilename + * @return void + */ + public function registerBreakPageTemplate($pageId, $templateFilename) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $sPageFilename = PATH_FEATURES . $this->sFeatureFolder . PATH_SEP . $templateFilename; + $oPluginRegistry->registerBreakPageTemplate ($this->sNamespace, $pageId, $sPageFilename); + } + + /** + * With this function we can register a CSS + * @param string $sPage + * @return void + */ + public function registerCss($sCssFile) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerCss($this->sNamespace, $sCssFile); + } + + /** + * With this function we can register the toolbar file for dynaform editor + * @param string $menuId + * @param string $menuFilename + * @return void + */ + public function registerToolbarFile($sToolbarId, $filename) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $sFilename = PATH_FEATURES . $this->sFeatureFolder . PATH_SEP . $filename; + $oPluginRegistry->registerToolbarFile($this->sNamespace, $sToolbarId, $sFilename); + } + + /** + * With this function we can register a Case Scheduler Plugin/Addon + * param + * @return void + */ + public function registerCaseSchedulerPlugin( + $sActionId, + $sActionForm, + $sActionSave, + $sActionExecute, + $sActionGetFields + ) { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerCaseSchedulerPlugin( + $this->sNamespace, $sActionId, $sActionForm, $sActionSave, $sActionExecute, $sActionGetFields + ); + } + + /** + * With this function we can register a task extended property + * @param string $sPage + * @return void + */ + public function registerTaskExtendedProperty($sPage, $sName, $sIcon="") + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerTaskExtendedProperty ( $this->sNamespace, $sPage, $sName, $sIcon ); + } + + /** + * Register a plugin javascript to run with core js script at same runtime + * @param string $coreJsFile + * @param array/string $pluginJsFile + * @return void + */ + function registerJavascript($sCoreJsFile, $pluginJsFile) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerJavascript($this->sNamespace, $sCoreJsFile, $pluginJsFile); + } + + /** + * Unregister a plugin javascript + * @param string $coreJsFile + * @param array/string $pluginJsFile + * @return void + */ + public function unregisterJavascript($sCoreJsFile, $pluginJsFile) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->unregisterJavascript($this->sNamespace, $sCoreJsFile, $pluginJsFile); + } + + public function registerDashboard() + { // Dummy function for backwards compatibility + } + + public function getExternalStepAction() + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + return $oPluginRegistry->getSteps(); + } + + /** + * Register a rest service and expose it + * + * @author Erik Amaru Ortiz + * @param string $coreJsFile + * @param array/string $pluginJsFile + * @return void + */ + function registerRestService() + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerRestService($this->sNamespace); + } + + /** + * Unregister a rest service + * + * @author Erik Amaru Ortiz + * @param string $coreJsFile + * @param array/string $pluginJsFile + * @return void + */ + function unregisterRestService($classname, $path) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->unregisterRestService($this->sNamespace, $classname, $path); + } + + /** + * With this function we can register a cron file + * param string $cronFile + * @return void + */ + public function registerCronFile($cronFile) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->registerCronFile($this->sNamespace, $cronFile); + } + + function enableRestService($enable) + { + $oPluginRegistry =& PMPluginRegistry::getSingleton(); + $oPluginRegistry->enableRestService($this->sNamespace, $enable); + } +} diff --git a/workflow/engine/classes/class.featureRegistry.php b/workflow/engine/classes/class.featureRegistry.php new file mode 100755 index 000000000..d779f45b4 --- /dev/null +++ b/workflow/engine/classes/class.featureRegistry.php @@ -0,0 +1,179 @@ +. + * + * For more information, contact Colosa Inc, 2566 Le Jeune Rd., + * Coral Gables, FL, 33134, USA, or email info@colosa.com. + */ + +class PMFeatureRegistry +{ + private $features = array (); + private $triggers = array (); + private static $instance = null; + + /** + * This function is the constructor of the PMPluginRegistry class + * param + * + * @return void + */ + private function __construct () + { + + } + + /** + * This function is instancing to this class + * param + * + * @return object + */ + public static function getSingleton () + { + if (self::$instance == null) { + self::$instance = new PMFeatureRegistry(); + } + return self::$instance; + } + + /** + * Register the feature in the singleton + * + * @param unknown_type $className + * @param unknown_type $featureName + * @param unknown_type $filename + */ + public function registerFeature ($featureName, $filename = null) + { + $className = $featureName . "Feature"; + $feature = new $className( $featureName, $filename ); + if (isset( $this->features[$featureName] )) { + $this->features[$featureName]->iVersion = $feature->iVersion; + return; + } else { + $this->features[$featureName] = $feature; + } + } + + /** + * Enable the plugin in the singleton + * + * @param unknown_type $featureName + */ + public function enableFeature ($featureName) + { + $feature = $this->retrieveFeature($featureName); + if ($feature) { + $feature->enable(); + } + throw new Exception( "Unable to enable feature '$featureName' (feature not found)" ); + } + + /** + * disable the plugin in the singleton + * + * @param unknown_type $featureName + */ + public function disableFeature ($featureName) + { + $feature = $this->retrieveFeature($featureName); + if ($feature) { + $feature->enable(); + } + throw new Exception( "Unable to disable feature '$featureName' (feature not found)" ); + } + + /** + * install the plugin + * + * @param unknown_type $featureName + */ + public function installFeature ($featureName) + { + try { + $this->registerFeature($featureName); + $feature = $this->retrieveFeature($featureName); + if ($feature) { + $feature->install(); + } else { + throw new Exception( "Unable to install feature '$featureName' (feature not found)" ); + } + } catch (Exception $e) { + global $G_PUBLISH; + $aMessage['MESSAGE'] = $e->getMessage(); + $G_PUBLISH = new Publisher(); + $G_PUBLISH->AddContent( 'xmlform', 'xmlform', 'login/showMessage', '', $aMessage ); + G::RenderPage( 'publish' ); + die(); + } + } + + public function retrieveFeature($name) + { + foreach ($this->features as $featureName => $feature) { + if ($featureName === $name) { + return $feature; + } + } + return false; + } + + /** + * execute all triggers related to a triggerId + * + * @param unknown_type $menuId + * @return object + */ + public function executeTriggers ($triggerId, $data) + { + foreach ($this->features as $feature) { + $feature->executeTrigger($triggerId, $data); + } + } + + public function setupFeatures () + { + return true; + $featureDirList = glob(PATH_FEATURES . "/*", GLOB_ONLYDIR); + foreach ($featureDirList as $directory) { + if ($directory == 'ViewContainers') { + continue; + } + $featureApiClassList = Util\Common::rglob($directory . DS . 'Services' . DS . 'Api' . "/*"); + foreach ($featureApiClassList as $classFile) { + if (pathinfo($classFile, PATHINFO_EXTENSION) === 'php') { + $relClassPath = str_replace('.php', '', str_replace($servicesDir, '', $classFile)); + $namespace = '\\ProcessMaker\\Services\\Api\\' . basename($classFile, '.php'); + $namespace = strpos($namespace, "//") === false? $namespace: str_replace("//", '', $namespace); + require_once $classFile; + $this->rest->addAPIClass($namespace); + } + } + } + foreach ($this->features as $feature) { + $feature->setup(); + } + } + +} + diff --git a/workflow/engine/classes/model/AppDelegation.php b/workflow/engine/classes/model/AppDelegation.php index 06cc09dde..4bd6d62fc 100755 --- a/workflow/engine/classes/model/AppDelegation.php +++ b/workflow/engine/classes/model/AppDelegation.php @@ -176,7 +176,9 @@ class AppDelegation extends BaseAppDelegation $data->DEL_INDEX = $delIndex; $data->USR_UID = $sUsrUid; $oPluginRegistry = &PMPluginRegistry::getSingleton(); + $featureRegistry = &PMFeatureRegistry::getSingleton(); $oPluginRegistry->executeTriggers( PM_CREATE_NEW_DELEGATION, $data ); + $featureRegistry->executeTriggers( PM_CREATE_NEW_DELEGATION, $data ); } return $delIndex; diff --git a/workflow/public_html/sysGeneric.php b/workflow/public_html/sysGeneric.php index 70d6ec37a..83567fb3e 100755 --- a/workflow/public_html/sysGeneric.php +++ b/workflow/public_html/sysGeneric.php @@ -196,6 +196,9 @@ define( 'PATH_METHODS', PATH_CORE . 'methods' . PATH_SEP ); define( 'PATH_XMLFORM', PATH_CORE . 'xmlform' . PATH_SEP ); define( 'PATH_CONFIG', PATH_CORE . 'config' . PATH_SEP ); define( 'PATH_PLUGINS', PATH_CORE . 'plugins' . PATH_SEP ); +/*****features-begins******/ +define( 'PATH_FEATURES', PATH_CORE . 'features' . PATH_SEP ); +/*****features-ends******/ define( 'PATH_HTMLMAIL', PATH_CORE . 'html_templates' . PATH_SEP ); define( 'PATH_TPL', PATH_CORE . 'templates' . PATH_SEP ); define( 'PATH_TEST', PATH_CORE . 'test' . PATH_SEP ); @@ -627,7 +630,9 @@ if (file_exists( $sSerializedFile )) { } else{ $oPluginRegistry = PMPluginRegistry::getSingleton(); } - +/****features-begins****/ +$featureRegistry =& PMFeatureRegistry::getSingleton(); +/****features-ends****/ // setup propel definitions and logging //changed to autoloader //require_once ("propel/Propel.php"); @@ -692,6 +697,9 @@ if (SYS_LANG != 'en' && ! is_file( PATH_LANGUAGECONT . 'translation.' . SYS_LANG // Setup plugins $oPluginRegistry->setupPlugins(); //get and setup enabled plugins +/****features-begins****/ +$featureRegistry->setupFeatures(); //get and setup enabled features +/****features-ends****/ $avoidChangedWorkspaceValidation = false; // Load custom Classes and Model from Plugins.