--- eventum-r3721/include/class.display_column.php~ 2008-09-09 22:45:13.000000000 +0300 +++ eventum-r3721/include/class.display_column.php 2008-09-09 22:46:04.000000000 +0300 @@ -229,7 +229,10 @@ ), "iss_expected_resolution_date" => array( "title" => ev_gettext("Expected Resolution Date") - ) + ), + "isu_order" => array( + "title" => ev_gettext("Issue Order") + ), ) ); return $columns[$page]; --- eventum-1.7.0/include/class.issue.php 2005-12-29 21:27:25.000000000 +0200 +++ eventum/include/class.issue.php 2006-03-27 15:33:02.000000000 +0300 @@ -1245,6 +1245,7 @@ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return -1; } else { + Issue::moveOrderForAllUsers($issue_id, 1000); $prj_id = Issue::getProjectID($issue_id); // add note with the reason to close the issue @@ -1349,7 +1350,6 @@ $assignment_notifications[] = $assignee; $assignments_changed = true; } - $assignments_changed = true; } if (count($assignment_notifications) > 0) { Notification::notifyNewAssignment($assignment_notifications, $issue_id); @@ -1596,16 +1596,33 @@ { $issue_id = Misc::escapeInteger($issue_id); $assignee_usr_id = Misc::escapeInteger($assignee_usr_id); + $order = 1; + // move all orders down to free "order space" for this new association + $stmt = "UPDATE + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user + SET + isu_order = isu_order + 1 + WHERE + isu_usr_id = $assignee_usr_id AND + isu_order >= $order"; + $res = $GLOBALS["db_api"]->dbh->query($stmt); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; + } + // insert the new association $stmt = "INSERT INTO " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user ( isu_iss_id, isu_usr_id, - isu_assigned_date + isu_assigned_date, + isu_order ) VALUES ( $issue_id, $assignee_usr_id, - '" . Date_API::getCurrentDateGMT() . "' + '" . Date_API::getCurrentDateGMT() . "', + $order )"; $res = $GLOBALS["db_api"]->dbh->query($stmt); if (PEAR::isError($res)) { @@ -1620,6 +1637,78 @@ } } + /** + * Method used to get the order list to be rearranged + * + * @access private + * @param string $issue_id The issue ID or a comma seperated list of IDs already prepared for giving to mysql + * @param string $usr_id The user to remove. When not specified, all users are taken as to be removed for that issue + * @return mixed delete order list to be rearranged. Used as a parameter to the method of rearranging the order. + */ + function getDeleteUserAssociationOrderList($issue_id, $usr_id = "") + { + // find all affected associantion orders + $stmt = "SELECT isu_usr_id, isu_order FROM + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user + WHERE + isu_iss_id IN ($issue_id)"; + if ($usr_id !== FALSE) { + $stmt.= " AND isu_usr_id IN ($usr_id)"; + } + $stmt.= "ORDER BY isu_order"; + $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; + } else { + $deleted_orders = array(); + foreach ($res as $row) { + if (empty($deleted_orders[$row['isu_usr_id']])) { + $deleted_orders[$row['isu_usr_id']] = array(); + } + $deleted_orders[$row['isu_usr_id']] [] = $row['isu_order']; + } + return $deleted_orders; + } + } + + /** + * + * Method used to rearrange order list in the db according to known deleted records + * + * @access private + * @param mixed deleteorder list + * @return void + */ + function rearrangeDeleteUserAssociationOrderList($delete_order_list) + { + if (empty($delete_order_list) || (!is_array($delete_order_list))) { + return -1; + } + foreach ($delete_order_list as $isu_usr_id => $orders) { + for ($i = 0; $i < count($orders); $i++) { // traverse all deleted orders + // move the orders after them up to take the "order space" of the deleted records + $stmt = "UPDATE + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user + SET + isu_order = isu_order - " . ($i+1) . " + WHERE + isu_usr_id = $isu_usr_id AND + isu_order > " . $orders[$i]; + if ($i < count($orders) - 1) { + $stmt.= " AND + isu_order < " . $orders[$i+1]; + } + $res = $GLOBALS["db_api"]->dbh->query($stmt); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; + } + } + } + return 1; + } + /** * Method used to delete all user assignments for a specific issue. @@ -1635,6 +1724,7 @@ if (is_array($issue_id)) { $issue_id = implode(", ", $issue_id); } + $deleted_order_list = Issue::getDeleteUserAssociationOrderList($issue_id); $stmt = "DELETE FROM " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user WHERE @@ -1647,6 +1737,7 @@ if ($usr_id) { History::add($issue_id, $usr_id, History::getTypeID('user_all_unassociated'), 'Issue assignments removed by ' . User::getFullName($usr_id)); } + Issue::rearrangeDeleteUserAsssociationOrderList($deleted_order_list); return 1; } } @@ -1665,6 +1756,7 @@ { $issue_id = Misc::escapeInteger($issue_id); $usr_id = Misc::escapeInteger($usr_id); + $delete_order_list = Issue::getDeleteUserAssociationOrderList($issue_id, $usr_id); $stmt = "DELETE FROM " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user WHERE @@ -1679,6 +1771,7 @@ History::add($issue_id, Auth::getUserID(), History::getTypeID('user_unassociated'), User::getFullName($usr_id) . ' removed from issue by ' . User::getFullName(Auth::getUserID())); } + Issue::rearrangeDeleteUserAssociationOrderList($delete_order_list); return 1; } } @@ -2047,14 +2140,6 @@ } } } - if (count($users) > 0) { - // automatically change the status to 'Assigned' - Issue::setStatus($new_issue_id, Status::getStatusID('Assigned'), FALSE); - - // set this special variable to false, to avoid triggering - // another status update on the workflow class - $has_assignee = false; - } // now process any files being uploaded $found = 0; @@ -2161,6 +2246,11 @@ { $sort_by = Issue::getParam('sort_by'); $sort_order = Issue::getParam('sort_order'); + $users = Issue::getParam('users'); + if (empty($users) && ($sort_by == 'isu_order')) { // Sorting by isu_order is impossible when no user specified + unset($sort_by); + unset($sort_order); + } $rows = Issue::getParam('rows'); $hide_closed = Issue::getParam('hide_closed'); if ($hide_closed === '') { @@ -2582,6 +2582,7 @@ "last_action_date" => "desc", "usr_full_name" => "asc", "iss_expected_resolution_date" => "desc", + "isu_order" => "desc", ); foreach ($custom_fields as $fld_id => $fld_name) { @@ -2975,6 +3066,8 @@ $ids = implode(", ", $ids); $stmt = "SELECT isu_iss_id, + isu_order, + isu_usr_id, usr_full_name FROM " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user, @@ -2986,6 +3079,7 @@ if (PEAR::isError($res)) { Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); } else { + // gather names of the users assigned to each issue $t = array(); for ($i = 0; $i < count($res); $i++) { if (!empty($t[$res[$i]['isu_iss_id']])) { @@ -2994,9 +3088,18 @@ $t[$res[$i]['isu_iss_id']] = $res[$i]['usr_full_name']; } } + // gather orders + $o = array(); + for ($i = 0; $i < count($res); $i++) { + if (empty($o[$res[$i]['isu_iss_id']])) { + $o[$res[$i]['isu_iss_id']] = array(); + } + $o[$res[$i]['isu_iss_id']][$res[$i]['isu_usr_id']] = $res[$i]['isu_order']; + } // now populate the $result variable again for ($i = 0; $i < count($result); $i++) { @$result[$i]['assigned_users'] = $t[$result[$i]['iss_id']]; + @$result[$i]['assigned_users_order'] = $o[$result[$i]['iss_id']]; } } } @@ -3963,6 +4066,7 @@ Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); return -1; } + Issue::moveOrderForAllUsers($issue_id, 1); } @@ -4021,8 +4125,91 @@ } return $returns[$msg_id]; } + + /** + * Reorders user's issues as requested by user + * @access public + * @param $usr_id User to be reordered + * @param $issue_id Issue or array of issues to be moved + * @param $neworder The new order of the issues + * @return void + */ + function reorderUserIssues($usr_id, $issue_id, $neworder) + { + if (!isset($usr_id) || !isset($issue_id) || !isset($neworder)) { + return false; + } + if (!is_numeric($usr_id) || !is_numeric($neworder)) { + return false; + } + $usr_id = Misc::escapeInteger($usr_id); + $issue_id = Misc::escapeInteger($issue_id); + $neworder = Misc::escapeInteger($neworder); + if (is_array($issue_id)) { + $issue_count = count($issue_id); + $issue_id_str = implode(", ", $issue_id); + } else { + $issue_count = 1; + $issue_id_str = $issue_id; + $issue_id = array($issue_id); + } + // do a nasty pretending to be deleting stuff so that reordering happens as if these elements were deleted + $orderlist = Issue::getDeleteUserAssociationOrderList($issue_id_str, $usr_id); + Issue::rearrangeDeleteUserAssociationOrderList($orderlist); + // move down the orders to free the "order space" needed + $stmt = "UPDATE + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user + SET + isu_order = isu_order + $issue_count + WHERE + isu_usr_id = $usr_id AND + isu_order >= $neworder"; + $res = $GLOBALS["db_api"]->dbh->query($stmt); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; + } + //update the order for the issues being moved + $i = 0; + foreach ($issue_id as $iss_id) { + $stmt = "UPDATE + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user + SET + isu_order = " . ($neworder + $i) . " + WHERE + isu_usr_id = $usr_id AND + isu_iss_id = $iss_id"; + $res = $GLOBALS["db_api"]->dbh->query($stmt); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; + } + $i++; + } + } + + function moveOrderForAllUsers($issue_id, $neworder) + { + // Move the issue to the top priority for the ppl it's assigned to + $stmt = "SELECT isu_usr_id FROM + " . APP_DEFAULT_DB . "." . APP_TABLE_PREFIX . "issue_user + WHERE + isu_iss_id = " . Misc::escapeInteger($issue_id); + $res = $GLOBALS["db_api"]->dbh->getAll($stmt, DB_FETCHMODE_ASSOC); + if (PEAR::isError($res)) { + Error_Handler::logError(array($res->getMessage(), $res->getDebugInfo()), __FILE__, __LINE__); + return -1; + } + foreach ($res as $row) { + Issue::reorderUserIssues($row["isu_usr_id"], $issue_id, $neworder); + } + } + } + + + // benchmarking the included file (aka setup time) if (APP_BENCHMARK) { $GLOBALS['bench']->setMarker('Included Issue Class'); diff -ru eventum-1.7.0/list.php eventum/list.php --- eventum-1.7.0/list.php 2005-12-29 21:27:24.000000000 +0200 +++ eventum/list.php 2006-03-30 14:57:06.000000000 +0300 @@ -67,6 +67,11 @@ $profile['sort_by'] . "&sort_order=" . $profile['sort_order']); } +@$reorder_usr_id = $_REQUEST["reorder_user"]; +@$reorder_issue_id = $_REQUEST["reorder_source"]; +@$reorder_neworder = $_REQUEST["reorder_neworder"]; +Issue::reorderUserIssues($reorder_usr_id, $reorder_issue_id, $reorder_neworder); + $options = Issue::saveSearchParams(); $tpl->assign("options", $options); $tpl->assign("sorting", Issue::getSortingInfo($options)); @@ -104,6 +109,21 @@ } } +// get the isu_order (assignated users) ordering user +if (!empty($options["users"])) { + if ($options["users"] == -2) { + $isu_order_user = $usr_id; + } else + if ($options["users"] > 0) { + $isu_order_user = $options["users"]; + } else { + unset($isu_order_user); + } +} else { + unset($isu_order_user); +} +$tpl->assign("isu_order_user", $isu_order_user); + $list = Issue::getListing($prj_id, $options, $pagerRow, $rows); $tpl->assign("list", $list["list"]); $tpl->assign("list_info", $list["info"]); --- eventum-1.7.0/templates/list.tpl.html 2005-12-29 21:27:24.000000000 +0200 +++ eventum/templates/list.tpl.html 2006-03-23 16:28:30.000000000 +0200 @@ -89,6 +89,28 @@ f.target = '_popup'; f.submit(); } +function reorderBulk(order_user, neworder) +{ + url = page_url + "?"; + url += "reorder_user=" + order_user; + + items = document.getElementsByName("item[]"); + checkedcount = 0; + for (var i = 0; i < items.length; i++) { + if (items[i].checked) { + url += "&reorder_source[" + checkedcount + "]=" + items[i].value; + checkedcount++; + } + } + if (checkedcount == 0) { + alert('{/literal}{t escape=js}Please choose which issues to move to the new place.{/t}{literal}'); + return false; + } + + url += "&reorder_neworder=" + neworder; + + window.location.href = url; +} function hideClosed(f) { if (f.hide_closed.checked) { @@ -202,8 +224,8 @@ {$fld_title|escape:"html"} - {/foreach} - {else} + {/foreach} + {elseif $field_name != 'isu_order' || $isu_order_user} {if $field_name == 'iss_summary'} @@ -218,8 +240,11 @@
{elseif $sorting.links[$field_name] != ''} - {$column.title} - {if $sorting.images[$field_name] != ""}{/if} + {$column.title} + {if $field_name == 'isu_order'} +
{$users[$isu_order_user]} + {/if} + {if $sorting.images[$field_name] != ""}{/if} {else} {$column.title} {/if} @@ -239,7 +264,7 @@ {$fld_value|formatCustomValue:$fld_id:$list[i].iss_id} {/foreach} - {else} + {elseif $field_name != 'isu_order' || $isu_order_user} {if $field_name == 'iss_id'} {$list[i].iss_id} @@ -278,7 +303,24 @@ {/if} {if $list[i].iss_private == 1} [Private] - {/if} + {/if} + {elseif $field_name == 'isu_order'} + {if $isu_order_user} + {assign var="order" value=$list[i].assigned_users_order[$isu_order_user]} + {if $order} + {$order} +