示例#1
0
 /**
  * @param \Base $f3
  * @throws \Exception
  */
 public function edit($f3)
 {
     $post = $f3->get("POST");
     $issue = new \Model\Issue();
     $issue->load($post["itemId"]);
     $issue->sprint_id = empty($post["reciever"]["receiverId"]) ? null : $post["reciever"]["receiverId"];
     $issue->save();
     $this->_printJson($issue);
 }
示例#2
0
 public function recent_comments()
 {
     $f3 = \Base::instance();
     $issue = new \Model\Issue();
     $ownerString = implode(",", $this->getOwnerIds());
     $issues = $issue->find(array("owner_id IN ({$ownerString}) OR author_id = ?", $f3->get("user.id")));
     $ids = array();
     foreach ($issues as $item) {
         $ids[] = $item->id;
     }
     $comment = new \Model\Issue\Comment\Detail();
     $issueIds = implode(",", $ids);
     return $comment->find(array("issue_id IN ({$issueIds}) AND user_id != ?", $f3->get("user.id")), array("order" => "created_date DESC", "limit" => 15));
 }
示例#3
0
 /**
  * Reassign assigned issues
  * @param  int $user_id
  * @return int Number of issues affected
  */
 public function reassignIssues($user_id)
 {
     if (!$this->id) {
         throw new \Exception("User is not initialized.");
     }
     $issue_model = new \Model\Issue();
     $issues = $issue_model->find(array("owner_id = ? AND deleted_date IS NULL AND closed_date IS NULL", $this->id));
     foreach ($issues as $issue) {
         $issue->owner_id = $user_id;
         $issue->save();
     }
     return count($issues);
 }
示例#4
0
 /**
  * Send an email to watchers with the file info
  * @param  int $issue_id
  * @param  int $file_id
  */
 public function issue_file($issue_id, $file_id)
 {
     $f3 = \Base::instance();
     if ($f3->get("mail.from")) {
         $log = new \Log("mail.log");
         // Get issue and comment data
         $issue = new \Model\Issue();
         $issue->load($issue_id);
         $file = new \Model\Issue\File\Detail();
         $file->load($file_id);
         // This should catch a bug I can't currently find the source of. --Alan
         if ($file->issue_id != $issue->id) {
             return;
         }
         // Get issue parent if set
         if ($issue->parent_id) {
             $parent = new \Model\Issue();
             $parent->load($issue->parent_id);
             $f3->set("parent", $parent);
         }
         // Get recipient list and remove current user
         $recipients = $this->_issue_watchers($issue_id);
         $recipients = array_diff($recipients, array($file->user_email));
         // Render message body
         $f3->set("issue", $issue);
         $f3->set("file", $file);
         $text = $this->_render("notification/file.txt");
         $body = $this->_render("notification/file.html");
         $subject = "[#{$issue->id}] - {$file->user_name} attached a file to {$issue->name}";
         // Send to recipients
         foreach ($recipients as $recipient) {
             $this->utf8mail($recipient, $subject, $body, $text);
             $log->write("Sent file notification to: " . $recipient);
         }
     }
 }
示例#5
0
 /**
  * Update an existing task
  */
 public function edit($f3, $params)
 {
     $post = $f3->get("POST");
     $issue = new \Model\Issue();
     $issue->load($post["taskId"]);
     if (!empty($post["receiver"])) {
         if ($post["receiver"]["story"]) {
             $issue->parent_id = $post["receiver"]["story"];
         }
         $issue->status = $post["receiver"]["status"];
         $status = new \Model\Issue\Status();
         $status->load($issue->status);
         if ($status->closed) {
             if (!$issue->closed_date) {
                 $issue->closed_date = $this->now();
             }
         } else {
             $issue->closed_date = null;
         }
     } else {
         $issue->name = $post["title"];
         $issue->description = $post["description"];
         $issue->owner_id = $post["assigned"];
         $issue->hours_remaining = $post["hours"];
         $issue->hours_spent += $post["hours_spent"];
         if (!empty($post["hours_spent"]) && !empty($post["burndown"])) {
             $issue->hours_remaining -= $post["hours_spent"];
         }
         if ($issue->hours_remaining < 0) {
             $issue->hours_remaining = 0;
         }
         if (!empty($post["dueDate"])) {
             $issue->due_date = date("Y-m-d", strtotime($post["dueDate"]));
         } else {
             $issue->due_date = null;
         }
         if (!empty($post["repeat_cycle"])) {
             $issue->repeat_cycle = $post["repeat_cycle"];
         }
         $issue->priority = $post["priority"];
         if (!empty($post["storyId"])) {
             $issue->parent_id = $post["storyId"];
         }
         $issue->title = $post["title"];
     }
     if (!empty($post["comment"])) {
         $comment = new \Model\Issue\Comment();
         $comment->user_id = $this->_userId;
         $comment->issue_id = $issue->id;
         if (!empty($post["hours_spent"])) {
             $comment->text = trim($post["comment"]) . sprintf(" (%s %s spent)", $post["hours_spent"], $post["hours_spent"] == 1 ? "hour" : "hours");
         } else {
             $comment->text = $post["comment"];
         }
         $comment->created_date = $this->now();
         $comment->save();
         $issue->update_comment = $comment->id;
     }
     $issue->save();
     $this->_printJson($issue->cast() + array("taskId" => $issue->id));
 }
示例#6
0
 }
 $to_user = new \Model\User();
 foreach ($header->to as $to_email) {
     $to = $to_email->mailbox . "@" . $to_email->host;
     $to_user->load(array('email = ? AND deleted_date IS NULL', $to));
     if (!empty($to_user->id)) {
         $owner = $to_user->id;
         break;
     } else {
         $owner = $from_user->id;
     }
 }
 // Find issue IDs in subject
 preg_match("/\\[#([0-9]+)\\] -/", $header->subject, $matches);
 // Get issue instance
 $issue = new \Model\Issue();
 if (!empty($matches[1])) {
     $issue->load(intval($matches[1]));
 }
 if (!$issue->id) {
     $subject = trim(preg_replace("/^((Re|Fwd?):\\s)*/i", "", $header->subject));
     $issue->load(array('name=? AND deleted_date IS NULL AND closed_date IS NULL', $subject));
 }
 if ($issue->id) {
     if (trim($text)) {
         $comment = \Model\Issue\Comment::create(array('user_id' => $from_user->id, 'issue_id' => $issue->id, 'text' => $text));
         $log->write(sprintf("Added comment %s on issue #%s - %s", $comment->id, $issue->id, $issue->name));
     }
 } else {
     $issue = \Model\Issue::create(array('name' => $header->subject, 'description' => $text, 'author_id' => $from_user->id, 'owner_id' => $owner, 'status' => 1, 'type_id' => 1));
     $log->write(sprintf("Created issue #%s - %s", $issue->id, $issue->name));
示例#7
0
<?php

/**
 * Tests the Issue model's core functionality
 * @package  Test
 * @author   Alan Hardman <*****@*****.**>
 */
require_once "base.php";
$test = new Test();
$issue = new Model\Issue();
$test->expect($issue->load(1) && $issue->id == 1, "Issue->load() by Integer");
$test->expect($issue->load(array('id = ?', 1)) && $issue->id == 1, "Issue->load() by String");
$test->expect(is_array($issue->getChildren()), "Issue->getChildren()");
$test->expect(is_array($issue->getAncestors()), "Issue->getAncestors()");
$test->expect($issue->save(false) && $issue->id, "Issue->save() without notifications");
// Output results
showResults($test);
示例#8
0
 if (!empty($user->id)) {
     $author = $user->id;
     // find an owner from the recipients
     foreach ($header->to as $owner_email) {
         $user->reset();
         $to = $owner_email->mailbox . "@" . $owner_email->host;
         $user->load(array('email=?', $to));
         if (!empty($user->id)) {
             $owner = $user->id;
             break;
         } else {
             $owner = $author;
         }
     }
     preg_match("/\\[#([0-9]+)\\] -/", $header->subject, $matches);
     $issue = new \Model\Issue();
     !empty($matches[1]) ? $issue->load($matches[1]) : '';
     // post a comment if replying to an issue
     if (!empty($issue->id)) {
         if (!empty($message)) {
             $comment = new \Model\Issue\Comment();
             $comment->user_id = $author;
             $comment->issue_id = $issue->id;
             $comment->text = html_entity_decode(strip_tags($message));
             $comment->created_date = date("Y-m-d H:i:s");
             $comment->save();
             $notification = \Helper\Notification::instance();
             $notification->issue_comment($issue->id, $comment->id);
         }
     } else {
         if (!empty($header->subject)) {
示例#9
0
 /**
  * GET /issues/parent_ajax
  * Load all matching issues
  *
  * @param  \Base $f3
  */
 public function parent_ajax($f3)
 {
     if (!$f3->get("AJAX")) {
         $f3->error(400);
     }
     $term = trim($f3->get('GET.q'));
     $results = array();
     $issue = new \Model\Issue();
     if (substr($term, 0, 1) == '#' && is_numeric(substr($term, 1))) {
         $id = (int) substr($term, 1);
         $issues = $issue->find(array('id LIKE ?', $id . '%'), array('limit' => 20));
         foreach ($issues as $row) {
             $results[] = array('id' => $row->get('id'), 'text' => $row->get('name'));
         }
     } elseif (is_numeric($term)) {
         $id = (int) $term;
         $issues = $issue->find(array('(id LIKE ?) OR (name LIKE ?)', $id . '%', '%' . $id . '%'), array('limit' => 20));
         foreach ($issues as $row) {
             $results[] = array('id' => $row->get('id'), 'text' => $row->get('name'));
         }
     } else {
         $issues = $issue->find(array('name LIKE ?', '%' . addslashes($term) . '%'), array('limit' => 20));
         foreach ($issues as $row) {
             $results[] = array('id' => $row->get('id'), 'text' => $row->get('name'));
         }
     }
     $this->_printJson(array('results' => $results));
 }
示例#10
0
 $start = strtotime($sprint->start_date);
 $end = strtotime($sprint->end_date);
 $tasks_for_this_sprint = array();
 // Find tasks that fit into this sprint
 foreach ($tasks as $task) {
     echo "Using task {$task->id}\n";
     $due = strtotime($task->due_date);
     if ($due >= $start && $due <= $end) {
         echo "Task marked for move {$task->id}\n";
         $tasks_for_this_sprint[] = $task;
     }
 }
 // Create sprint project
 if (count($tasks_for_this_sprint)) {
     echo "Creating project for sprint {$sprint->id}\n";
     $sprint_project = new \Model\Issue();
     $sprint_project->type_id = $issue_type_project;
     $sprint_project->parent_id = $project->id;
     $sprint_project->sprint_id = $sprint->id;
     $sprint_project->author_id = $project->author_id;
     $sprint_project->owner_id = $project->owner_id;
     if ($sprint->name) {
         $sprint_project->name = $project->name . " - " . $sprint->name . " - " . date("n/j", strtotime($sprint->start_date)) . "-" . date("n/j", strtotime($sprint->start_date));
     } else {
         $sprint_project->name = $project->name . " - " . date("n/j", strtotime($sprint->start_date)) . "-" . date("n/j", strtotime($sprint->start_date));
     }
     $sprint_project->description = "This is an automatically generated project for breaking large projects into sprints.";
     $sprint_project->created_date = date("Y-m-d H:i:s");
     $sprint_project->save();
     // Move tasks into sprint project
     foreach ($tasks_for_this_sprint as $task) {
示例#11
0
 public function single_comments_post($f3, $params)
 {
     $issue = new \Model\Issue();
     $issue->load($params["id"]);
     if (!$issue->id) {
         $f3->error(404);
         return;
     }
     $data = array("issue_id" => $issue->id, "user_id" => $this->_userId, "text" => $f3->get("POST.text"));
     $comment = \Model\Issue\Comment::create($data);
     $this->_printJson($comment->cast());
 }
示例#12
0
 /**
  * Convert an issue ID to a name
  * @param int $id
  * @return string
  */
 public function convertIssueId($id)
 {
     if (isset($this->cache['issue.' . $id])) {
         $issue = $this->cache['issue.' . $id];
     } else {
         $issue = new \Model\Issue();
         $issue->load($id);
         $this->cache['issue.' . $id] = $issue;
     }
     return $issue->name;
 }
示例#13
0
 /**
  * Log issue update, send notifications
  * @param  boolean $notify
  * @return Issue
  */
 public function save($notify = true)
 {
     $f3 = \Base::instance();
     // Catch empty sprint at the lowest level here
     if ($this->get("sprint_id") === 0) {
         $this->set("sprint_id", null);
     }
     // Censor credit card numbers if enabled
     if ($f3->get("security.block_ccs")) {
         if (preg_match("/([0-9]{3,4}-){3}[0-9]{3,4}/", $this->get("description"))) {
             $this->set("description", preg_replace("/([0-9]{3,4}-){3}([0-9]{3,4})/", "************\$2", $this->get("description")));
         }
     }
     // Make dates correct
     if ($this->due_date) {
         $this->due_date = date("Y-m-d", strtotime($this->due_date));
     } else {
         $this->due_date = null;
     }
     if ($this->start_date) {
         $this->start_date = date("Y-m-d", strtotime($this->start_date));
     } else {
         $this->start_date = null;
     }
     // Check if updating or inserting
     if ($this->query) {
         // Save issue updates and send notifications
         $update = $this->_saveUpdate($notify);
         $issue = parent::save();
         if ($notify && $update && $update->id && $update->notify) {
             $notification = \Helper\Notification::instance();
             $notification->issue_update($this->get("id"), $update->id);
         }
     } else {
         // Move task to a sprint if the parent is in a sprint
         if ($this->get("parent_id") && !$this->get("sprint_id")) {
             $parent = new \Model\Issue();
             $parent->load($this->get("parent_id"));
             if ($parent->sprint_id) {
                 $this->set("sprint_id", $parent->sprint_id);
             }
         }
         // Save issue and send notifications
         $issue = parent::save();
         if ($notify) {
             $notification = \Helper\Notification::instance();
             $notification->issue_create($issue->id);
         }
         return $issue;
     }
     $this->saveTags();
     return empty($issue) ? parent::save() : $issue;
 }
示例#14
0
文件: issue.php 项目: Rayne/phproject
 /**
  * Repeat an issue by generating a minimal copy and setting new due date
  * @param  boolean $notify
  * @return Issue
  */
 public function repeat($notify = true)
 {
     $repeat_issue = new \Model\Issue();
     $repeat_issue->name = $this->name;
     $repeat_issue->type_id = $this->type_id;
     $repeat_issue->parent_id = $this->parent_id;
     $repeat_issue->author_id = $this->author_id;
     $repeat_issue->owner_id = $this->owner_id;
     $repeat_issue->description = $this->description;
     $repeat_issue->priority = $this->priority;
     $repeat_issue->repeat_cycle = $this->repeat_cycle;
     $repeat_issue->hours_total = $this->hours_total;
     $repeat_issue->hours_remaining = $this->hours_total;
     $repeat_issue->created_date = date("Y-m-d H:i:s");
     // Find a due date in the future
     switch ($repeat_issue->repeat_cycle) {
         case 'daily':
             $repeat_issue->start_date = $this->start_date ? date("Y-m-d", strtotime("tomorrow")) : NULL;
             $repeat_issue->due_date = date("Y-m-d", strtotime("tomorrow"));
             break;
         case 'weekly':
             $repeat_issue->start_date = $this->start_date ? date("Y-m-d", strtotime($this->start_date . " +1 week")) : NULL;
             $repeat_issue->due_date = date("Y-m-d", strtotime($this->due_date . " +1 week"));
             break;
         case 'monthly':
             $repeat_issue->start_date = $this->start_date ? date("Y-m-d", strtotime($this->start_date . " +1 month")) : NULL;
             $repeat_issue->due_date = date("Y-m-d", strtotime($this->due_date . " +1 month"));
             break;
         case 'sprint':
             $sprint = new \Model\Sprint();
             $sprint->load(array("start_date > NOW()"), array('order' => 'start_date'));
             $repeat_issue->start_date = $this->start_date ? $sprint->start_date : NULL;
             $repeat_issue->due_date = $sprint->end_date;
             break;
         default:
             $repeat_issue->repeat_cycle = 'none';
     }
     // If the issue was in a sprint before, put it in a sprint again.
     if ($this->sprint_id) {
         $sprint = new \Model\Sprint();
         $sprint->load(array("end_date >= ? AND start_date <= ?", $repeat_issue->due_date, $repeat_issue->due_date), array('order' => 'start_date'));
         $repeat_issue->sprint_id = $sprint->id;
     }
     $repeat_issue->save();
     if ($notify) {
         $notification = \Helper\Notification::instance();
         $notification->issue_create($repeat_issue->id);
     }
     return $repeat_issue;
 }
示例#15
0
 /**
  * Log and save an issue update
  * @param  boolean $notify
  * @return Issue\Update
  */
 protected function _saveUpdate($notify = true)
 {
     $f3 = \Base::instance();
     // Ensure issue is not tied to itself as a parent
     if ($this->get("id") == $this->get("parent_id")) {
         $this->set("parent_id", $this->_getPrev("parent_id"));
     }
     // Log update
     $update = new \Model\Issue\Update();
     $update->issue_id = $this->id;
     $update->user_id = $f3->get("user.id");
     $update->created_date = date("Y-m-d H:i:s");
     if ($f3->exists('update_comment')) {
         $update->comment_id = $f3->get('update_comment')->id;
         if ($notify) {
             $update->notify = 1;
         }
     } else {
         $update->notify = 0;
     }
     $update->save();
     // Set hours_total to the hours_remaining value if it's 0 or null
     if ($this->get("hours_remaining") && !$this->get("hours_total")) {
         $this->set("hours_total", $this->get("hours_remaining"));
     }
     // Set hours remaining to 0 if the issue has been closed
     if ($this->get("closed_date") && $this->get("hours_remaining")) {
         $this->set("hours_remaining", 0);
     }
     // Create a new issue if repeating
     if ($this->get("closed_date") && $this->get("repeat_cycle") && $this->get("repeat_cycle") != "none") {
         $repeat_issue = new \Model\Issue();
         $repeat_issue->name = $this->get("name");
         $repeat_issue->type_id = $this->get("type_id");
         $repeat_issue->parent_id = $this->get("parent_id");
         $repeat_issue->author_id = $this->get("author_id");
         $repeat_issue->owner_id = $this->get("owner_id");
         $repeat_issue->description = $this->get("description");
         $repeat_issue->priority = $this->get("priority");
         $repeat_issue->repeat_cycle = $this->get("repeat_cycle");
         $repeat_issue->hours_total = $this->get("hours_total");
         $repeat_issue->hours_remaining = $this->get("hours_total");
         // Reset hours remaining to start hours
         $repeat_issue->created_date = date("Y-m-d H:i:s");
         // Find a due date in the future
         switch ($repeat_issue->repeat_cycle) {
             case 'daily':
                 $repeat_issue->start_date = $this->get("start_date") ? date("Y-m-d", strtotime("tomorrow")) : NULL;
                 $repeat_issue->due_date = date("Y-m-d", strtotime("tomorrow"));
                 break;
             case 'weekly':
                 $repeat_issue->start_date = $this->get("start_date") ? date("Y-m-d", strtotime($this->get("start_date") . " +1 week")) : NULL;
                 $repeat_issue->due_date = date("Y-m-d", strtotime($this->get("due_date") . " +1 week"));
                 break;
             case 'monthly':
                 $repeat_issue->start_date = $this->get("start_date") ? date("Y-m-d", strtotime($this->get("start_date") . " +1 month")) : NULL;
                 $repeat_issue->due_date = date("Y-m-d", strtotime($this->get("due_date") . " +1 month"));
                 break;
             case 'sprint':
                 $sprint = new \Model\Sprint();
                 $sprint->load(array("start_date > NOW()"), array('order' => 'start_date'));
                 $repeat_issue->start_date = $this->get("start_date") ? $sprint->start_date : NULL;
                 $repeat_issue->due_date = $sprint->end_date;
                 break;
             default:
                 $repeat_issue->repeat_cycle = 'none';
         }
         // If the issue was in a sprint before, put it in a sprint again.
         if ($this->get("sprint_id")) {
             $sprint = new \Model\Sprint();
             $sprint->load(array("end_date >= ? AND start_date <= ?", $repeat_issue->due_date, $repeat_issue->due_date), array('order' => 'start_date'));
             $repeat_issue->sprint_id = $sprint->id;
         }
         $repeat_issue->save();
         $notification = \Helper\Notification::instance();
         $notification->issue_create($repeat_issue->id);
         $this->set("repeat_cycle", null);
     }
     // Log updated fields
     $updated = 0;
     $important_changes = 0;
     $important_fields = array('status', 'name', 'description', 'owner_id', 'priority', 'due_date');
     foreach ($this->fields as $key => $field) {
         if ($field["changed"] && $field["value"] != $this->_getPrev($key)) {
             $update_field = new \Model\Issue\Update\Field();
             $update_field->issue_update_id = $update->id;
             $update_field->field = $key;
             $update_field->old_value = $this->_getPrev($key);
             $update_field->new_value = $field["value"];
             $update_field->save();
             $updated++;
             if ($key == 'sprint_id') {
                 $this->resetTaskSprints();
             }
             if (in_array($key, $important_fields)) {
                 $important_changes++;
             }
         }
     }
     // Delete update if no fields were changed
     if (!$updated) {
         $update->delete();
     }
     // Set notify flag if important changes occurred
     if ($notify && $important_changes) {
         $update->notify = 1;
         $update->save();
     }
     // Send back the update
     return $update->id ? $update : false;
 }
示例#16
0
文件: view.php 项目: Rayne/phproject
 /**
  * Replaces IDs with links to their corresponding issues
  * @param  string $str
  * @return string
  */
 protected function _parseIds($str)
 {
     $url = \Base::instance()->get("site.url");
     // Find all IDs
     $count = preg_match_all("/(?<=[^a-z\\/&]#|^#)[0-9]+(?=[^a-z\\/]|\$)/i", $str, $matches);
     if (!$count) {
         return $str;
     }
     // Load IDs
     $ids = array();
     foreach ($matches[0] as $match) {
         $ids[] = $match;
     }
     $idsStr = implode(",", array_unique($ids));
     $issue = new \Model\Issue();
     $issues = $issue->find(array("id IN ({$idsStr})"));
     return preg_replace_callback("/(?<=[^a-z\\/&]|^)#[0-9]+(?=[^a-z\\/]|\$)/i", function ($matches) use($url, $issues) {
         $id = ltrim($matches[0], "#");
         foreach ($issues as $i) {
             if ($i->id == $id) {
                 $issue = $i;
             }
         }
         if ($issue) {
             if ($issue->deleted_date) {
                 $f3 = \Base::instance();
                 if ($f3->get("user.role") == "admin" || $f3->get("user.rank") >= \Model\User::RANK_MANAGER || $f3->get("user.id") == $issue->author_id) {
                     return "<a href=\"{$url}issues/{$id}\" style=\"text-decoration: line-through;\">#{$id} &ndash; " . htmlspecialchars($issue->name) . "</a>";
                 } else {
                     return "#{$id}";
                 }
             }
             return "<a href=\"{$url}issues/{$id}\">#{$id} &ndash; " . htmlspecialchars($issue->name) . "</a>";
         }
         return "<a href=\"{$url}issues/{$id}\">#{$id}</a>";
     }, $str);
 }