1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
4 //require_once 'MTrack/Captcha.php';
7 require_once 'MTrackWeb.php';
8 class MTrackWeb_Ticket extends MTrackWeb
15 var $tid = 0; // or the MD5 rep.
22 //require_once 'MTrack/ACL.php';
23 // MTrackACL::requireAllRights('Browser', 'read');
31 if (!isset($_REQUEST['ajax_body'])) {
34 $this->masterTemplate = 'ticket.html';
35 $this->id = $pi ? $pi: (isset($_GET['id']) ? $_GET['id'] : 0);
36 $this->id = (int) $this->id;
38 $this->initEditForm();
42 function loadIssue( );
46 $this->issue = DB_DataObject::factory('mtrack_ticket');
47 $this->issue->autoJoin();
48 if (!$this->id || !$this->issue->get($this->id)) {
49 $this->jerr("no such ticket");
52 if ($this->issue->project_id != $this->currentProject()) {
53 $this->jerr("not in current project");
60 //$this->issue->augmentFormFields($this->fieldset());
63 $this->preview = false;
64 $this->error = array();
67 if (!$this->id && !$this->hasPerm('MTrack.Issue','A')) {
68 return HTML_FlexyFramework::run('Noperm');
71 !$this->hasPerm('MTrack.Issue','S')
73 $this->jerr('no permission');
76 $this->editable = !$this->hasPerm('MTrack.Issue','E') ;
78 $this->issue->milestoneURL = $this->baseURL.'/Milestone'; // fix me later..
80 $this->showEditBar = false;
82 if ($this->editable && $this->id && !$this->preview) {
83 $this->showEditBar = true;
91 function post() // handle the post...
96 if (isset($_POST['cancel'])) {
97 header("Location: {$$this->baseURL}/Ticket/$this->issue->nsident");
101 if (!MTrack_Captcha::check('ticket')) {
102 $this->error[] = "CAPTCHA failed, please try again";
104 $this->preview = isset($_POST['preview']) ? true : false;
109 MTrackACL::requireAllRights("Tickets", 'create');
111 MTrackACL::requireAllRights("ticket:" . $this->issue->tid, 'modify');
113 } catch (Exception $e) {
114 $this->error[] = $e->getMessage();
118 $comment = empty($_POST['comment']) ? '' : $_POST['comment'];
121 if (!strlen($comment)) {
122 $comment = $_POST['summary'];
125 $CS = MTrackChangeset::begin("ticket:X", $comment);
126 } catch (Exception $e) {
127 $this->error[] = $e->getMessage();
131 // compute next id number.
132 // We don't use auto-number, because we allow for importing multiple
133 // projects with their own ticket sequence.
134 // During "normal" user-driven operation, we do want plain old id numbers
135 // so we compute it here, under a transaction
136 $db = MTrackDB::get();
140 switch($db->getAttribute(PDO::ATTR_DRIVER_NAME)) {
142 // Some versions of postgres don't like that we have "abc123" for
143 // identifiers, so match on the bigest number nsident fields only
144 $max = "select max(cast(nsident as integer)) + 1 from tickets where nsident ~ '^\\\\d+$'";
148 $max = "select max(cast(nsident as UNSIGNED)) + 1 from tickets";
152 $max = 'select max(cast(nsident as integer)) + 1 from tickets';
158 list($this->issue->nsident) = MTrackDB::q($max)->fetchAll(PDO::FETCH_COLUMN, 0);
159 if ($this->issue->nsident === null) {
160 $this->issue->nsident = 1;
164 if (isset($_POST['action']) && !$this->preview) {
165 $act= explode('_', $_POST['action'] , 2);
166 //var_dump($act);exit;
171 $this->issue->reOpen();
174 $this->issue->resolution = 'fixed';
175 $this->issue->close();
176 $_POST['estimated'] = $this->issue->estimated;
181 // will be applied to the issue further down
182 $_POST['owner'] = MTrackAuth::whoami();
183 if ($this->issue->status == 'new') {
184 $this->issue->status = 'open';
190 //$this->issue->resolution = $_POST['resolution'];
191 $this->issue->resolution = $act[1];
192 $this->issue->close();
193 $_POST['estimated'] = $this->issue->estimated;
197 $this->issue->status = $act[1];
213 $this->issue->applyPOSTData($_POST);
217 foreach ($fields as $fieldname) {
218 if (isset($_POST[$fieldname]) && strlen($_POST[$fieldname])) {
219 $this->issue->$fieldname = $_POST[$fieldname];
221 $this->issue->$fieldname = null;
225 $kw = $this->issue->getKeywords();
226 $kill = array_values($kw);
227 foreach (preg_split('/[ \t,]+/', $_POST['keywords']) as $w) {
231 $x = array_search($w, $kw);
233 $k = MTrackKeyword::loadByWord($w);
235 $k = new MTrackKeyword;
239 $this->issue->assocKeyword($k);
241 $w = array_search($w, $kill);
247 foreach ($kill as $w) {
248 $this->issue->dissocKeyword($w);
251 $ms = $this->issue->getMilestones();
253 if (isset($_POST['milestone']) && is_array($_POST['milestone'])) {
254 foreach ($_POST['milestone'] as $mid) {
255 $this->issue->assocMilestone($mid);
259 foreach ($kill as $mid) {
260 $this->issue->dissocMilestone($mid);
263 $ms = $this->issue->getComponents();
265 if (isset($_POST['component']) && is_array($_POST['component'])) {
266 foreach ($_POST['component'] as $mid) {
267 $this->issue->assocComponent($mid);
271 foreach ($kill as $mid) {
272 $this->issue->dissocComponent($mid);
275 if (!empty($_POST['comment'])) {
276 $this->issue->addComment($_POST['comment']);
279 $this->issue->addEffort(
280 empty($_POST['spent']) ? 0 : $_POST['spent'],
281 empty($_POST['estimate']) ? 0 : $_POST['estimate']
284 if (!count($this->error)) {
286 $this->issue->save($CS);
288 // make sure everyone is watching it!!!!
289 if($this->issue->owner && $this->issue->tid) {
290 // make sure owner is tracking it...
291 MTrackWatch::watch_object('ticket', $this->issue->tid, $this->issue->owner);
294 if ($this->id == 'new') {
295 MTrackWatch::watch_object('ticket', $this->issue->tid, MTrackAuth::whoami());
299 $CS->setObject("ticket:" . $this->issue->tid);
300 } catch (Exception $e) {
301 $this->error[] = $e->getMessage();
305 if (!count($this->error)) {
306 if (!empty($_FILES['attachments'])) {
307 require_once 'MTrack/Attachment.php';
308 foreach ($_FILES['attachments']['name'] as $fileid => $name) {
310 MTrackAttachment::add("ticket:{$this->issue->tid}",
311 $_FILES['attachments']['tmp_name'][$fileid],
312 $_FILES['attachments']['name'][$fileid],
318 if (!count($this->error) && $this->id != 'new') {
319 require_once 'MTrack/Attachment.php';
320 MTrackAttachment::process_delete("ticket:{$this->issue->tid}", $CS);
323 if (isset($_POST['apply']) && !count($this->error)) {
325 header("Location: {$this->baseURL}/Ticket/{$this->issue->nsident}");
331 function initEditForm($params = array())
333 require_once 'HTML/Template/Flexy/Element.php';
334 require_once 'HTML/Template/Flexy/Factory.php';
335 $this->elements = array();
339 // FIX ME - need to determine who the owner is..
340 // for a new issue it's the person who created it.
341 // later on it's an assignement???
345 $this->elements['owner'] = new HTML_Template_Flexy_Element('select');
346 $this->elements['owner']->setOptions($users);
350 // keywords -- in toArray...
355 foreach(array( 'resolution', 'ticketstate' ) as $c) {
356 $d = DB_DataObject::factory('core_enum');
358 $d->orderBy('seqid ASC, name ASC');
360 $d->createBaseEntries();
363 $this->{$c} = $d->fetchAll('id','name');
369 // unset($ST['closed']);
370 // unset($ST[$this->issue->status]);
372 // $this->change_status = empty($ST) ? array() : array_keys($ST);
374 // admin can only change to 'fixed'?
376 $this->elements = HTML_Template_Flexy_Factory::fromArray($this->issue->toArray(), $this->elements);