Closed hartois closed 5 years ago
I found everything that I needed for the implementation of this feature:
Please close this issue.
My patch in haste:
Index: ajax/dropdownMassiveActionReplaceActor.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- ajax/dropdownMassiveActionReplaceActor.php (date 1478764812000)
+++ ajax/dropdownMassiveActionReplaceActor.php (date 1478764812000)
@@ -0,0 +1,16 @@
+<?php
+
+$AJAX_INCLUDE = 1;
+include ('../inc/includes.php');
+
+header("Content-Type: text/html; charset=UTF-8");
+Html::header_nocache();
+
+Session::checkRight('ticket', UPDATE);
+
+if ($_POST["actortype"] > 0) {
+ $ticket = new Ticket();
+ $rand = mt_rand();
+ $ticket->showActorReplaceForm($_POST["actortype"], $rand, $_POST["tickets"], false);
+ echo " <input type='submit' name='replace_actor' class='submit' value=\""._sx('button','Replace')."\">";
+}
Index: ajax/dropdownTicketCurrentActors.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- ajax/dropdownTicketCurrentActors.php (date 1479123873000)
+++ ajax/dropdownTicketCurrentActors.php (date 1479123873000)
@@ -0,0 +1,97 @@
+<?php
+
+include ('../inc/includes.php');
+
+header("Content-Type: text/html; charset=UTF-8");
+Html::header_nocache();
+
+Session::checkCentralAccess();
+global $CFG_GLPI;
+// Make a select box
+if (isset($_POST["type"])
+ && isset($_POST["actortype"])
+ && isset($_POST["itemtype"])) {
+ $rand = mt_rand();
+ if ($item = getItemForItemtype($_POST["itemtype"])) {
+ switch ($_POST["type"]) {
+ case "user" :
+ $right = 'all';
+ // Only steal or own ticket whit empty assign
+ if ($_POST["to_actor"]["_type"] == 'assign') {
+ $right = "own_ticket";
+ if (!$item->canAssign()) {
+ $right = 'id';
+ }
+ }
+
+ $options_from = array('name' => 'from_actor',
+ 'right' => $right,
+ 'rand' => $rand,
+ 'width' => '150',
+ 'ldap_import' => true);
+ $options_to = array('name' => 'to_actor',
+ 'right' => $right,
+ 'rand' => $rand,
+ 'width' => '150',
+ 'ldap_import' => true);
+
+ $actors = [];
+ foreach($_POST['tickets'] as $ticket_id) {
+ $ticket = new Ticket();
+ $ticket->getFromDB($ticket_id);
+
+ foreach($ticket->getTicketActorsByType('user') as $actor_id => $actor)
+ foreach($actor as $actor_type) {
+ if ($actor_type == $_POST['actortype']) {
+ $actorObj = new User();
+ $actorObj->getFromDB($actor_id);
+ $actors[$actor_id] = $actorObj->getRawName();
+ }
+ }
+ }
+ $rand_from = Dropdown::showFromArray('from_actor',$actors,$options);
+ $rand_to = User::dropdown($options_to);
+
+ break;
+
+ case "group" :
+ $right = 'all';
+ // Only steal or own ticket whit empty assign
+ if ($_POST["to_actor"]["_type"] == 'assign') {
+ $right = "own_ticket";
+ if (!$item->canAssign()) {
+ $right = 'id';
+ }
+ }
+
+ $options_from = array('name' => 'from_actor',
+ 'right' => $right,
+ 'rand' => $rand,
+ 'width' => '150',
+ 'ldap_import' => true);
+ $options_to = array('name' => 'to_actor',
+ 'right' => $right,
+ 'rand' => $rand,
+ 'width' => '150',
+ 'ldap_import' => true);
+
+ $actors = [];
+ foreach($_POST['tickets'] as $ticket_id) {
+ $ticket = new Ticket();
+ $ticket->getFromDB($ticket_id);
+
+ foreach($ticket->getTicketActorsByType('group') as $actor_id => $actor)
+ foreach($actor as $actor_type) {
+ if ($actor_type == $_POST['actortype']) {
+ $actorObj = new Group();
+ $actorObj->getFromDB($actor_id);
+ $actors[$actor_id] = $actorObj->getRawName();
+ }
+ }
+ }
+ $rand = Dropdown::showFromArray('from_actor',$actors,$options);
+ $rand = Group::dropdown($options_to);
+ break;
+ }
+ }
+}
Index: inc/ticket.class.php
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- inc/ticket.class.php (date 1478764793000)
+++ inc/ticket.class.php (date 1479123873000)
@@ -2211,6 +2211,8 @@
}
if (Session::haveRight(self::$rightname, UPDATE)) {
+ $actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'replace_actor']
+ = __('Replace actor');
$actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'add_actor']
= __('Add an actor');
$actions[__CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR.'enable_notif']
@@ -2227,10 +2229,134 @@
return $actions;
}
+ static function showFormMassiveActionReplaceActor($tickets) {
+ global $CFG_GLPI;
+ $types = array(CommonITILActor::ASSIGN => __('Assigned to'),
+ CommonITILActor::REQUESTER => __('Requester'),
+ CommonITILActor::OBSERVER => __('Watcher')
+ );
+ $rand = Dropdown::showFromArray('actortype', $types, array('display_emptychoice' => true));
-
+
+ $paramsmassaction = array('"actortype"' => '__VALUE__',
+ 'tickets' => $tickets,
+ 'right' => array(UPDATE));
+ Ajax::updateItemOnSelectEvent("dropdown_actortype".$rand, "show_massiveaction_field",
+ $CFG_GLPI["root_doc"].
+ "/ajax/dropdownMassiveActionReplaceActor.php",
+ $paramsmassaction);
+ echo Html::scriptBlock(Html::jsSetDropdownValue("dropdown_actortype".$rand,CommonITILActor::ASSIGN));
+ echo "<br><span id='show_massiveaction_field'> </span>\n";
+ }
+
+ static function showMassiveActionsSubForm(MassiveAction $ma) {
+
+ switch ($ma->getAction()) {
+ case 'replace_actor' :
+ $items = $ma->getInput()['initial_items'];
+ $tickets = [];
+ if(!empty($items['Ticket']))
+ $tickets = array_keys($items['Ticket']);
+ static::showFormMassiveActionReplaceActor($tickets);
+ return true;
+ }
+
+ return parent::showMassiveActionsSubForm($ma);
+ }
+
+ function showActorReplaceForm($type, $rand_type, $tickets, $inobject=true) {
+ global $CFG_GLPI;
+
+ $types = array('user' => __('User'), 'group' => __('Group'));
+
+ echo "<div ".($inobject?"style='display:none'":'')." id='actor$rand_type' class='actor-dropdown'>";
+ $rand = Dropdown::showFromArray("actorobjecttype", $types,
+ array('display_emptychoice' => true, 'width'=>'200px'));
+ echo "<br />";
+ $params = array('type' => '__VALUE__',
+ 'actortype' => $type,
+ 'itemtype' => $this->getType(),
+ 'tickets' => $tickets
+ );
+
+ Ajax::updateItemOnSelectEvent("dropdown_actorobjecttype$rand",
+ "from_actor$rand",
+ $CFG_GLPI["root_doc"]."/ajax/dropdownTicketCurrentActors.php",
+ $params);
+ echo "<span id='from_actor$rand' class='actor-dropdown'> </span>";
+ if ($inobject) {
+ echo "<hr>";
+ }
+ echo "</div>";
+ }
+
+ static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item,
+ array $ids) {
+
+ switch ($ma->getAction()) {
+ case 'replace_actor' :
+ $input = $ma->getInput();
+ $actorObj = $input['actorobjecttype'];
+ switch($actorObj){
+ case 'user':
+ $actorLinkObj = new Ticket_User();
+ break;
+ case 'group':
+ $actorLinkObj = new Group_Ticket();
+ break;
+ }
+ $actorIdField = $actorObj.'s_id';
+ foreach ($ids as $id) {
+ $actorLinkObj->getFromDB($id);
+ $addData = ['id' => $id];
+
+ switch($input['actortype']) {
+ case CommonITILActor::REQUESTER:
+ $addData['_itil_requester'] = [$actorIdField => $input['to_actor'], '_type' => $actorObj];
+ break;
+ case CommonITILActor::ASSIGN:
+ $addData['_itil_assign'] = [$actorIdField => $input['to_actor'], '_type' => $actorObj];
+ break;
+ case CommonITILActor::OBSERVER:
+ $addData['_itil_observer'] = [$actorIdField => $input['to_actor'], '_type' => $actorObj];
+ break;
+ default:
+ $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
+ $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION));
+ continue;
+ break;
+ }
+ if(!$item->can($id, UPDATE)){
+ $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_NORIGHT);
+ $ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
+ continue;
+ }
+ if(!$item->update($addData)) {
+ $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
+ $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION));
+ continue;
+ }
+
+ $find_from = $actorLinkObj->find("`tickets_id` = $id AND `type` = '".$input['actortype']
+ ."' AND `".$actorIdField."` = ".$input['from_actor']);
+
+ if(!empty($find_from)){
+ $recId = array_keys($find_from)[0];
+ if(!$actorLinkObj->delete(['id' => $recId])){
+ $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
+ $ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION));
+ continue;
+ }
+ }
+ $ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK);
+ }
+ return;
+ }
+ parent::processMassiveActionsForOneItemtype($ma, $item, $ids);
+ }
+
function getSearchOptions() {
$tab = array();
@@ -6597,6 +6723,31 @@
return $ticket_users_keys;
}
+ function getTicketActorsByType($objtype = 'user') {
+ global $DB;
+
+ switch($objtype) {
+ case 'user':
+ $sql = "SELECT tu.`users_id` AS actor_id, tu.`type` AS type
+ FROM `glpi_tickets_users` tu
+ WHERE tu.`tickets_id` = ".$this->getId()." GROUP BY tu.`users_id`, tu.`type`";
+ break;
+
+ case 'group':
+ $sql = "SELECT gt.`groups_id` AS actor_id, gt.`type` AS type
+ FROM `glpi_groups_tickets` gt
+ WHERE gt.`tickets_id` = ".$this->getId()." GROUP BY gt.`groups_id`, gt.`type`";
+ break;
+ }
+ $res = $DB->query($sql);
+ $actors = [];
+ while($actor = $DB->fetch_assoc($res)) {
+ if(!isset($actors[$actor['actor_id']]))
+ $actors[$actor['actor_id']] = [];
+ $actors[$actor['actor_id']][] = $actor['type'];
+ }
+ return $actors;
+ }
/**
* @since version 0.90
implementation in #3229 is completly broken (some warnings, replace non selected users by another)
Ux pov, the feature is poor understandable for a new comer (two GLPI dev didn't understand without explanation). Maybe a little radical, but adding an option to delete user could be better understandable.
Please close this issue.
I need to implement in massive action for ticket feature for replace actor. My users really want this. Now replacing actor need two steps: add new actor, remove old actor. My task: add feature for merge this steps to one action - replace selected actor with another. But I cannot understand architecture of massive actions. Can you help me? Where I can find info about this?