diff --git a/README.md b/README.md index 9130842..643387d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ GLPI plugin that provides an interface with a customized ProcessMaker server (https://github.com/tomolimo/processmaker-server). -version 3.4.x is compatible with GLPI 9.2 and needs ProcessMaker either 3.0.1.8-RE-1.12 (https://github.com/tomolimo/processmaker-server/releases/tag/3.0.1.8-RE-1.12) or 3.3.0-RE-1.0 (https://github.com/tomolimo/processmaker-server/releases/tag/3.3.0-RE-1.0) +version 3.4.x is compatible with GLPI 9.2 and needs ProcessMaker either 3.0.1.8-RE-1.12 (https://github.com/tomolimo/processmaker-server/releases/tag/3.0.1.8-RE-1.12) or 3.3.0-RE-1.x (https://github.com/tomolimo/processmaker-server/releases/tag/3.3.0-RE-1.5) version 3.5.x is compatible with GLPI 9.3 and needs ProcessMaker 3.3.0-RE-1.x (https://github.com/tomolimo/processmaker-server/releases/latest) diff --git a/ajax/dropdownProcesses.php b/ajax/dropdownProcesses.php index f8c8fc9..c9c585e 100644 --- a/ajax/dropdownProcesses.php +++ b/ajax/dropdownProcesses.php @@ -67,7 +67,7 @@ //if ($DB->numrows($result)) { // while ($data = $DB->fetch_array($result)) { -if ($result->numrows()) { +//if ($result->numrows()) { foreach ($result as $data) { $process_entities = PluginProcessmakerProcess::getEntitiesForProfileByProcess($data["id"], $_SESSION['glpiactiveprofile']['id'], true); $can_add = $data['max_cases_per_item'] == 0 || !isset($count_cases_per_item[$data["id"]]) || $count_cases_per_item[$data["id"]] < $data['max_cases_per_item']; @@ -82,7 +82,7 @@ $count++; } } -} +//} $ret['results'] = $processes; $ret['count'] = $count; diff --git a/ajax/dropdownUsers.php b/ajax/dropdownUsers.php index 6015a0b..40de892 100644 --- a/ajax/dropdownUsers.php +++ b/ajax/dropdownUsers.php @@ -79,13 +79,13 @@ $count = 0; //if ($DB->numrows($result)) { // while ($data = $DB->fetch_assoc($result)) { -if ($res->numrows()) { +//if ($res->numrows()) { foreach ($res as $data) { $users[$data["id"]] = $dbu->formatUserName($data["id"], $data["name"], $data["realname"], $data["firstname"]); $logins[$data["id"]] = $data["name"]; } -} +//} if (!function_exists('dpuser_cmp')) { function dpuser_cmp($a, $b) { diff --git a/front/processmaker.form.php b/front/processmaker.form.php index d70ab35..edd9106 100644 --- a/front/processmaker.form.php +++ b/front/processmaker.form.php @@ -14,7 +14,7 @@ $case = new PluginProcessmakerCase; if ($case->getFromGUID($resultCase->caseId)) { $link = $case->getLinkURL(); - $task = new PluginProcessmakerTask(); + $task = new PluginProcessmakerTask($_POST['itemtype'].'Task'); $task->getFromDBByRequest([ 'WHERE' => [ diff --git a/inc/case.class.php b/inc/case.class.php index 44c2d9e..6ba292a 100644 --- a/inc/case.class.php +++ b/inc/case.class.php @@ -265,27 +265,50 @@ function reassignCase($delIndex, $taskGuid, $delThread, $users_id_source, $users */ public function reassignTask ($delIndex, $newDelIndex, $delThread, $newDelThread, $newTech) { global $DB; - $res = $DB->request('glpi_plugin_processmaker_tasks', [ - 'AND' => [ - 'plugin_processmaker_cases_id' => $this->getID(), - 'del_index' => $delIndex, - 'del_thead' => $delThread - ] - ]); - //$query = "SELECT * FROM glpi_plugin_processmaker_tasks WHERE plugin_processmaker_cases_id={$this->getID()} AND del_index=$delIndex AND del_thread=$delThread; "; - //$res = $DB->query($query); - //if ($DB->numrows($res) > 0) { - // $row = $DB->fetch_array( $res ); - if ($row = $res->next()) { - $glpi_task = new $row['itemtype']; - $glpi_task->getFromDB( $row['items_id'] ); - - $itilobject_itemtype = $this->fields['itemtype']; //str_replace( 'Task', '', $row['itemtype'] ); + + $dbu = new DbUtils; + $pm_task_row = $dbu->getAllDataFromTable(PluginProcessmakerTask::getTable(), ['plugin_processmaker_cases_id' => $this->getID(), 'del_index' => $delIndex, 'del_thread' => $delThread]); + if ($pm_task_row && count($pm_task_row) == 1) { + $pm_task_row = array_shift($pm_task_row); + $glpi_task = new $pm_task_row['itemtype']; + $glpi_task->getFromDB( $pm_task_row['items_id'] ); + + $itilobject_itemtype = $this->fields['itemtype']; $foreignkey = getForeignKeyFieldForItemType( $itilobject_itemtype ); PluginProcessmakerProcessmaker::addWatcher( $itilobject_itemtype, $glpi_task->fields[ $foreignkey ], $newTech ); - $glpi_task->update( [ 'id' => $row['items_id'], $foreignkey => $glpi_task->fields[ $foreignkey ], 'users_id_tech' => $newTech ]); + $donotif = PluginProcessmakerNotificationTargetProcessmaker::saveNotificationState(false); // do not send notification yet + $glpi_task->update( ['id' => $glpi_task->getID(), $foreignkey => $glpi_task->fields[$foreignkey], 'users_id_tech' => $newTech, 'update' => true] ); + PluginProcessmakerNotificationTargetProcessmaker::restoreNotificationState($donotif); + + // Notification management + // search if at least one active notification is existing for that pm task with that event 'task_update_'.$glpi_task->fields['taskcategories_id'] + $res = PluginProcessmakerNotificationTargetTask::getNotifications('task_update', $glpi_task->fields['taskcategories_id'], $this->fields['entities_id']); + if ($res['notifications'] && count($res['notifications']) > 0) { + $pm_task = new PluginProcessmakerTask($pm_task_row['itemtype']); + $pm_task->getFromDB($pm_task_row['items_id']); + NotificationEvent::raiseEvent($res['event'], + $pm_task, + ['plugin_processmaker_cases_id' => $this->getID(), + 'itemtype' => $pm_task_row['itemtype'], + 'task_id' => $glpi_task->getID(), + 'old_users_id_tech' => $glpi_task->oldvalues['users_id_tech'], + 'is_private' => isset($glpi_task->fields['is_private']) ? $glpi_task->fields['is_private'] : 0, + 'entities_id' => $this->fields['entities_id'], + 'case' => $this + ]); + } else { + $item = new $itilobject_itemtype; + $item->getFromDB($glpi_task->fields[$foreignkey]); + NotificationEvent::raiseEvent('update_task', + $item, + ['plugin_processmaker_cases_id' => $this->getID(), + 'itemtype' => $pm_task_row['itemtype'], + 'task_id' => $glpi_task->getID(), + 'is_private' => isset($glpi_task->fields['is_private']) ? $glpi_task->fields['is_private'] : 0 + ]); + } // then update the delIndex and delThread //$query = "UPDATE glpi_plugin_processmaker_tasks SET del_index = $newDelIndex, del_thread = $newDelThread WHERE id={$row['id']}; "; @@ -294,7 +317,7 @@ public function reassignTask ($delIndex, $newDelIndex, $delThread, $newDelThread 'del_index' => $newDelIndex, 'del_thread' => $newDelThread ], [ - 'id' => $row['id'] + 'id' => $pm_task_row['id'] ] ); } @@ -694,14 +717,14 @@ static function showForItem(CommonITILObject $item) { $condition[] = ['is_active' => 1]; if ($itemtype == 'Ticket') { $condition[] = ['is_incident' => 1]; - $is_itemtype = "AND is_incident=1"; + //$is_itemtype = "AND is_incident=1"; if ($item->fields['type'] == Ticket::DEMAND_TYPE) { $condition[] = ['is_request' => 1]; - $is_itemtype = "AND is_request=1"; + //$is_itemtype = "AND is_request=1"; } } else { $condition[] = ['is_'.strtolower($itemtype) => 1]; - $is_itemtype = "AND is_".strtolower($itemtype)."=1"; + //$is_itemtype = "AND is_".strtolower($itemtype)."=1"; } PluginProcessmakerProcess::dropdown(['value' => 0, 'entity' => $item->fields['entities_id'], diff --git a/inc/config.class.php b/inc/config.class.php index e8c6ed2..0caee15 100644 --- a/inc/config.class.php +++ b/inc/config.class.php @@ -326,9 +326,6 @@ function parseUrl( url ) { foreach ($res as $row) { $pmGroups[ $row['CON_ID'] ] = $row['CON_VALUE']; } - //foreach ($PM_DB->request( $query ) as $row) { - // $pmGroups[ $row['CON_ID'] ] = $row['CON_VALUE']; - //} Dropdown::showFromArray( 'pm_group_guid', $pmGroups, ['value' => $config->fields['pm_group_guid']] ); } else { echo "".__('Not connected'); diff --git a/inc/notificationtargetcase.class.php b/inc/notificationtargetcase.class.php new file mode 100644 index 0000000..7e74e32 --- /dev/null +++ b/inc/notificationtargetcase.class.php @@ -0,0 +1,120 @@ + __('Send email', 'processmaker')]; + } + + + /** + * Summary of addAdditionalTargets + * @param mixed $event + */ + function addAdditionalTargets($event = '') { + $this->notification_targets = []; + $this->notification_targets_labels = []; + $this->addTarget(self::RECIPIENTS, __('eMail recipients', 'processmaker'), self::EMAIL_RECIPIENTS); + } + + + /** + * Summary of addSpecificTargets + * @param mixed $data + * @param mixed $options + */ + function addSpecificTargets($data, $options) { + + // test if we are in the good notification + // then in this case add the targets from the ['recipients'] + if (isset($options['glpi_send_email'])) { + // normalize $options['glpi_send_email'] to an array of email parameters + $options['glpi_send_email'] = isset($options['glpi_send_email']['notifications_id']) ? [$options['glpi_send_email']] : $options['glpi_send_email']; + + foreach($options['glpi_send_email'] as $params) { + if (isset($params['notifications_id']) + && $params['notifications_id'] == $data['notifications_id']) { + //Look for all targets whose type is Notification::ITEM_USER + switch ($data['type']) { + case self::EMAIL_RECIPIENTS: + + switch ($data['items_id']) { + + case self::RECIPIENTS : + $this->addUsers($params); + break; + } + } + } + } + } + + // if no target is added to $this, then the notification will not be sent. + + } + + + /** + * Add users from $options['glpi_send_email']['to'] + * + * @param array $email_param should contain 'recipients' + * + * @return void + */ + function addUsers($email_param = []) { + global $DB, $CFG_GLPI; + + if (isset($email_param['recipients'])) { + $id_list = []; // for users with ids + $email_list = []; // for standalone emails + + // normalize into array the recipient list + $email_param['recipients'] = is_array($email_param['recipients']) ? $email_param['recipients'] : [$email_param['recipients']]; + foreach ($email_param['recipients'] as $user) { + if (is_numeric($user)) { + $id_list[] = intval($user); + } else { + $email_list[] = $user; + } + } + + $query = $this->getDistinctUserSql()." + FROM `glpi_users` ". + $this->getProfileJoinSql()." + WHERE `glpi_users`.`id` IN (".implode(',', $id_list).")"; + + foreach ($DB->request($query) as $data) { + $this->addToRecipientsList($data); + } + + foreach($email_list as $email){ + $this->addToRecipientsList([ + 'email' => $email, + 'language' => $CFG_GLPI["language"], + 'users_id' => -1 + ]); + } + } + } + +} diff --git a/inc/notificationtargetprocessmaker.class.php b/inc/notificationtargetprocessmaker.class.php new file mode 100644 index 0000000..8179c1a --- /dev/null +++ b/inc/notificationtargetprocessmaker.class.php @@ -0,0 +1,168 @@ + __('Process category', 'processmaker'), + 'process.categoryid' => __('Process category id', 'processmaker'), + 'process.categorycomment' => __('Process category comment', 'processmaker'), + 'case.id' => __('Case id', 'processmaker'), + 'case.title' => __('Case title', 'processmaker'), + 'case.description' => __('Case description', 'processmaker'), + 'case.url' => __('URL'), + 'var.XXX' => __('Case variable \'XXX\'', 'processmaker'), + 'array.YYY' => __('List of values in \'YYY\' array', 'processmaker'), + 'array.numberofYYY' => __('Number of rows in \'YYY\' array', 'processmaker'), + 'array.YYY.colname' => __('Value for colname in case array \'YYY\'', 'processamker') + ]; + + foreach ($tags as $tag => $label) { + $elt= ['tag' => $tag, + 'label' => $label, + 'value' => true]; + if ($tag == 'var.XXX') { + $elt['allowed_values'] = [__('XXX is to be replaced by any case variable names', 'processmaker')]; + } + if ($tag == 'array.YYY') { + $elt['allowed_values'] = [__('YYY is to be replaced by any array variables', 'processmaker')]; + $elt['foreach'] = true; + } + $this->addTagToList($elt); + } + + asort($this->tag_descriptions); + } + + + /** + * Get all data needed for template processing + **/ + public function addDataForTemplate($event, $options = []) { + global $PM_DB, $CFG_GLPI; + + $excluded = ['_VAR_CHANGED_', + 'PIN', + 'APPLICATION', + 'PROCESS', + 'TASK', + 'INDEX', + 'USER_LOGGED', + 'USR_USERNAME', + 'APP_NUMBER', + 'GLPI_.*', + 'SYS_.*' + ]; + + $process = new PluginProcessmakerProcess; + + $process->getFromDB($options['case']->fields['plugin_processmaker_processes_id']); + $taskcat_id = $process->fields['taskcategories_id']; + + // set defaults to all + foreach ($this->tags as $key => $val) { + $this->data["##$key##"] = "-"; + } + + // get case variable values + $res = $PM_DB->query("SELECT APP_DATA, APP_TITLE, APP_DESCRIPTION FROM APPLICATION WHERE APP_NUMBER = ".$options['case']->fields['id']); + if ($res && $PM_DB->numrows($res) == 1) { + // get all the case variables from $PM_DB + $caserow = $PM_DB->fetch_assoc($res); + $case_variables = unserialize($caserow['APP_DATA']); + $excluded_re = '/^(' . implode('|', $excluded) . ')$/u'; + foreach ($case_variables as $key => $val) { + if (!preg_match($excluded_re, $key)) { + if (is_array($val)) { + // add numberof for count of rows + $this->data["##array.numberof$key##"] = count($val); + // get the keys/vals of the sub-array + foreach ($val as $row) { + foreach ($row as $col_name => $col_val) { + $this->data["array.$key"][]["##array.$key.$col_name##"] = $col_val; + $this->data["##lang.array.$key.$col_name##"] = $col_name; + } + } + } else { + $this->data["##var.$key##"] = $val; + $this->data["##lang.var.$key##"] = $key; + } + } + } + $this->data['##case.title##'] = $caserow['APP_TITLE']; + $this->data['##case.description##'] = $caserow['APP_DESCRIPTION']; + } + + // case id + $this->data['##case.id##'] = $options['case']->fields['id']; + + // case URL + $this->data['##case.url##'] = $CFG_GLPI["url_base"]."/index.php?redirect=".urlencode("/plugins/processmaker/front/case.form.php?id=".$options['case']->fields['id']); + + // parent task information: meta data on process + // will get parent of task which is the process task category + $tmp_taskcatinfo['name'] = DropdownTranslation::getTranslatedValue( $taskcat_id, 'TaskCategory', 'name'); + $tmp_taskcatinfo['comment'] = DropdownTranslation::getTranslatedValue( $taskcat_id, 'TaskCategory', 'comment'); + // process title + $this->data['##process.categoryid##'] = $taskcat_id; + $this->data['##process.category##'] = $tmp_taskcatinfo['name']; + $this->data['##process.categorycomment##'] = $tmp_taskcatinfo['comment']; + + // add labels + $this->getTags(); + foreach ($this->tag_descriptions[NotificationTarget::TAG_LANGUAGE] as $tag => $values) { + if (!isset($this->data[$tag])) { + $this->data[$tag] = $values['label']; + } + } + } + +} \ No newline at end of file diff --git a/inc/notificationtargettask.class.php b/inc/notificationtargettask.class.php new file mode 100644 index 0000000..948be21 --- /dev/null +++ b/inc/notificationtargettask.class.php @@ -0,0 +1,320 @@ + ['event' => 'task_add_', 'label' => __('New task')], + 'task_update' => ['event' => 'task_update_', 'label' => __('Update of a task')] + ]; + } + + + /** + * Summary of getNotification + * @param mixed $evt + * @param mixed $taskcat + * @param mixed $entity + * @return array + */ + static function getNotifications($evt, $taskcat, $entity) { + // search if at least one active notification is existing for that pm task with that event 'task_update_'.$glpi_task->fields['taskcategories_id'] + $defaultEvents = self::getDefaultEvents(); + $event = $defaultEvents[$evt]['event'].$taskcat; + $dbu = new DbUtils; + $crit = $dbu->getEntitiesRestrictCriteria(Notification::getTable(), 'entities_id', $entity, true); + return ['event' => $event, 'notifications' => $dbu->getAllDataFromTable(Notification::getTable(), ['itemtype' => 'PluginProcessmakerTask', 'event' => $event, 'is_active' => 1, $crit])]; + } + + + /** + * Summary of getEvents + * @return string[] + */ + public function getEvents() { + global $DB; + $actions = []; + + $defaultEvents = self::getDefaultEvents(); + + $table = PluginProcessmakerTaskCategory::getTable(); + $ptable = PluginProcessmakerProcess::getTable(); + $query = "SELECT $table.taskcategories_id AS taskcat, $ptable.taskcategories_id AS ptaskcat FROM $table + LEFT JOIN $ptable ON $ptable.id=$table.plugin_processmaker_processes_id + WHERE $table.is_active = 1 + AND $ptable.is_active = 1"; + + $ptaskcats = []; + $temp = new TaskCategory; + foreach ($DB->request($query) as $row) { + if (!isset($ptaskcats[$row['ptaskcat']])) { + $temp->getFromDB($row['ptaskcat']); + $ptaskcats[$row['ptaskcat']] = $temp->fields['name']; + } + $temp->getFromDB($row['taskcat']); + + $actions[$defaultEvents['task_add']['event'].$row['taskcat']] = $ptaskcats[$row['ptaskcat']]." > ".$temp->fields['name'].": " . $defaultEvents['task_add']['label']; + $actions[$defaultEvents['task_update']['event'].$row['taskcat']] = $ptaskcats[$row['ptaskcat']]." > ".$temp->fields['name'].": " . $defaultEvents['task_update']['label']; + } + + return $actions; + } + + + /** + * Get all data needed for template processing + **/ + public function addDataForTemplate($event, $options = []) { + global $PM_DB, $CFG_GLPI; + + if (!isset($options['case'])) { + $mycase = new PluginProcessmakerCase; + $mycase->getFromDB($options['plugin_processmaker_cases_id']); + $options['case'] = $mycase; + } + parent::addDataForTemplate($event, $options); + + $events = self::getDefaultEvents(); + $locevent = explode('_', $event); + $baseevent = $locevent[0].'_'.$locevent[1]; + $taskcat_id = $locevent[2]; + + // task action: add or update + $this->data['##task.action##'] = $events[$baseevent]['label']; + + // task category information: meta data on task + $tmp_taskcatinfo['name'] = DropdownTranslation::getTranslatedValue( $taskcat_id, 'TaskCategory', 'name'); + $tmp_taskcatinfo['comment'] = DropdownTranslation::getTranslatedValue( $taskcat_id, 'TaskCategory', 'comment'); + $this->data['##task.categoryid##'] = $taskcat_id; + $this->data['##task.category##'] = $tmp_taskcatinfo['name']; + $this->data['##task.categorycomment##'] = $tmp_taskcatinfo['comment']; + + // task information + $taskobj = $this->obj; + + // is private? + $this->data['##task.isprivate##'] = Dropdown::getYesNo(false); + if ($taskobj->maybePrivate()) { + $this->data['##task.isprivate##'] = Dropdown::getYesNo($taskobj->fields['is_private']); + } + // status + $this->data['##task.status##'] = Planning::getState($taskobj->fields['state']); + // creation date + $this->data['##task.date##'] = Html::convDateTime($taskobj->fields['date_creation']); + // update date + $this->data['##task.update##'] = Html::convDateTime($taskobj->fields['date_mod']); + // content: don't know if this could be interesting + $this->data['##task.description##'] = $taskobj->fields['content']; + + // task creator + // should always be Process Maker user + $dbu = new DbUtils(); + $this->data['##task.author##'] = Html::clean($dbu->getUserName($taskobj->fields['users_id'])); + + // task editor + $this->data['##task.lastupdater##'] = Html::clean($dbu->getUserName($taskobj->fields['users_id_editor'])); + + // task technician + $this->data['##task.user##'] = Html::clean($dbu->getUserName($taskobj->fields['users_id_tech'])); + + // task group technician + $this->data['##task.group##'] = Html::clean(Toolbox::clean_cross_side_scripting_deep(Dropdown::getDropdownName("glpi_groups", $taskobj->fields['groups_id_tech'])), true, 2, false); + + // task planning + $this->data['##task.begin##'] = ''; + $this->data['##task.end##'] = ''; + if (!is_null($taskobj->fields['begin'])) { + $this->data['##task.begin##'] = Html::convDateTime($taskobj->fields['begin']); + $this->data['##task.end##'] = Html::convDateTime($taskobj->fields['end']); + } + // task duration + $this->data['##task.time##'] = Html::timestampToString($taskobj->fields['actiontime'], false); + + // add labels + $this->getTags(); + foreach ($this->tag_descriptions[NotificationTarget::TAG_LANGUAGE] as $tag => $values) { + if (!isset($this->data[$tag])) { + $this->data[$tag] = $values['label']; + } + } + } + + + /** + * Summary of getTags + */ + public function getTags() { + + parent::getTags(); + + $tags = ['task.action' => __('Task action', 'processmaker'), + 'task.author' => __('Writer'), + 'task.isprivate' => __('Private'), + 'task.date' => __('Opening date'), + 'task.description' => __('Description'), + 'task.categoryid' => __('Category id'), + 'task.category' => __('Category'), + 'task.categorycomment' => __('Category comment'), + 'task.time' => __('Total duration'), + 'task.user' => __('User assigned to task'), + 'task.group' => __('Group assigned to task'), + 'task.begin' => __('Start date'), + 'task.end' => __('End date'), + 'task.status' => __('Status'), + 'task.lastupdater' => __('Last updater'), + 'task.update' => __('Last update') + ]; + foreach ($tags as $tag => $label) { + $elt= ['tag' => $tag, + 'label' => $label, + 'value' => true]; + + $this->addTagToList($elt); + } + asort($this->tag_descriptions); + } + + + /** + * Summary of addAdditionalTargets + * @param mixed $event + */ + function addAdditionalTargets($event = '') { + + $this->addTarget(Notification::TASK_ASSIGN_TECH, __('Technician in charge of the task')); + $this->addTarget(Notification::TASK_ASSIGN_GROUP, __('Group in charge of the task')); + + if (strpos($event, 'task_update_') === 0) { + $this->addTarget(Notification::OLD_TECH_IN_CHARGE, + __('Former technician in charge of the task')); + } + + } + + + /** + * Summary of addSpecificTargets + * @param mixed $data + * @param mixed $options + */ + function addSpecificTargets($data, $options) { + + //Look for all targets whose type is Notification::ITEM_USER + switch ($data['type']) { + case Notification::USER_TYPE : + + switch ($data['items_id']) { + + //Send to the ITIL object followup author + case Notification::TASK_ASSIGN_TECH : + $this->addTaskAssignUser($options); + break; + + //Send to the ITIL object task group assigned + case Notification::TASK_ASSIGN_GROUP : + $this->addTaskAssignGroup($options); + break; + + //Send to the technician previously in charge of the task (before re-assignment) + case Notification::OLD_TECH_IN_CHARGE : + $this->addOldAssignTechnician($options); + break; + + } + } + } + + + /** + * Add user assigned to task + * + * @param array $options Options + * + * @return void + */ + function addTaskAssignUser($options = []) { + global $DB; + + // In case of delete task pass user id + if (isset($options['task_users_id_tech'])) { + $query = $this->getDistinctUserSql()." + FROM `glpi_users` ". + $this->getProfileJoinSql()." + WHERE `glpi_users`.`id` = '".$options['task_users_id_tech']."'"; + + foreach ($DB->request($query) as $data) { + $this->addToRecipientsList($data); + } + } else if (isset($options['task_id'])) { + $dbu = new DbUtils; + $tasktable = $dbu->getTableForItemType($options['itemtype']); //getTableForItemType($this->obj->getType().'Task'); + + $query = $this->getDistinctUserSql()." + FROM `$tasktable` + INNER JOIN `glpi_users` + ON (`glpi_users`.`id` = `$tasktable`.`users_id_tech`)". + $this->getProfileJoinSql()." + WHERE `$tasktable`.`id` = '".$options['task_id']."'"; + + foreach ($DB->request($query) as $data) { + $this->addToRecipientsList($data); + } + } + } + + + /** + * Add group assigned to the task + * + * @param array $options Options + * + * @return void + */ + function addTaskAssignGroup($options = []) { + global $DB; + + // In case of delete task pass user id + if (isset($options['task_groups_id_tech'])) { + $this->addForGroup(0, $options['task_groups_id_tech']); + + } else if (isset($options['task_id'])) { + $dbu = new DbUtils; + $tasktable = $dbu->getTableForItemType($options['itemtype']); //getTableForItemType($this->obj->getType().'Task'); + foreach ($DB->request([$tasktable, 'glpi_groups'], "`glpi_groups`.`id` = `$tasktable`.`groups_id_tech` + AND `$tasktable`.`id` = '".$options['task_id']."'") as $data) { + $this->addForGroup(0, $data['groups_id_tech']); + } + } + } + + + function addOldAssignTechnician($options = []) { + global $DB; + + // In case of delete task pass user id + if (isset($options['old_users_id_tech'])) { + $query = $this->getDistinctUserSql()." + FROM `glpi_users` ". + $this->getProfileJoinSql()." + WHERE `glpi_users`.`id` = '".$options['old_users_id_tech']."'"; + + foreach ($DB->request($query) as $data) { + $this->addToRecipientsList($data); + } + } + } + +} diff --git a/inc/process.class.php b/inc/process.class.php index f0816a5..704da48 100644 --- a/inc/process.class.php +++ b/inc/process.class.php @@ -190,7 +190,7 @@ function refreshTasks($post) { ] ); } // here we should take into account translations if any - if ( isset($taskArray[ $taskGUID ])) { + if (isset($taskArray[ $taskGUID ])) { foreach ($taskArray[ $taskGUID ] as $langTask => $taskL) { // look for 'name' field if ($loc_id = DropdownTranslation::getTranslationID( $taskCat->getID(), 'TaskCategory', 'name', $langTask )) { @@ -318,7 +318,7 @@ function refresh() { ); //$query = "SELECT * FROM `".PluginProcessmakerCase::getTable()."` WHERE `plugin_processmaker_processes_id` = ".$key; //$res = $DB->query($query); - if ($DB->numrows($res) === 0) { + if ($res->numrows() === 0) { // and if no will delete the process $proc->delete(['id' => $key]); // delete main taskcat @@ -815,13 +815,13 @@ function showForm ($ID, $options = ['candel'=>false]) { * @param $count true if execute an count(*), * @param $search pattern * - * @return mysql result set. + * @return DBmysqlIterator. **/ static function getSqlSearchResult ($count = true, $search = []) { global $DB, $CFG_GLPI; $query = []; - $where = ''; - $orderby = ''; + //$where = ''; + //$orderby = ''; if (isset($_REQUEST['condition']) && isset($_SESSION['glpicondition'][$_REQUEST['condition']])) { //$where = ' WHERE '.$_SESSION['glpicondition'][$_REQUEST['condition']]; //glpi_plugin_processmaker_processes.is_active=1 '; @@ -838,7 +838,7 @@ static function getSqlSearchResult ($count = true, $search = []) { //$orderby = " ORDER BY glpi_plugin_processmaker_processes.name ASC"; } - if (!empty($search) && $search!=$CFG_GLPI["ajax_wildcard"]) { + if (!empty($search) && $search != $CFG_GLPI["ajax_wildcard"]) { $query['WHERE']['AND']['OR']['glpi_plugin_processmaker_processes.name'] = $search; $query['WHERE']['AND']['OR']['glpi_plugin_processmaker_processes.comment'] = $search; //$where .= " AND (glpi_plugin_processmaker_processes.name $search @@ -847,7 +847,7 @@ static function getSqlSearchResult ($count = true, $search = []) { $query['FROM'] = 'glpi_plugin_processmaker_processes'; //$query = "SELECT $fields FROM glpi_plugin_processmaker_processes ".$where." ".$orderby.";"; //return $DB->query($query); - $r= $DB->request($query); + //$r= $DB->request($query); return $DB->request($query); } @@ -858,7 +858,7 @@ static function getSqlSearchResult ($count = true, $search = []) { * @return mixed */ static function getProcessName($pid, $link = 0) { - global $DB; + global $DB, $CFG_GLPI; $process=''; if ($link==2) { $process = ["name" => "", @@ -872,8 +872,10 @@ static function getProcessName($pid, $link = 0) { //if ($result && $DB->numrows($result)==1) { // $data = $DB->fetch_assoc($result); if ($res && $res->numrows() == 1) { - $processname = $res['name'];//$data["name"]; - if ($link==2) { +// $processname = $res['name'];//$data["name"]; + $data = $res->next(); + $processname = $data["name"]; + if ($link == 2) { $process["name"] = $processname; $process["link"] = $CFG_GLPI["root_doc"]."/plugins/processmaker/front/process.form.php?id=".$pid; $process["comment"] = __('Name')." : ".$processname."
".__('Comments'). @@ -908,10 +910,10 @@ static function getEntitiesForProfileByProcess($processes_id, $profiles_id, $chi ] ] ]); - $query = "SELECT `entities_id`, `is_recursive` - FROM `glpi_plugin_processmaker_processes_profiles` - WHERE `plugin_processmaker_processes_id` = '$processes_id' - AND `profiles_id` = '$profiles_id'"; + //$query = "SELECT `entities_id`, `is_recursive` + // FROM `glpi_plugin_processmaker_processes_profiles` + // WHERE `plugin_processmaker_processes_id` = '$processes_id' + // AND `profiles_id` = '$profiles_id'"; $entities = []; //foreach ($DB->request($query) as $data) { @@ -961,6 +963,5 @@ static function showUnderMaintenance($ptitle, $size = '') { echo "

"; echo ""; } - } diff --git a/inc/processmaker.class.php b/inc/processmaker.class.php index 3f74361..dede130 100644 --- a/inc/processmaker.class.php +++ b/inc/processmaker.class.php @@ -114,8 +114,8 @@ static function getTable($classname = null) { static function getAllPMErrorArray() { $tab = [self::ERROR_CREATING_CASE => _x('errors', 'Error creating case!', 'processmaker'), - self::ERROR_NO_RIGHTS => _x('errors', 'Can\'t create case: no rights for it!', 'processmaker'), - self::ERROR_CREATING_CASE2 => _x('errors', 'Error creating case!', 'processmaker')]; + self::ERROR_NO_RIGHTS => _x('errors', 'Can\'t create case: no rights for it!', 'processmaker'), + self::ERROR_CREATING_CASE2 => _x('errors', 'Error creating case!', 'processmaker')]; return $tab; } @@ -145,18 +145,28 @@ public function addItemFollowup($itemtype, $itemId, $txtForFollowup, $users_id = $fu = new ITILFollowup();//new TicketFollowup(); $fu->getEmpty(); // to get default values $input = $fu->fields; + if (isset( $txtForFollowup['GLPI_TICKET_FOLLOWUP_CONTENT'] )) { + $input['content'] = $DB->escape($txtForFollowup['GLPI_TICKET_FOLLOWUP_CONTENT']); + } if (isset( $txtForFollowup['GLPI_ITEM_FOLLOWUP_CONTENT'] )) { $input['content'] = $DB->escape($txtForFollowup['GLPI_ITEM_FOLLOWUP_CONTENT']); } + if (isset( $txtForFollowup['GLPI_TICKET_FOLLOWUP_IS_PRIVATE'] )) { + $input['is_private'] = $txtForFollowup['GLPI_TICKET_FOLLOWUP_IS_PRIVATE']; + } if (isset( $txtForFollowup['GLPI_ITEM_FOLLOWUP_IS_PRIVATE'] )) { $input['is_private'] = $txtForFollowup['GLPI_ITEM_FOLLOWUP_IS_PRIVATE']; } + if (isset( $txtForFollowup['GLPI_TICKET_FOLLOWUP_REQUESTTYPES_ID'] )) { + $input['requesttypes_id'] = $txtForFollowup['GLPI_TICKET_FOLLOWUP_REQUESTTYPES_ID']; + } if (isset( $txtForFollowup['GLPI_ITEM_FOLLOWUP_REQUESTTYPES_ID'] )) { $input['requesttypes_id'] = $txtForFollowup['GLPI_ITEM_FOLLOWUP_REQUESTTYPES_ID']; } $input['items_id'] = $itemId;//$input['tickets_id'] = $itemId; $input['users_id'] = (isset($users_id) ? $users_id : Session::getLoginUserID( true )); // $this->taskWriter; $input['itemtype'] = $itemtype; + $fu->add( $input ); } @@ -1115,12 +1125,12 @@ static function cronPMTaskActions($crontask = null) { } // do not send notifications - $donotif = self::saveNotification(false); + $donotif = PluginProcessmakerNotificationTargetProcessmaker::saveNotificationState(false); // now manage tasks associated with item $PM_SOAP->claimTask( $postdata['APP_UID'], $postdata['DEL_INDEX'], $users_id ); - self::restoreNotification($donotif); + PluginProcessmakerNotificationTargetProcessmaker::restoreNotificationState($donotif); } @@ -1270,9 +1280,9 @@ static function cronPMUsers($task) { //if($pmgrp_key = array_search($PM_SOAP->pm_group_guid, array_column($pmGroupList, 'guid'))) { // $pmgroup = $pmGroupList[$pmgrp_key]; //} - foreach ($pmGroupList as $pmGroupL) { - if ($pmGroupL->guid == $PM_SOAP->pm_group_guid) { - $pmGroup = $pmGroupL; + foreach ($pmGroupList as $pmGroupList) { + if ($pmGroupList->guid == $PM_SOAP->pm_group_guid) { + $pmGroup = $pmGroupList; break; // to get the name :) } } @@ -1583,7 +1593,7 @@ public static function plugin_item_add_processmaker($parm) { if (preg_match($ptnProcessToStart, $str, $matches) > 0) { // and it is requested to start a case of process $processGuid = $matches[1]; - $hasCase = self::getCaseIdFromItem( 'Ticket', $parm->fields['id'] ); + $hasCase = self::hasCase( 'Ticket', $parm->fields['id'] ); if ($hasCase === false) { // check writer $writer = new User; @@ -1642,9 +1652,9 @@ public static function addWatcher($itemType, $itemId, $techId) { $glpi_item_user = $dbu->getItemForItemtype( $glpi_item->getType() . "_User" ); // do not send notifications - $donotif = self::saveNotification(false); + $donotif = PluginProcessmakerNotificationTargetProcessmaker::saveNotificationState(false); $glpi_item_user->add( [ $glpi_item::getForeignKeyField() => $glpi_item->getId(), 'users_id' => $techId, 'type' => CommonITILActor::OBSERVER, '_disablenotif' => true ] ); - self::restoreNotification($donotif); + PluginProcessmakerNotificationTargetProcessmaker::restoreNotificationState($donotif); return true; } } @@ -1729,6 +1739,7 @@ public function addTask($cases_id, $itemtype, $items_id, $caseInfo, $delIndex, $ $input['users_id'] = $this->taskWriter; // manage groups + $groups_id_tech = 0; if ($techId == 0) { // then we must look-up DB to get the group that will be assigned to the task $groupname=''; if ($groupId == 0) { @@ -1739,17 +1750,17 @@ public function addTask($cases_id, $itemtype, $items_id, $caseInfo, $delIndex, $ 'WHERE' => ['AND' => ['TASK_USER.TAS_UID' => $pmTaskId, 'TASK_USER.TU_RELATION' => 2]], 'LIMIT' => 1 ]); - $query = "SELECT CONTENT.CON_VALUE FROM TASK_USER - JOIN CONTENT ON CONTENT.CON_ID=TASK_USER.USR_UID AND CONTENT.CON_CATEGORY='GRP_TITLE' AND CONTENT.CON_LANG = 'en' - WHERE TASK_USER.TAS_UID='$pmTaskId' AND TASK_USER.TU_RELATION=2 LIMIT 1;"; + //$query = "SELECT CONTENT.CON_VALUE FROM TASK_USER + // JOIN CONTENT ON CONTENT.CON_ID=TASK_USER.USR_UID AND CONTENT.CON_CATEGORY='GRP_TITLE' AND CONTENT.CON_LANG = 'en' + // WHERE TASK_USER.TAS_UID='$pmTaskId' AND TASK_USER.TU_RELATION=2 LIMIT 1;"; } else { $res = $PM_DB->request([ 'SELECT' => 'CON_VALUE', 'FROM' => 'CONTENT', 'WHERE' => ['AND' => ['CONTENT.CON_ID' => $groupId, 'CONTENT.CON_CATEGORY' => 'GRP_TITLE', 'CONTENT.CON_LANG' => 'en']] ]); - $query = "SELECT CON_VALUE FROM CONTENT - WHERE CONTENT.CON_ID='$groupId' AND CONTENT.CON_CATEGORY='GRP_TITLE' AND CONTENT.CON_LANG='en' ;"; + //$query = "SELECT CON_VALUE FROM CONTENT + // WHERE CONTENT.CON_ID='$groupId' AND CONTENT.CON_CATEGORY='GRP_TITLE' AND CONTENT.CON_LANG='en' ;"; } // as there is a LIMIT of 1 // or @@ -1760,7 +1771,6 @@ public function addTask($cases_id, $itemtype, $items_id, $caseInfo, $delIndex, $ $groupname = $onlyrec['CON_VALUE']; } - $groups_id_tech = 0; $res = $DB->request([ 'SELECT' => 'id AS glpi_group_id', 'FROM' => 'glpi_groups', @@ -1814,9 +1824,9 @@ public function addTask($cases_id, $itemtype, $items_id, $caseInfo, $delIndex, $ 'field' => 'begin']; } - $donotif = self::saveNotification(false); // do not send notification yet as the PluginProcessmakerTask is not yet added to DB + $donotif = PluginProcessmakerNotificationTargetProcessmaker::saveNotificationState(false); // do not send notification yet as the PluginProcessmakerTask is not yet added to DB $glpi_task->add( Toolbox::addslashes_deep( $input ) ); - self::restoreNotification($donotif); + PluginProcessmakerNotificationTargetProcessmaker::restoreNotificationState($donotif); // to prevent error message for overlapping planning if (isset($_SESSION["MESSAGE_AFTER_REDIRECT"][WARNING])) { @@ -1838,7 +1848,7 @@ public function addTask($cases_id, $itemtype, $items_id, $caseInfo, $delIndex, $ 'plugin_processmaker_cases_id' => $cases_id, 'plugin_processmaker_taskcategories_id' => $pmtaskcat->fields['id'], 'del_index' => $delIndex, - 'del_thread' =>$delThread + 'del_thread' => $delThread ]); //$query = "INSERT INTO glpi_plugin_processmaker_tasks (items_id, itemtype, plugin_processmaker_cases_id, plugin_processmaker_taskcategories_id, del_index, del_thread) // VALUES ({$glpi_task->getId()}, '{$glpi_task->getType()}', $cases_id, {$pmtaskcat->fields['id']}, $delIndex, $delThread);"; @@ -1846,32 +1856,38 @@ public function addTask($cases_id, $itemtype, $items_id, $caseInfo, $delIndex, $ } // send notification if needed for new task as now we have the PluginProcessmakerTask in the DB - $donotif = self::saveNotification($options['notif']); + $donotif = PluginProcessmakerNotificationTargetProcessmaker::saveNotificationState($options['notif']); + // Notification management $item = new $itemtype; $item->getFromDB($items_id); - NotificationEvent::raiseEvent('add_task', $item, ['task_id' => $glpi_task->getID(), 'is_private' => isset($glpi_task->fields['is_private']) ? $glpi_task->fields['is_private'] : 0]); - self::restoreNotification($donotif); - - } - - - private static function saveNotification($donotif) { - global $CFG_GLPI; - // $CFG_GLPI["use_notifications"] is available since 9.2 - $savenotif = isset($CFG_GLPI["use_notifications"]) ? $CFG_GLPI["use_notifications"] : $CFG_GLPI["use_mailing"]; - if (!$donotif) { - isset($CFG_GLPI["use_notifications"]) ? $CFG_GLPI["use_notifications"] = false : $CFG_GLPI["use_mailing"] = false; + // search if at least one active notification is existing for that pm task with that event 'task_update_'.$glpi_task->fields['taskcategories_id'] + $res = PluginProcessmakerNotificationTargetTask::getNotifications('task_add', $glpi_task->fields['taskcategories_id'], $item->fields['entities_id']); + if ($res['notifications'] && count($res['notifications']) > 0) { + $pm_task = new PluginProcessmakerTask($glpi_task->getType()); + $pm_task->getFromDB($glpi_task->getId()); + NotificationEvent::raiseEvent($res['event'], + $pm_task, + ['plugin_processmaker_cases_id' => $cases_id, + 'itemtype' => $glpi_task->getType(), + 'task_id' => $glpi_task->getID(), + 'is_private' => isset($glpi_task->fields['is_private']) ? $glpi_task->fields['is_private'] : 0, + 'entities_id' => $item->fields['entities_id'] + ]); + } else { + NotificationEvent::raiseEvent('add_task', + $item, + ['plugin_processmaker_cases_id' => $cases_id, + 'itemtype' => $itemtype, + 'task_id' => $glpi_task->getID(), + 'is_private' => isset($glpi_task->fields['is_private']) ? $glpi_task->fields['is_private'] : 0 + ]); } - return $savenotif; - } + PluginProcessmakerNotificationTargetProcessmaker::restoreNotificationState($donotif); - private static function restoreNotification($savenotif) { - global $CFG_GLPI; - // $CFG_GLPI["use_notifications"] is available since 9.2 - isset($CFG_GLPI["use_notifications"]) ? $CFG_GLPI["use_notifications"] = $savenotif : $CFG_GLPI["use_mailing"] = $savenotif; } + /** * Summary of add1stTask * adds a GLPI task to ticket @@ -2066,7 +2082,7 @@ function computeTaskDuration($begin, $end, $entity) { public function solveTask($cases_id, $delIndex, $options = []) { global $DB; - $query = "SELECT * FROM glpi_plugin_processmaker_tasks WHERE plugin_processmaker_cases_id=$cases_id and del_index=$delIndex; "; + //$query = "SELECT * FROM glpi_plugin_processmaker_tasks WHERE plugin_processmaker_cases_id=$cases_id and del_index=$delIndex; "; //$res = $DB->query($query); $res = $DB->request('glpi_plugin_processmaker_tasks', ['AND' => ['plugin_processmaker_cases_id' => $cases_id, 'del_index' => $delIndex]]); //if ($DB->numrows($res) > 0) { @@ -2115,9 +2131,9 @@ public function solveTask($cases_id, $delIndex, $options = []) { //'groups_id_tech' => 0, 'content' => $DB->escape($glpi_task->fields[ 'content' ].$options['txtToAppend']) ]; - $donotif = self::saveNotification($options['notif']); + $donotif = PluginProcessmakerNotificationTargetProcessmaker::saveNotificationState($options['notif']); $glpi_task->update($params); - self::restoreNotification($donotif); + PluginProcessmakerNotificationTargetProcessmaker::restoreNotificationState($donotif); // Close the task //$DB->query("UPDATE glpi_plugin_processmaker_tasks SET del_thread_status = '".PluginProcessmakerTask::CLOSED."' WHERE id = {$row['id']}"); @@ -2140,7 +2156,7 @@ public function solveTask($cases_id, $delIndex, $options = []) { public function claimTask($cases_id, $delIndex, $users_id_tech = null) { global $DB; $res = $DB->request('glpi_plugin_processmaker_tasks', ['AND' => ['plugin_processmaker_cases_id' => $cases_id, 'del_index' => $delIndex]]); - $query = "SELECT * FROM glpi_plugin_processmaker_tasks WHERE plugin_processmaker_cases_id='$cases_id' and del_index=$delIndex; "; + //$query = "SELECT * FROM glpi_plugin_processmaker_tasks WHERE plugin_processmaker_cases_id='$cases_id' and del_index=$delIndex; "; //$res = $DB->query($query); //if ($DB->numrows($res) > 0) { if ($row = $res->next()) { @@ -2153,82 +2169,101 @@ public function claimTask($cases_id, $delIndex, $users_id_tech = null) { $glpi_item = $dbu->getItemForItemtype( $itemType ); $glpi_item->getFromDB( $glpi_task->fields[ getForeignKeyFieldForItemType( $itemType ) ] ); - $glpi_task->update( [ 'id' => $row['items_id'], - $glpi_item->getForeignKeyField() => $glpi_item->getId(), - 'users_id_tech' => (isset($users_id_tech)?$users_id_tech: Session::getLoginUserID()), - 'groups_id_tech' => 0 ]); - } - } - - - /** - * Summary of getCaseIdFromItem - * get case id for an id item_id of type item_type (if a case if attached to it) - * @param string $item_type, the type for the item ("Ticket", "Problem", ...) - * @param integer $item_id, the id for the item - * @return string the case guid, false if no case is attached to item, or if an error occurred - */ - public static function getCaseIdFromItem ($item_type, $item_id) { - global $DB; - $res = $DB->request('glpi_plugin_processmaker_cases', ['AND' => ['itemtype' => $item_type, 'items_id' => $item_id]]); - $query = "SELECT * FROM glpi_plugin_processmaker_cases WHERE `itemtype` = '$item_type' AND `items_id` = $item_id ;"; - // $res = $DB->query($query); - //if ($DB->numrows($res) > 0) { - // // case is existing for this item - // // then get info from db - // $row = $DB->fetch_array($res); - if ($row = $res->next()) { - return $row['id']; - } - - return false; - } + $glpi_task->update( [ 'id' => $row['items_id'], + $glpi_item->getForeignKeyField() => $glpi_item->getId(), + 'users_id_tech' => (isset($users_id_tech)?$users_id_tech: Session::getLoginUserID()), + 'groups_id_tech' => 0, + 'update' => true]); + } + } + + + // /** + // * Summary of getCaseIdFromItem + // * get case id for an id item_id of type item_type (if a case if attached to it) + // * @param string $item_type, the type for the item ("Ticket", "Problem", ...) + // * @param integer $item_id, the id for the item + // * @return string the case guid, false if no case is attached to item, or if an error occurred + // */ + //public static function getCaseIdFromItem ($item_type, $item_id) { + // global $DB; + // $res = $DB->request('glpi_plugin_processmaker_cases', ['AND' => ['itemtype' => $item_type, 'items_id' => $item_id]]); + // //$query = "SELECT * FROM glpi_plugin_processmaker_cases WHERE `itemtype` = '$item_type' AND `items_id` = $item_id ;"; + // // $res = $DB->query($query); + // //if ($DB->numrows($res) > 0) { + // // // case is existing for this item + // // // then get info from db + // // $row = $DB->fetch_array($res); + // if ($row = $res->next()) { + // return $row['id']; + // } + + // return false; + //} /** - * Summary of getCaseGuidFromItem - * get case id for an id item_id of type item_type (if a case if attached to it) + * Summary of hasCase + * returns true if cases are attached to item, false otherwise * @param string $item_type, the type for the item ("Ticket", "Problem", ...) * @param integer $item_id, the id for the item - * @return string the case guid, false if no case is attached to item, or if an error occurred + * @return boolean true if at least one case is attached, otherwise false */ - public static function getCaseGuidFromItem ($item_type, $item_id) { + public static function hasCase($item_type, $item_id) { global $DB; $res = $DB->request('glpi_plugin_processmaker_cases', ['AND' => ['itemtype' => $item_type, 'items_id' => $item_id]]); - $query = "SELECT * FROM glpi_plugin_processmaker_cases WHERE `itemtype` = '$item_type' AND `items_id` = $item_id ;"; - //$res = $DB->query($query); - //if ($DB->numrows($res) > 0) { - // // case is existing for this item - // // then get info from db - // $row = $DB->fetch_array($res); - if ($row = $res->next()) { - return $row['case_guid']; + if ($res->numrows() > 0) { + return true; } return false; } - /** - * Summary of getCaseFromItem - * get case infos for an id item_id of type item_type (if a case if attached to it) - * @param string $item_type, the type for the item ("Ticket", "Problem", ...) - * @param integer $item_id, the id for the item - * @return getCaseInfoResponse object, false if no case is attached to item, or if an error occurred - */ - public function getCaseFromItem($item_type, $item_id) { - global $DB; - $caseId = self::getCaseGuidFromItem( $item_type, $item_id ); - if ($caseId !== false) { - $caseInfo = $this->getCaseInfo( $caseId ); - if ($caseInfo !== false && $caseInfo->status_code == 0) { - return $caseInfo; - } else { - return false; // means any error - } - } else { - return false; // means no case - } - } + ///** + // * Summary of getCaseGuidFromItem + // * get case id for an id item_id of type item_type (if a case if attached to it) + // * @param string $item_type, the type for the item ("Ticket", "Problem", ...) + // * @param integer $item_id, the id for the item + // * @return string the case guid, false if no case is attached to item, or if an error occurred + // */ + //public static function getCaseGuidFromItem ($item_type, $item_id) { + // global $DB; + // $res = $DB->request('glpi_plugin_processmaker_cases', ['AND' => ['itemtype' => $item_type, 'items_id' => $item_id]]); + // //$query = "SELECT * FROM glpi_plugin_processmaker_cases WHERE `itemtype` = '$item_type' AND `items_id` = $item_id ;"; + // //$res = $DB->query($query); + // //if ($DB->numrows($res) > 0) { + // // // case is existing for this item + // // // then get info from db + // // $row = $DB->fetch_array($res); + // if ($row = $res->next()) { + // return $row['case_guid']; + // } + + // return false; + //} + + // /** + // * Summary of getCaseFromItem + // * get case infos for an id item_id of type item_type (if a case if attached to it) + // * @param string $item_type, the type for the item ("Ticket", "Problem", ...) + // * @param integer $item_id, the id for the item + // * @return getCaseInfoResponse object, false if no case is attached to item, or if an error occurred + // */ + //public function getCaseFromItem($item_type, $item_id) { + // global $DB; + + // $caseId = self::getCaseGuidFromItem( $item_type, $item_id ); + // if ($caseId !== false) { + // $caseInfo = $this->getCaseInfo( $caseId ); + // if ($caseInfo !== false && $caseInfo->status_code == 0) { + // return $caseInfo; + // } else { + // return false; // means any error + // } + // } else { + // return false; // means no case + // } + //} /** * Summary of multiexplode @@ -2451,10 +2486,10 @@ public static function getItemUsers($itemtype, $itemId, $userType) { 'WHERE' => ['AND' => ["$item_userstable.$itemlink" => $itemId, "$item_userstable.type" => $userType]], 'ORDER' => ['ORDER' => $item_userstable.'.id'] ]); - $query = "select glpi_plugin_processmaker_users.pm_users_id as pm_users_id, glpi_plugin_processmaker_users.id as id from $item_userstable - left join glpi_plugin_processmaker_users on glpi_plugin_processmaker_users.id = $item_userstable.users_id - where $item_userstable.$itemlink = $itemId and $item_userstable.type = $userType - order by $item_userstable.id"; + //$query = "select glpi_plugin_processmaker_users.pm_users_id as pm_users_id, glpi_plugin_processmaker_users.id as id from $item_userstable + // left join glpi_plugin_processmaker_users on glpi_plugin_processmaker_users.id = $item_userstable.users_id + // where $item_userstable.$itemlink = $itemId and $item_userstable.type = $userType + // order by $item_userstable.id"; //foreach ($DB->request( $query ) as $dbuser) { foreach ($res as $dbuser) { $users[] = [ 'glpi_id' => $dbuser['id'], 'pm_id' => $dbuser['pm_users_id'] ]; @@ -2612,9 +2647,9 @@ function urldecode(url) { public static function plugin_item_get_data_processmaker($item) { global $_SESSION, $CFG_GLPI; if (isset( $item->data ) && isset( $item->data['tasks'] )) { + $pmtask_itemtype = $item->obj->getType().'Task'; $pmtask = new PluginProcessmakerTask($pmtask_itemtype); foreach ($item->data['tasks'] as &$task) { - $pmtask_itemtype = $item->obj->getType().'Task'; $pmtask_items_id = $task['##task.id##']; // for each task, we must check if it is in our task table @@ -2897,12 +2932,18 @@ public function derivateCase($myCase, $request, $users_id = null) { "GLPI_ITEM_SET_SOLUTION_TYPE_ID", "GLPI_ITEM_APPEND_TO_SOLUTION_DESCRIPTION", "GLPI_ITEM_INITIAL_DUE_DATE", - "GLPI_ITEM_DUE_DATE" + "GLPI_ITEM_DUE_DATE", + "GLPI_SEND_EMAIL" ]; // now tries to get some variables to setup content for new task and to append text to solved task $casevariablevalues = $myCase->getVariables($casevariables); + $sendemail = ''; + if (array_key_exists( 'GLPI_SEND_EMAIL', $casevariablevalues ) && $casevariablevalues[ 'GLPI_SEND_EMAIL' ] != '') { + $sendemail = json_decode($casevariablevalues[ 'GLPI_SEND_EMAIL' ], true); + } + $itemSetStatus = ''; if (array_key_exists( 'GLPI_ITEM_SET_STATUS', $casevariablevalues )) { $itemSetStatus = $casevariablevalues[ 'GLPI_ITEM_SET_STATUS' ]; @@ -2968,9 +3009,8 @@ public function derivateCase($myCase, $request, $users_id = null) { } $createFollowup = false; // by default - if (array_key_exists( 'GLPI_ITEM_FOLLOWUP_CONTENT', $casevariablevalues ) && $casevariablevalues[ 'GLPI_ITEM_FOLLOWUP_CONTENT' ] != '') { - //&& array_key_exists( 'GLPI_TICKET_FOLLOWUP_IS_PRIVATE', $infoForTasks ) - //&& array_key_exists( 'GLPI_TICKET_FOLLOWUP_REQUESTTYPES_ID', $infoForTasks ) + if ((array_key_exists( 'GLPI_TICKET_FOLLOWUP_CONTENT', $casevariablevalues ) && $casevariablevalues[ 'GLPI_TICKET_FOLLOWUP_CONTENT' ] != '') + || (array_key_exists( 'GLPI_ITEM_FOLLOWUP_CONTENT', $casevariablevalues ) && $casevariablevalues[ 'GLPI_ITEM_FOLLOWUP_CONTENT' ] != '')) { $createFollowup = true; } @@ -3008,7 +3048,7 @@ public function derivateCase($myCase, $request, $users_id = null) { ] ); // create a followup if requested - if ($createFollowup && $itemtype == 'Ticket') { + if ($createFollowup) { // && $itemtype == 'Ticket') { $this->addItemFollowup( $itemtype, $items_id, $casevariablevalues ); } @@ -3059,8 +3099,9 @@ public function derivateCase($myCase, $request, $users_id = null) { ] ] ]); - $res = $PM_DB->query("SELECT APP_UID FROM SUB_APPLICATION WHERE APP_PARENT='{$myCase->fields['case_guid']}' AND DEL_INDEX_PARENT={$route->delIndex} AND SA_STATUS='ACTIVE'"); // AND DEL_THREAD_PARENT={$route->delThread} seems like it is not set to correct threadIndex - if ($row = $res->next() && $PM_DB->numrows($res) == 1) { + //$res = $PM_DB->query("SELECT APP_UID FROM SUB_APPLICATION WHERE APP_PARENT='{$myCase->fields['case_guid']}' AND DEL_INDEX_PARENT={$route->delIndex} AND SA_STATUS='ACTIVE'"); // AND DEL_THREAD_PARENT={$route->delThread} seems like it is not set to correct threadIndex + //if ($row = $res->next() && $PM_DB->numrows($res) == 1) { + if ($res->numrows() == 1 && $row = $res->next()) { // then new task is a sub-process, //$row = $PM_DB->fetch_assoc($res); @@ -3196,7 +3237,16 @@ public function derivateCase($myCase, $request, $users_id = null) { } } - } + // send email if requested + if (is_array($sendemail)) { + NotificationEvent::raiseEvent('send_email', + $myCase, + ['glpi_send_email' => $sendemail, + 'case' => $myCase + ]); + } + + } } else { // must check if current case is a sub-process, and if it has ended, then must reflect parent case into the current item. @@ -3211,7 +3261,7 @@ public function derivateCase($myCase, $request, $users_id = null) { foreach ($parentCaseInfo->currentUsers as $open_task) { // must check if $open_task is not is_subprocess and is not already existing in the item $locTaskCat = new PluginProcessmakerTaskCategory; - $locTask = new PluginProcessmakerTask(); + $locTask = new PluginProcessmakerTask($itemtype.'Task'); $locTaskRestrict=[ 'WHERE' => [ @@ -3253,6 +3303,15 @@ public function derivateCase($myCase, $request, $users_id = null) { // evolution of case status: DRAFT, TO_DO, COMPLETED, CANCELLED $myCase->update( [ 'id' => $myCase->getID(), 'case_status' => $caseInfo->caseStatus, 'name' => $caseInfo->caseName ] ); + // send email if requested + if (is_array($sendemail)) { + NotificationEvent::raiseEvent('send_email', + $myCase, + ['glpi_send_email' => $sendemail, + 'case' => $myCase + ]); + } + } @@ -3401,4 +3460,4 @@ function echoDomain() { echo Html::scriptBlock($script); } } -} +} \ No newline at end of file diff --git a/inc/task.class.php b/inc/task.class.php index c8cf125..e7c43cc 100644 --- a/inc/task.class.php +++ b/inc/task.class.php @@ -89,8 +89,8 @@ public static function getToDoTasks($case_id, $itemtype) { ] ] ]); - $query = "SELECT `$selfTable`.`items_id` as taskID from $selfTable - WHERE `$selfTable`.`del_thread_status` = '".self::OPEN."' AND `$selfTable`.`plugin_processmaker_cases_id` = '$case_id';"; + //$query = "SELECT `$selfTable`.`items_id` as taskID from $selfTable + // WHERE `$selfTable`.`del_thread_status` = '".self::OPEN."' AND `$selfTable`.`plugin_processmaker_cases_id` = '$case_id';"; //$query = "SELECT $itemTypeTaskTable.id as taskID from $itemTypeTaskTable // INNER JOIN $selfTable on $selfTable.items_id=$itemTypeTaskTable.id @@ -183,7 +183,7 @@ function getTabNameForItem(CommonGLPI $case, $withtemplate = 0) { ] ] ); - $query = "SELECT * FROM `glpi_plugin_processmaker_tasks` WHERE `plugin_processmaker_cases_id`={$case->fields['id']} AND `del_thread_status`='OPEN'"; + //$query = "SELECT * FROM `glpi_plugin_processmaker_tasks` WHERE `plugin_processmaker_cases_id`={$case->fields['id']} AND `del_thread_status`='OPEN'"; //foreach ($DB->request($query) as $task) { foreach ($res as $task) { $tasks[$task['del_index']] = $task; @@ -233,7 +233,7 @@ function getTabNameForItem(CommonGLPI $case, $withtemplate = 0) { ]); //$res = $PM_DB->query("SELECT APP_UID FROM SUB_APPLICATION WHERE APP_PARENT='{$case->fields['case_guid']}' AND DEL_INDEX_PARENT={$task->delIndex} AND SA_STATUS='ACTIVE'"); //if ($res && $PM_DB->numrows($res) == 1) { - if ($row = $res->next() && $res->numrows() == 1) { + if ($res->numrows() == 1 && $row = $res->next()) { //$row = $PM_DB->fetch_assoc($res); $loc_case = new PluginProcessmakerCase; $loc_case->getFromGUID($row['APP_UID']); diff --git a/inc/taskcategory.class.php b/inc/taskcategory.class.php index a16b692..6305ca0 100644 --- a/inc/taskcategory.class.php +++ b/inc/taskcategory.class.php @@ -18,11 +18,19 @@ class PluginProcessmakerTaskCategory extends CommonDBTM { function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { - return __('Task List', 'processmaker'); + if ($item->getType() == 'TaskCategory') { + $pmtaskcat = new PluginProcessmakerTaskCategory; + if ($pmtaskcat->getFromDBbyCategory($item->fields['id'])) { + return __('Process task', 'processmaker'); + } else { + return ''; // means no tab + } + } + return __('Task list', 'processmaker'); } - static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { + static function displayTabContentForProcess(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { global $DB, $CFG_GLPI; self::title($item); @@ -62,9 +70,9 @@ static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtem 'pm.plugin_processmaker_processes_id' => $item->getId() ] ]); - $query = "SELECT pm.pm_task_guid, pm.taskcategories_id, pm.`is_start`, gl.name, gl.completename, gl.`comment`, pm.is_active, pm.is_subprocess FROM glpi_plugin_processmaker_taskcategories AS pm - LEFT JOIN glpi_taskcategories AS gl ON pm.taskcategories_id=gl.id - WHERE pm.plugin_processmaker_processes_id=".$item->getID().";"; + //$query = "SELECT pm.pm_task_guid, pm.taskcategories_id, pm.`is_start`, gl.name, gl.completename, gl.`comment`, pm.is_active, pm.is_subprocess FROM glpi_plugin_processmaker_taskcategories AS pm + // LEFT JOIN glpi_taskcategories AS gl ON pm.taskcategories_id=gl.id + // WHERE pm.plugin_processmaker_processes_id=".$item->getID().";"; //foreach ($DB->request($query) as $taskCat) { foreach ($res as $taskCat) { @@ -111,19 +119,125 @@ static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtem return true; } + /** - * Print a good title for task categories tab - * add button for re-synchro of taskcategory list (only if rigths are w) - * @return nothing (display) - **/ + * Summary of displayTabContentForTaskCategory + * @param CommonGLPI $item + * @param mixed $tabnum + * @param mixed $withtemplate + * @return boolean + */ + static function displayTabContentForTaskCategory(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { + global $DB, $CFG_GLPI; + + $is_taskcat = false; + $processes_id = 0; + $pmtaskcat = new PluginProcessmakerTaskCategory; + $is_taskcat = $pmtaskcat->getFromDBbyCategory($item->fields['id']); + $processes_id = $pmtaskcat->fields['plugin_processmaker_processes_id']; + + echo "

"; + + echo ""; + echo ""; + echo ""; + + echo "" . + "" . + "" . + "" . + "" . + "" . + ""; + + $query = "SELECT pm.pm_task_guid, pm.taskcategories_id, pm.`is_start`, glp.name as 'pname', gl.name, gl.completename, gl.`comment`, pm.is_active, pm.is_subprocess FROM glpi_plugin_processmaker_taskcategories AS pm + LEFT JOIN glpi_taskcategories AS gl ON pm.taskcategories_id=gl.id + LEFT JOIN glpi_taskcategories AS glp ON glp.id=gl.taskcategories_id + WHERE pm.taskcategories_id=".$item->getID().";"; + + foreach ($DB->request($query) as $taskCat) { + echo ""; + + echo ""; + echo ""; + + echo ""; + + echo ""; + + echo ""; + + echo ""; + + echo ""; + + echo ""; + + echo ""; + } + echo "
".__('Process task', 'processmaker')."
".__('Process name', 'processmaker')."".__('Task name', 'processmaker')."".__('Complete name')."".__('Start', 'processmaker')."".__('Task GUID', 'processmaker')."".__('Comments')."".__('Active')."".__('Sub-process', 'processmaker')."
" . $taskCat['pname']; + if ($_SESSION["glpiis_ids_visible"]) { + echo " (" . $processes_id . ")"; + } + echo ""; + echo $taskCat['name']; + + if ($_SESSION["glpiis_ids_visible"]) { + echo " (" . $taskCat['taskcategories_id'] . ")"; + } + echo "" . $taskCat['completename'] . ""; + if ($taskCat['is_start']) { + echo "\""."; + } + echo "".$taskCat['pm_task_guid']."".$taskCat['comment'].""; + if ($taskCat['is_active']) { + echo "\""."; + } + echo ""; + if ($taskCat['is_subprocess']) { + echo "\""."; + } + echo "
"; + + return true; + } + + + /** + * Summary of displayTabContentForItem + * @param CommonGLPI $item + * @param mixed $tabnum + * @param mixed $withtemplate + * @return boolean + */ + static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { + $ret = false; + switch ($item->getType()) { + case 'PluginProcessmakerProcess': + $ret = self::displayTabContentForProcess($item, $tabnum, $withtemplate); + break; + case 'TaskCategory': + $ret = self::displayTabContentForTaskCategory($item, $tabnum, $withtemplate); + break; + } + return $ret; + } + + /** + * Print a good title for task categories tab + * add button for re-synchro of taskcategory list (only if rigths are w) + * @return nothing (display) + **/ static function title(CommonGLPI $item) { global $CFG_GLPI; - $buttons = []; - $title = __('Synchronize Task List', 'processmaker'); - if (Session::haveRight('plugin_processmaker_config', UPDATE)) { - $buttons["process.form.php?refreshtask=1&id=".$item->getID()] = $title; + $title = __('Synchronize Task List', 'processmaker'); + $buttons = ["process.form.php?refreshtask=1&id=".$item->getID() => $title]; $pic = $CFG_GLPI["root_doc"] . "/plugins/processmaker/pics/gears.png"; if ($item->fields['maintenance']) { $pic = $CFG_GLPI["root_doc"] . "/plugins/processmaker/pics/verysmall-under_maintenance.png"; diff --git a/inc/user.class.php b/inc/user.class.php index 9c22743..a8aae84 100644 --- a/inc/user.class.php +++ b/inc/user.class.php @@ -23,7 +23,7 @@ class PluginProcessmakerUser extends CommonDBTM { * @param $used array: Already used items ID: not to display in dropdown * @param $search pattern * - * @return mysql result set. + * @return DBmysqlIterator **/ static function getSqlSearchResult ($taskId, $count = true, $right = "all", $entity_restrict = -1, $value = 0, $used = [], $search = '', $limit = '') { @@ -104,12 +104,12 @@ static function getSqlSearchResult ($taskId, $count = true, $right = "all", $ent //$where .= " AND `glpi_users`.`id` NOT IN ("; if (is_numeric($value)) { - $first = false; + //$first = false; //$where .= $value; $used[] = $value; //$query2['WHERE']['AND']['NOT']['glpi_users.id'] = $value; } else { - $first = true; + //$first = true; } //$query2['WHERE']['AND']['NOT']['glpi_users.id'] = $used; //foreach ($used as $val) { @@ -258,7 +258,7 @@ static function getSqlSearchResult ($taskId, $count = true, $right = "all", $ent * - used : array / Already used items ID: not to display in dropdown (default empty) * - on_change : string / value to transmit to "onChange" * - * @param $options possible options + * @param $options array of possible options * * @return int (print out an HTML select box) **/ diff --git a/install/install.php b/install/install.php index b1e9143..0f1825d 100644 --- a/install/install.php +++ b/install/install.php @@ -9,4 +9,5 @@ function processmaker_install() { // add configuration singleton $query = "INSERT INTO `glpi_plugin_processmaker_configs` (`id`) VALUES (1);"; $DB->query( $query ) or die("error creating default record in glpi_plugin_processmaker_configs" . $DB->error()); + } diff --git a/js/central.js b/js/central.js index c907753..fe4b7eb 100644 --- a/js/central.js +++ b/js/central.js @@ -1,4 +1,4 @@ -$(function () { +$(function () { $(document).ajaxComplete(function (event, jqXHR, ajaxOptions) { //debugger; var pattern = /##processmaker.*(##|...)/g; diff --git a/js/planning.js b/js/planning.js index b82153a..a0c8be9 100644 --- a/js/planning.js +++ b/js/planning.js @@ -6,4 +6,4 @@ } $('input[type="checkbox"][value="PluginProcessmakerTask"]').parents('li').first().hide(); }); -}); +}); \ No newline at end of file diff --git a/processmaker.xml b/processmaker.xml index b58b56c..76b3fe6 100644 --- a/processmaker.xml +++ b/processmaker.xml @@ -27,17 +27,17 @@ 3.3.8 9.1 + + + 3.4.12 + 9.2 - 3.4.10 - 9.2 - - - 3.5.2 + 3.5.3 9.3 - 3.6.2 + 3.6.3 9.4 diff --git a/setup.php b/setup.php index 6d8be9c..87edfff 100644 --- a/setup.php +++ b/setup.php @@ -2,7 +2,7 @@ // used for case cancellation define("CANCEL", 256); -define('PROCESSMAKER_VERSION', '3.6.2'); +define('PROCESSMAKER_VERSION', '3.6.3'); // Init the hooks of the plugins -Needed function plugin_init_processmaker() { @@ -14,9 +14,11 @@ function plugin_init_processmaker() { Plugin::registerClass('PluginProcessmakerProcessmaker'); - Plugin::registerClass('PluginProcessmakerCase', ['addtabon' => $objects]); + Plugin::registerClass('PluginProcessmakerCase', ['addtabon' => $objects, 'notificationtemplates_types' => true]); - Plugin::registerClass('PluginProcessmakerTaskCategory'); + Plugin::registerClass('PluginProcessmakerTask', ['notificationtemplates_types' => true]); + + Plugin::registerClass('PluginProcessmakerTaskCategory', ['addtabon' => 'TaskCategory']); if (Session::haveRightsOr("config", [READ, UPDATE])) { Plugin::registerClass('PluginProcessmakerConfig', ['addtabon' => 'Config']);