fields['issues'] = array( "guid", "numb", "mesg", "closer", "closed", "due", "tags", ); parent::__construct($guid); $this->expectType("issue"); } /* * Initialize a new issue object with the given message, parent, * and owner. The issue's name is taken from the message's name. * The given message object is updated to parent the new issue. */ public static function initNew(mesg $mesg, user $owner, stage $parent) : issue { $pad = $parent->getParent(); $numb = $pad->issueNumb++; $pad->saveObj(); $issue = new issue(); $issue->setOwner($owner); $issue->setParent($parent); $issue->name = $mesg->name; $issue->objtype = "issue"; $issue->numb = $numb; $issue->mesg = $mesg->guid; $issue->saveObj(); $mesg->setParent($issue); return $issue; } /* * Get all assignees. Assignees are returned as an array of * stdClass instances. Objects contain data from the 'assignees' * database table with no defined operations. Pointers to users * will be followed and an instanciated user object will be * in their place. Limit of zero returns all assignees. */ public function getAssignees(int $limit = 0) : array { $assign = array(); $query = "SELECT * FROM assignees WHERE guid = '" . database::esc($this->guid) . "'"; if ($limit != 0) $query .= " LIMIT " . database::esc($limit); $res = database::query($query); foreach ($res as $a) { $obj = new stdClass(); foreach ($a as $k => $v) $obj->{$k} = $v; $obj->assignee = new user($obj->assignee); $obj->assigner = new user($obj->assigner); if (isset($obj->dismisser) && $obj->dismisser != "") $obj->dismisser = new user($obj->dismisser); $assign[] = $obj; } return $assign; } /* * Add an assignee to this issue. Returns false if user is * already assigned, or if another error occurs; true * otherwise. */ public function addAssignee(user $assignee, user $assigner) : bool { if ($assignee->isAssignedTo($this) || !isset($assignee->guid) || !isset($assigner->guid)) return false; $query = "INSERT INTO assignees (guid, assignee, assigner, assigned)" . " VALUES ('" . database::esc($this->guid) . "', '" . database::esc($assignee->guid) . "', '" . database::esc($assigner->guid) . "', '" . database::esc(self::getCurrentTimestamp()) . "')"; database::query($query); return true; } /* * Dismiss an assignee, effectively unassigning them. Returns * false if user is not already an active assignee, or if another * error occurs; true otherwise. */ public function dismissAssignee(user $assignee, user $dismisser) : bool { if (!$assignee->isAssignedTo($this) || !isset($assignee->guid) || !isset($dismisser->guid)) return false; $query = "UPDATE assignees SET dismisser = '" . database::esc($dismisser->guid) . "', dismissed = '" . database::esc(self::getCurrentTimestamp()) . "' WHERE guid = '" . database::esc($this->guid) . "' AND assignee = '" . database::esc($assignee->guid) . "'"; database::query($query); return true; } /* * Signoff an assignee's portion of this issue. Returns false * if user is not already an active assignee, or if another * error occurs; true otherwise. */ public function signoffAssignee(user $assignee) : bool { if (!$assignee->isAssignedTo($this) || !isset($assignee->guid)) return false; $query = "UPDATE assignees SET signedoff = '" . database::esc(self::getCurrentTimestamp()) . "' WHERE guid = '" . database::esc($this->guid) . "' AND assignee = '" . database::esc($assignee->guid) . "'"; database::query($query); return true; } /* * Get the OP message for this issue. */ public function getOPMesg() : mesg { return new mesg($this->mesg); } /* * Get all messages on this issue. The OP message is filtered * from results. Messages are sorted by date created. */ public function getMesgs_ordByDatetime() : array { $mesgs = parent::getMesgs_ordByDatetime(); $i = -1; foreach ($mesgs as $k => $m) { if ($m->guid == $this->mesg) { $i = $k; break; } } if ($i != -1) { unset($mesgs[$i]); $mesgs = array_values($mesgs); } return $mesgs; } /* * Get the user that closed this issue. If the issue is still * open, NULL is returned. */ public function getCloser() : ?user { if (!isset($this->closer) || $this->closer == "") return NULL; return new user($this->closer); } /* * Get the pad this issue exists under */ public function getPad() : pad { $parent = $this->getParent(); if ($parent->objtype == "pad") return $parent; return $parent->getParent(); } /* * Advance this issue in the pipeline, closing it if already in the * last stage. A closer is needed incase a close takes place. */ public function advance(user $closer) : void { $stage = $this->getParent(); if ($stage->objtype != "stage") return; if (!($next = $stage->getNext())) $this->close($closer); else $this->setParent($next); } /* * Mark this issue as completed and closed. */ public function close(user $closer) : void { $pad = $this->getParent()->getParent(); if ($pad) { $this->closer = $closer->guid; $this->closed = self::getCurrentTimestamp(); $this->setParent($pad); } } /* * Check whether issue is currently open or closed. */ public function isOpen() : bool { return self::typeOf($this->parent) != "pad"; } } ?>