MTrackWeb/TicketEdit.php
[web.mtrack] / MTrackWeb / TicketEdit.php
1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
3  
4 //require_once 'MTrack/Captcha.php';
5
6  
7 require_once 'MTrackWeb.php';
8 class MTrackWeb_TicketEdit extends MTrackWeb 
9 {
10     var $id; // 0 = new
11     var $issue;
12     var $preview;
13     var $error;
14     var $editable;
15     var $tid = 0; // or the MD5 rep.
16     
17      
18     
19     function getAuth() 
20     {
21         parent::getAuth();
22         //require_once 'MTrack/ACL.php';
23      //   MTrackACL::requireAllRights('Browser', 'read');
24         return true;
25   
26     }
27     
28     function get($pi= 0)
29     {
30     
31         if (!isset($_REQUEST['ajax_body'])) {
32             return;
33         }
34         $this->masterTemplate = 'ticket_edit.html';
35         $this->id = $pi ?  $pi: (isset($_GET['id']) ? $_GET['id'] : 0);
36         $this->id  = $this->id  == 'new' ? 0 : $this->id;
37         $this->id  = (int) $this->id;
38         
39     
40         // -- load issue..
41
42         $this->issue = DB_DataObject::factory('mtrack_ticket');
43
44         if ($this->id) {
45             if (!$this->issue->get($this->id)) {
46                 throw new Exception("Invalid ticket $this->id");
47             }
48             if ($this->id && $this->currentProject() != $this->issue->project_id) {
49                 throw new Exception("Project and ticket do not match..");
50             }
51             
52         } 
53         
54         
55         
56         //$this->issue->augmentFormFields($this->fieldset());
57
58
59         $this->preview = false;
60         $this->error = array();
61        
62        
63         if (!$this->id && !$this->hasPerm('MTrack.Issue','A')) {
64             return HTML_FlexyFramework::run('Noperm');
65         }
66         
67         
68         if ($this->id &&  (
69                 !$this->hasPerm('MTrack.Issue','S') || // general permission to view
70                 !$this->ticket->hasPerm($this->authUser,'S') // specific permission on this bug.
71                 
72             )) {
73             return HTML_FlexyFramework::run('Noperm');
74         }
75         
76         
77         
78         
79         
80         
81         // new is always editable..????
82         $this->editable = $this->id ?
83             $this->ticket->hasPerm($this->authUser,'E')  : true;
84          
85         $this->issue->milestoneURL = $this->baseURL.'/Milestone'; // fix me later..
86     
87         $this->showEditBar = false;
88          
89         if ($this->editable && $this->id   && !$this->preview) {
90             $this->showEditBar = true;
91         }
92         
93         if (empty($_POST)) {
94             return;
95         }
96         
97         $this->initEditForm();
98  
99         
100       
101     }
102    
103     function post() // handle the post...
104     {
105        
106         $this->get($_REQUEST['id']);
107         die("TODO");
108         if (isset($_POST['cancel'])) {
109             header("Location: {$$this->baseURL}/Ticket/$this->issue->nsident");
110             exit;
111           }
112           
113           if (!MTrack_Captcha::check('ticket')) {
114             $this->error[] = "CAPTCHA failed, please try again";
115           }
116           $this->preview = isset($_POST['preview']) ? true : false;
117
118           $comment = '';
119           try {
120             if (!$this->id) {
121               MTrackACL::requireAllRights("Tickets", 'create');
122             } else {
123               MTrackACL::requireAllRights("ticket:" . $this->issue->tid, 'modify');
124             }
125           } catch (Exception $e) {
126             $this->error[] = $e->getMessage();
127           }
128           
129           if (!$this->id) {
130             $comment = empty($_POST['comment']) ? '' : $_POST['comment'];
131           }
132           
133           if (!strlen($comment)) {
134             $comment = $_POST['summary'];
135           }
136           try {
137             $CS = MTrackChangeset::begin("ticket:X", $comment);
138           } catch (Exception $e) {
139             $this->error[] = $e->getMessage();
140             $CS = null;
141           }
142           if (!$this->id) {
143             // compute next id number.
144             // We don't use auto-number, because we allow for importing multiple
145             // projects with their own ticket sequence.
146             // During "normal" user-driven operation, we do want plain old id numbers
147             // so we compute it here, under a transaction
148             $db = MTrackDB::get();
149             
150             
151             
152             switch($db->getAttribute(PDO::ATTR_DRIVER_NAME)) {
153                 case 'pgsql':
154                     // Some versions of postgres don't like that we have "abc123" for
155                     // identifiers, so match on the bigest number nsident fields only
156                     $max = "select max(cast(nsident as integer)) + 1 from tickets where nsident ~ '^\\\\d+$'";
157                     break;
158                 
159                 case 'mysql':
160                     $max = "select max(cast(nsident as UNSIGNED)) + 1 from tickets";
161                     break;
162                 
163                 default:
164                     $max = 'select max(cast(nsident as integer)) + 1 from tickets';   
165                     break;
166             }
167             
168             
169              
170             list($this->issue->nsident) = MTrackDB::q($max)->fetchAll(PDO::FETCH_COLUMN, 0);
171             if ($this->issue->nsident === null) {
172               $this->issue->nsident = 1;
173             }
174           }
175
176           if (isset($_POST['action']) && !$this->preview) {
177             $act= explode('_', $_POST['action'] , 2);
178             //var_dump($act);exit;
179             switch ($act[0]) {
180               case 'leave':
181                 break;
182               case 'reopen':
183                 $this->issue->reOpen();
184                 break;
185               case 'fixed':
186                 $this->issue->resolution = 'fixed';
187                 $this->issue->close();
188                 $_POST['estimated'] = $this->issue->estimated;
189                 break;
190                 
191               
192               case 'accept':
193                 // will be applied to the issue further down
194                 $_POST['owner'] = MTrackAuth::whoami();
195                 if ($this->issue->status == 'new') {
196                   $this->issue->status = 'open';
197                 }
198                 break;
199                 
200                 
201               case 'resolve':
202                 //$this->issue->resolution = $_POST['resolution'];
203                 $this->issue->resolution = $act[1];
204                 $this->issue->close();
205                 $_POST['estimated'] = $this->issue->estimated;
206                 break;  
207                 
208               case 'change':
209                 $this->issue->status = $act[1];
210                 break;
211             }
212           }
213
214           $fields = array(
215             'summary',
216             'description',
217             'classification',
218             'priority',
219             'severity',
220             'changelog',
221             'owner',
222             'cc',
223           );
224
225           $this->issue->applyPOSTData($_POST);
226
227          
228           
229           foreach ($fields as $fieldname) {
230             if (isset($_POST[$fieldname]) && strlen($_POST[$fieldname])) {
231               $this->issue->$fieldname = $_POST[$fieldname];
232             } else {
233               $this->issue->$fieldname = null;
234             }
235           }
236
237           $kw = $this->issue->getKeywords();
238           $kill = array_values($kw);
239           foreach (preg_split('/[ \t,]+/', $_POST['keywords']) as $w) {
240             if (!strlen($w)) {
241               continue;
242             }
243             $x = array_search($w, $kw);
244             if ($x === false) {
245               $k = MTrackKeyword::loadByWord($w);
246               if ($k === null) {
247                 $k = new MTrackKeyword;
248                 $k->keyword = $w;
249                 $k->save($CS);
250               }
251               $this->issue->assocKeyword($k);
252             } else {
253               $w = array_search($w, $kill);
254               if ($w !== false) {
255                 unset($kill[$w]);
256               }
257             }
258           }
259           foreach ($kill as $w) {
260             $this->issue->dissocKeyword($w);
261           }
262
263           $ms = $this->issue->getMilestones();
264           $kill = $ms;
265           if (isset($_POST['milestone']) && is_array($_POST['milestone'])) {
266             foreach ($_POST['milestone'] as $mid) {
267               $this->issue->assocMilestone($mid);
268               unset($kill[$mid]);
269             }
270           }
271           foreach ($kill as $mid) {
272             $this->issue->dissocMilestone($mid);
273           }
274
275           $ms = $this->issue->getComponents();
276           $kill = $ms;
277           if (isset($_POST['component']) && is_array($_POST['component'])) {
278             foreach ($_POST['component'] as $mid) {
279               $this->issue->assocComponent($mid);
280               unset($kill[$mid]);
281             }
282           }
283           foreach ($kill as $mid) {
284             $this->issue->dissocComponent($mid);
285           }
286           
287             if (!empty($_POST['comment'])) {
288                $this->issue->addComment($_POST['comment']);
289             }
290           
291           $this->issue->addEffort(
292             empty($_POST['spent']) ? 0 : $_POST['spent'], 
293             empty($_POST['estimate']) ? 0 : $_POST['estimate']
294         );
295
296           if (!count($this->error)) {
297             try {
298               $this->issue->save($CS);
299               
300               // make sure everyone is watching it!!!!
301                 if($this->issue->owner && $this->issue->tid) {
302                   // make sure owner is tracking it...
303                     MTrackWatch::watch_object('ticket', $this->issue->tid,  $this->issue->owner);
304                 }
305                 
306                 if ($this->id == 'new') {
307                     MTrackWatch::watch_object('ticket', $this->issue->tid,  MTrackAuth::whoami());
308                 }
309               
310               
311               $CS->setObject("ticket:" . $this->issue->tid);
312             } catch (Exception $e) {
313               $this->error[] = $e->getMessage();
314             }
315         }
316
317         if (!count($this->error)) {
318             if (!empty($_FILES['attachments'])) {
319                 require_once 'MTrack/Attachment.php';
320                 foreach ($_FILES['attachments']['name'] as $fileid => $name) {
321                       
322                     MTrackAttachment::add("ticket:{$this->issue->tid}",
323                         $_FILES['attachments']['tmp_name'][$fileid],
324                         $_FILES['attachments']['name'][$fileid],
325                         $CS
326                     );
327                 }
328             }
329         }
330         if (!count($this->error) && $this->id != 'new') {
331             require_once 'MTrack/Attachment.php';
332             MTrackAttachment::process_delete("ticket:{$this->issue->tid}", $CS);
333         }
334
335         if (isset($_POST['apply']) && !count($this->error)) {
336           $CS->commit();
337           header("Location: {$this->baseURL}/Ticket/{$this->issue->nsident}");
338           exit;
339         }
340     }
341       
342          
343     function initEditForm($params = array())
344     {
345         require_once 'HTML/Template/Flexy/Element.php';
346         require_once 'HTML/Template/Flexy/Factory.php';
347         $this->elements = array();
348         
349         
350         
351         foreach(array( 'classification', 'priority', 'severity', 'resolution' ) as $c)  {
352             $d = DB_DataObject::factory('core_enum');
353             $d->etype = $c;
354             $d->orderBy('seqid ASC, name ASC');
355             if (!$d->count()) {
356                 $d->createBaseEntries();
357                 
358             }
359             $ar = $d->fetchAll('id','name');
360             if (!$this->id) {
361                 $ar = array_merge( array(0 => '-- Select --'),$ar);
362             }
363             $this->elements[$c] = new HTML_Template_Flexy_Element('select');
364             
365             
366             
367             $this->elements[$c]->setOptions($ar);
368             
369         }
370         
371         if (false && $this->currentProject()) {
372             $d = DB_DataObject::factory('mtrack_project_component');
373             $d->project_id = $this->currentProject();
374             $d->orderBy('name');
375             $d->whereAdd('deleted != 1');
376             $this->elements['component[]'] = new HTML_Template_Flexy_Element('select');
377             $this->elements['component[]']->setOptions($d->fetchAll('id', 'name'));
378             $ar = $this->issue->components();
379             $this->elements['component[]']->setValue(array_keys($ar));
380         
381         
382             $d = DB_DataObject::factory('mtrack_milestone');
383             $d->project_id = $this->currentProject();
384             $d->orderBy('(case when duedate is null then 1 else 0 end), duedate, name');
385             $d->whereAdd('completed != 1');
386             $d->whereAdd('deleted != 1');
387             $this->elements['milestone'] = new HTML_Template_Flexy_Element('select');
388             $this->elements['milestone']->setOptions($d->fetchAll('id', 'name'));
389             $ar = $this->issue->milestone();
390             $this->elements['milestone']->setValue(array_keys($ar));
391         }
392         
393         // FIX ME - need to determine who the owner is..
394         // for a new issue it's the person who created it.
395         // later on it's an assignement???
396         
397         $users = array();
398          
399         $this->elements['owner'] = new HTML_Template_Flexy_Element('select');
400         $this->elements['owner']->setOptions($users);
401         
402         
403         
404         // keywords -- in toArray...
405         // milestone 
406           
407           
408         
409
410           
411     }
412    
413      
414     function eq($a,$b) {
415         return $a == $b;
416     }
417     
418 }