Example #1
0
 /**
  * View a taskboard
  *
  * @param \Base $f3
  * @param array $params
  */
 public function index($f3, $params)
 {
     $sprint = new \Model\Sprint();
     // Load current sprint if no sprint ID is given
     if (!intval($params["id"])) {
         $localDate = date('Y-m-d', \Helper\View::instance()->utc2local());
         $sprint->load(array("? BETWEEN start_date AND end_date", $localDate));
         if (!$sprint->id) {
             $f3->error(404);
             return;
         }
     }
     // Default to showing group tasks
     if (empty($params["filter"])) {
         $params["filter"] = "groups";
     }
     // Load the requested sprint
     if (!$sprint->id) {
         $sprint->load($params["id"]);
         if (!$sprint->id) {
             $f3->error(404);
             return;
         }
     }
     $f3->set("sprint", $sprint);
     $f3->set("title", $sprint->name . " " . date('n/j', strtotime($sprint->start_date)) . "-" . date('n/j', strtotime($sprint->end_date)));
     $f3->set("menuitem", "backlog");
     // Get list of all users in the user's groups
     $filter_users = $this->_filterUsers($params);
     // Load issue statuses
     $status = new \Model\Issue\Status();
     $statuses = $status->find(array('taskboard > 0'), array('order' => 'taskboard_sort ASC'));
     $mapped_statuses = array();
     $visible_status_ids = array();
     $column_count = 0;
     foreach ($statuses as $s) {
         $visible_status_ids[] = $s->id;
         $mapped_statuses[$s->id] = $s;
         $column_count += $s->taskboard;
     }
     $visible_status_ids = implode(",", $visible_status_ids);
     $f3->set("statuses", $mapped_statuses);
     $f3->set("column_count", $column_count);
     // Load issue priorities
     $priority = new \Model\Issue\Priority();
     $f3->set("priorities", $priority->find(null, array("order" => "value DESC"), $f3->get("cache_expire.db")));
     // Load project list
     $issue = new \Model\Issue\Detail();
     // Find all visible tasks
     $tasks = $issue->find(array("sprint_id = ? AND type_id != ? AND deleted_date IS NULL AND status IN ({$visible_status_ids})" . (empty($filter_users) ? "" : " AND owner_id IN (" . implode(",", $filter_users) . ")"), $sprint->id, $f3->get("issue_type.project")), array("order" => "priority DESC"));
     $task_ids = array();
     $parent_ids = array(0);
     foreach ($tasks as $task) {
         $task_ids[] = $task->id;
         if ($task->parent_id) {
             $parent_ids[] = $task->parent_id;
         }
     }
     $task_ids_str = implode(",", $task_ids);
     $parent_ids_str = implode(",", $parent_ids);
     $f3->set("tasks", $task_ids_str);
     // Find all visible projects or parent tasks
     $projects = $issue->find(array("id IN ({$parent_ids_str}) OR (sprint_id = ? AND type_id = ? AND deleted_date IS NULL" . (empty($filter_users) ? ")" : " AND owner_id IN (" . implode(",", $filter_users) . "))"), $sprint->id, $f3->get("issue_type.project")), array("order" => "owner_id ASC, priority DESC"));
     // Sort projects if a filter is given
     if (!empty($params["filter"]) && is_numeric($params["filter"])) {
         $sortModel = new \Model\Issue\Backlog();
         $sortModel->load(array("user_id = ? AND sprint_id = ?", $params["filter"], $sprint->id));
         $sortArray = array();
         if ($sortModel->id) {
             $sortArray = json_decode($sortModel->issues);
             usort($projects, function (\Model\Issue $a, \Model\Issue $b) use($sortArray) {
                 $ka = array_search($a->id, $sortArray);
                 $kb = array_search($b->id, $sortArray);
                 if ($ka === false && $kb !== false) {
                     return -1;
                 }
                 if ($ka !== false && $kb === false) {
                     return 1;
                 }
                 if ($ka === $kb) {
                     return 0;
                 }
                 if ($ka > $kb) {
                     return 1;
                 }
                 if ($ka < $kb) {
                     return -1;
                 }
             });
         }
     }
     // Build multidimensional array of all tasks and projects
     $taskboard = array();
     foreach ($projects as $project) {
         // Build array of statuses to put tasks under
         $columns = array();
         foreach ($statuses as $status) {
             $columns[$status["id"]] = array();
         }
         // Add current project's tasks
         foreach ($tasks as $task) {
             if ($task->parent_id == $project->id || $project->id == 0 && (!$task->parent_id || !in_array($task->parent_id, $parent_ids))) {
                 $columns[$task->status][] = $task;
             }
         }
         // Add hierarchical structure to taskboard array
         $taskboard[] = array("project" => $project, "columns" => $columns);
     }
     $f3->set("taskboard", array_values($taskboard));
     $f3->set("filter", $params["filter"]);
     // Get user list for select
     $users = new \Model\User();
     $f3->set("users", $users->getAll());
     $f3->set("groups", $users->getAllGroups());
     $this->_render("taskboard/index.html");
 }
Example #2
0
 /**
  * View a taskboard
  */
 public function index($f3, $params)
 {
     // Require a valid numeric sprint ID
     if (!intval($params["id"])) {
         $f3->error(404);
         return;
     }
     // Default to showing group tasks
     if (empty($params["filter"])) {
         $params["filter"] = "groups";
     }
     // Load the requested sprint
     $sprint = new \Model\Sprint();
     $sprint->load($params["id"]);
     if (!$sprint->id) {
         $f3->error(404);
         return;
     }
     $f3->set("sprint", $sprint);
     $f3->set("title", $sprint->name . " " . date('n/j', strtotime($sprint->start_date)) . "-" . date('n/j', strtotime($sprint->end_date)));
     $f3->set("menuitem", "backlog");
     // Get list of all users in the user's groups
     $filter_users = $this->_filterUsers($params);
     // Load issue statuses
     $status = new \Model\Issue\Status();
     $statuses = $status->find(array('taskboard > 0'), null, $f3->get("cache_expire.db"));
     $mapped_statuses = array();
     $visible_status_ids = array();
     $column_count = 0;
     foreach ($statuses as $s) {
         $visible_status_ids[] = $s->id;
         $mapped_statuses[$s->id] = $s;
         $column_count += $s->taskboard;
     }
     $visible_status_ids = implode(",", $visible_status_ids);
     $f3->set("statuses", $mapped_statuses);
     $f3->set("column_count", $column_count);
     // Load issue priorities
     $priority = new \Model\Issue\Priority();
     $f3->set("priorities", $priority->find(null, array("order" => "value DESC"), $f3->get("cache_expire.db")));
     // Load project list
     $issue = new \Model\Issue\Detail();
     // Find all visible tasks
     $tasks = $issue->find(array("sprint_id = ? AND type_id != ? AND deleted_date IS NULL AND status IN ({$visible_status_ids})" . (empty($filter_users) ? "" : " AND owner_id IN (" . implode(",", $filter_users) . ")"), $sprint->id, $f3->get("issue_type.project")), array("order" => "priority DESC"));
     $task_ids = array();
     $parent_ids = array(0);
     foreach ($tasks as $task) {
         $task_ids[] = $task->id;
         if ($task->parent_id) {
             $parent_ids[] = $task->parent_id;
         }
     }
     $task_ids_str = implode(",", $task_ids);
     $parent_ids_str = implode(",", $parent_ids);
     $f3->set("tasks", $task_ids_str);
     // Find all visible projects or parent tasks
     $projects = $issue->find(array("id IN ({$parent_ids_str}) OR (sprint_id = ? AND type_id = ? AND deleted_date IS NULL" . (empty($filter_users) ? ")" : " AND owner_id IN (" . implode(",", $filter_users) . "))"), $sprint->id, $f3->get("issue_type.project")), array("order" => "owner_id ASC"));
     // Build multidimensional array of all tasks and projects
     $taskboard = array();
     foreach ($projects as $project) {
         // Build array of statuses to put tasks under
         $columns = array();
         foreach ($statuses as $status) {
             $columns[$status["id"]] = array();
         }
         // Add current project's tasks
         foreach ($tasks as $task) {
             if ($task->parent_id == $project->id || $project->id == 0 && (!$task->parent_id || !in_array($task->parent_id, $parent_ids))) {
                 $columns[$task->status][] = $task;
             }
         }
         // Add hierarchical structure to taskboard array
         $taskboard[] = array("project" => $project, "columns" => $columns);
     }
     $f3->set("taskboard", array_values($taskboard));
     $f3->set("filter", $params["filter"]);
     // Get user list for select
     $users = new \Model\User();
     $f3->set("users", $users->getAll());
     $f3->set("groups", $users->getAllGroups());
     $this->_render("taskboard/index.html");
 }
Example #3
0
 /**
  * GET /issues/@id
  * View an issue
  *
  * @param \Base $f3
  * @param array $params
  * @throws \Exception
  */
 public function single($f3, $params)
 {
     $issue = new \Model\Issue\Detail();
     $issue->load(array("id=?", $params["id"]));
     $user = $f3->get("user_obj");
     if (!$issue->id || $issue->deleted_date && !($user->role == 'admin' || $user->rank >= \Model\User::RANK_MANAGER || $issue->author_id == $user->id)) {
         $f3->error(404);
         return;
     }
     $type = new \Model\Issue\Type();
     $type->load($issue->type_id);
     $f3->set("title", $type->name . " #" . $issue->id . ": " . $issue->name);
     $f3->set("menuitem", "browse");
     $author = new \Model\User();
     $author->load($issue->author_id);
     $owner = new \Model\User();
     if ($issue->owner_id) {
         $owner->load($issue->owner_id);
     }
     $files = new \Model\Issue\File\Detail();
     $f3->set("files", $files->find(array("issue_id = ? AND deleted_date IS NULL", $issue->id)));
     if ($issue->sprint_id) {
         $sprint = new \Model\Sprint();
         $sprint->load($issue->sprint_id);
         $f3->set("sprint", $sprint);
     }
     $watching = new \Model\Issue\Watcher();
     $watching->load(array("issue_id = ? AND user_id = ?", $issue->id, $this->_userId));
     $f3->set("watching", !!$watching->id);
     $f3->set("issue", $issue);
     $f3->set("ancestors", $issue->getAncestors());
     $f3->set("type", $type);
     $f3->set("author", $author);
     $f3->set("owner", $owner);
     $comments = new \Model\Issue\Comment\Detail();
     $f3->set("comments", $comments->find(array("issue_id = ?", $issue->id), array("order" => "created_date DESC")));
     // Extra data needed for inline edit form
     $status = new \Model\Issue\Status();
     $f3->set("statuses", $status->find(null, null, $f3->get("cache_expire.db")));
     $priority = new \Model\Issue\Priority();
     $f3->set("priorities", $priority->find(null, array("order" => "value DESC"), $f3->get("cache_expire.db")));
     $sprint = new \Model\Sprint();
     $f3->set("sprints", $sprint->find(array("end_date >= ? OR id = ?", $this->now(false), $issue->sprint_id), array("order" => "start_date ASC")));
     $users = new \Model\User();
     $f3->set("users", $users->find("deleted_date IS NULL AND role != 'group'", array("order" => "name ASC")));
     $f3->set("groups", $users->find("deleted_date IS NULL AND role = 'group'", array("order" => "name ASC")));
     $this->_render("issues/single.html");
 }
Example #4
0
 public function single($f3, $params)
 {
     $this->_requireLogin();
     $user = new \Model\User();
     $user->load(array("username = ? AND deleted_date IS NULL", $params["username"]));
     if ($user->id) {
         $f3->set("title", $user->name);
         $f3->set("this_user", $user);
         // Extra arrays required for bulk update
         $status = new \Model\Issue\Status();
         $f3->set("statuses", $status->find(null, null, $f3->get("cache_expire.db")));
         $f3->set("users", $user->getAll());
         $f3->set("groups", $user->getAllGroups());
         $priority = new \Model\Issue\Priority();
         $f3->set("priorities", $priority->find(null, array("order" => "value DESC"), $f3->get("cache_expire.db")));
         $type = new \Model\Issue\Type();
         $f3->set("types", $type->find(null, null, $f3->get("cache_expire.db")));
         $issue = new \Model\Issue\Detail();
         $f3->set("created_issues", $issue->paginate(0, 200, array("status_closed = '0' AND deleted_date IS NULL AND author_id = ?", $user->id), array("order" => "priority DESC, due_date DESC")));
         $f3->set("assigned_issues", $issue->paginate(0, 200, array("status_closed = '0' AND deleted_date IS NULL AND owner_id = ?", $user->id), array("order" => "priority DESC, due_date DESC")));
         $f3->set("overdue_issues", $issue->paginate(0, 200, array("status_closed = '0' AND deleted_date IS NULL AND owner_id = ? AND due_date IS NOT NULL AND due_date < ?", $user->id, date("Y-m-d", \Helper\View::instance()->utc2local())), array("order" => "due_date ASC")));
         $this->_render("user/single.html");
     } else {
         $f3->error(404);
     }
 }
Example #5
0
 public function post($f3)
 {
     if ($_REQUEST) {
         // By default, use standard HTTP POST fields
         $post = $_REQUEST;
     } else {
         // For Redmine compatibility, also accept a JSON object
         try {
             $post = json_decode(file_get_contents('php://input'), true);
         } catch (Exception $e) {
             throw new Exception("Unable to parse input");
         }
         if (!empty($post["issue"])) {
             $post = $post["issue"];
         }
         // Convert Redmine names to Phproject names
         if (!empty($post["subject"])) {
             $post["name"] = $post["subject"];
         }
         if (!empty($post["parent_issue_id"])) {
             $post["parent_id"] = $post["parent_issue_id"];
         }
         if (!empty($post["tracker_id"])) {
             $post["type_id"] = $post["tracker_id"];
         }
         if (!empty($post["assigned_to_id"])) {
             $post["owner_id"] = $post["assigned_to_id"];
         }
         if (!empty($post["fixed_version_id"])) {
             $post["sprint_id"] = $post["fixed_version_id"];
         }
     }
     // Ensure a status ID is added
     if (!empty($post["status_id"])) {
         $post["status"] = $post["status_id"];
     }
     if (empty($post["status"])) {
         $post["status"] = 1;
     }
     // Verify the required "name" field is passed
     if (empty($post["name"])) {
         $f3->error("The 'name' value is required.");
         return;
     }
     // Verify given values are valid (types, statueses, priorities)
     if (!empty($post["type_id"])) {
         $type = new \Model\Issue\Type();
         $type->load($post["type_id"]);
         if (!$type->id) {
             $f3->error("The 'type_id' field is not valid.");
             return;
         }
     }
     if (!empty($post["parent_id"])) {
         $parent = new \Model\Issue();
         $parent->load($post["parent_id"]);
         if (!$parent->id) {
             $f3->error("The 'type_id' field is not valid.");
             return;
         }
     }
     if (!empty($post["status"])) {
         $status = new \Model\Issue\Status();
         $status->load($post["status"]);
         if (!$status->id) {
             $f3->error("The 'status' field is not valid.");
             return;
         }
     }
     if (!empty($post["priority_id"])) {
         $priority = new \Model\Issue\Priority();
         $priority->load(array("value" => $post["priority_id"]));
         if (!$priority->id) {
             $f3->error("The 'priority_id' field is not valid.");
             return;
         }
     }
     // Create a new issue based on the data
     $issue = new \Model\Issue();
     $issue->author_id = !empty($post["author_id"]) ? $post["author_id"] : $this->_userId;
     $issue->name = trim($post["name"]);
     $issue->type_id = empty($post["type_id"]) ? 1 : $post["type_id"];
     $issue->priority_id = empty($post["priority_id"]) ? $f3->get("issue_priority.default") : $post["priority_id"];
     // Set due date if valid
     if (!empty($post["due_date"]) && preg_match("/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}( [0-9:]{8})?\$/", $post["due_date"])) {
         $issue->due_date = $post["due_date"];
     } elseif (!empty($post["due_date"]) && ($due_date = strtotime($post["due_date"]))) {
         $issue->due_date = date("Y-m-d", $due_date);
     }
     if (!empty($post["description"])) {
         $issue->description = $post["description"];
     }
     if (!empty($post["parent_id"])) {
         $issue->parent_id = $post["parent_id"];
     }
     if (!empty($post["owner_id"])) {
         $issue->owner_id = $post["owner_id"];
     }
     $issue->save();
     $this->_printJson(array("issue" => $issue->cast()));
 }
Example #6
0
 /**
  * Convert a priority ID to a name
  * @param int $value
  * @return string
  */
 public function convertPriority($value)
 {
     if (isset($this->cache['priority.' . $value])) {
         $priority = $this->cache['priority.' . $value];
     } else {
         $priority = new \Model\Issue\Priority();
         $priority->load(array("value = ?", $value));
         $this->cache['priority.' . $value] = $priority;
     }
     return $priority->name;
 }
Example #7
0
 /**
  * @param \Base $f3
  * @param array $params
  * @throws \Exception
  */
 public function single($f3, $params)
 {
     $issue = new \Model\Issue\Detail();
     $issue->load(array("id=?", $f3->get("PARAMS.id")));
     $user = $f3->get("user_obj");
     if (!$issue->id || $issue->deleted_date && !($user->role == 'admin' || $user->rank >= \Model\User::RANK_MANAGER || $issue->author_id == $user->id)) {
         $f3->error(404);
         return;
     }
     $type = new \Model\Issue\Type();
     $type->load($issue->type_id);
     // Run actions if passed
     $post = $f3->get("POST");
     if (!empty($post)) {
         switch ($post["action"]) {
             case "add_watcher":
                 $watching = new \Model\Issue\Watcher();
                 // Loads just in case the user is already a watcher
                 $watching->load(array("issue_id = ? AND user_id = ?", $issue->id, $post["user_id"]));
                 if (!$watching->id) {
                     $watching->issue_id = $issue->id;
                     $watching->user_id = $post["user_id"];
                     $watching->save();
                 }
                 if ($f3->get("AJAX")) {
                     return;
                 }
                 break;
             case "remove_watcher":
                 $watching = new \Model\Issue\Watcher();
                 $watching->load(array("issue_id = ? AND user_id = ?", $issue->id, $post["user_id"]));
                 $watching->delete();
                 if ($f3->get("AJAX")) {
                     return;
                 }
                 break;
             case "add_dependency":
                 $dependencies = new \Model\Issue\Dependency();
                 // Loads just in case the task  is already a dependency
                 $dependencies->load(array("issue_id = ? AND dependency_id = ?", $issue->id, $post["id"]));
                 $dependencies->issue_id = $issue->id;
                 $dependencies->dependency_id = $post["id"];
                 $dependencies->dependency_type = $post["type_id"];
                 $dependencies->save();
                 if ($f3->get("AJAX")) {
                     return;
                 }
                 break;
             case "add_dependent":
                 $dependencies = new \Model\Issue\Dependency();
                 // Loads just in case the task  is already a dependency
                 $dependencies->load(array("issue_id = ? AND dependency_id = ?", $post["id"], $issue->id));
                 $dependencies->dependency_id = $issue->id;
                 $dependencies->issue_id = $post["id"];
                 $dependencies->dependency_type = $post["type_id"];
                 $dependencies->save();
                 if ($f3->get("AJAX")) {
                     return;
                 }
                 break;
             case "remove_dependency":
                 $dependencies = new \Model\Issue\Dependency();
                 $dependencies->load($post["id"]);
                 $dependencies->delete();
                 if ($f3->get("AJAX")) {
                     return;
                 }
                 break;
         }
     }
     $f3->set("title", $type->name . " #" . $issue->id . ": " . $issue->name);
     $f3->set("menuitem", "browse");
     $author = new \Model\User();
     $author->load($issue->author_id);
     $owner = new \Model\User();
     if ($issue->owner_id) {
         $owner->load($issue->owner_id);
     }
     $files = new \Model\Issue\File\Detail();
     $f3->set("files", $files->find(array("issue_id = ? AND deleted_date IS NULL", $issue->id)));
     if ($issue->sprint_id) {
         $sprint = new \Model\Sprint();
         $sprint->load($issue->sprint_id);
         $f3->set("sprint", $sprint);
     }
     $watching = new \Model\Issue\Watcher();
     $watching->load(array("issue_id = ? AND user_id = ?", $issue->id, $this->_userId));
     $f3->set("watching", !!$watching->id);
     $f3->set("issue", $issue);
     $f3->set("ancestors", $issue->getAncestors());
     $f3->set("type", $type);
     $f3->set("author", $author);
     $f3->set("owner", $owner);
     $comments = new \Model\Issue\Comment\Detail();
     $f3->set("comments", $comments->find(array("issue_id = ?", $issue->id), array("order" => "created_date DESC")));
     // Extra data needed for inline edit form
     $status = new \Model\Issue\Status();
     $f3->set("statuses", $status->find(null, null, $f3->get("cache_expire.db")));
     $priority = new \Model\Issue\Priority();
     $f3->set("priorities", $priority->find(null, array("order" => "value DESC"), $f3->get("cache_expire.db")));
     $sprint = new \Model\Sprint();
     $f3->set("sprints", $sprint->find(array("end_date >= ? OR id = ?", $this->now(false), $issue->sprint_id), array("order" => "start_date ASC")));
     $users = new \Model\User();
     $f3->set("users", $users->find("deleted_date IS NULL AND role != 'group'", array("order" => "name ASC")));
     $f3->set("groups", $users->find("deleted_date IS NULL AND role = 'group'", array("order" => "name ASC")));
     $this->_render("issues/single.html");
 }