MTrackWeb.php
[web.mtrack] / MTrackWeb.php
1 <?php
2 /**
3  * every class extends this...
4  */
5  
6  
7 class MTrackWeb extends HTML_FlexyFramework_Page
8 {
9     var $template = 'wiki.html';
10     var $priorities = array();
11     var $severities = array();
12     var $link = false; // the link handler..
13     
14     function hasPerm($what, $cando) {
15         // our whole perm logic sits in here....
16         
17         // here's how it works
18         // a) anonymous users - not authenticated.
19         // - can see projects that are in *PUBLIC project "MTrack.Repos", "S"
20         // - can see bugs that are in *PUBLIC project "MTrack.Issue", "S"
21         // - can see bugs that are in *PUBLIC project "MTrack.Wiki", "S"
22         if (!$this->authUser) {
23             if ($cando == 'S' &&
24                     in_array( $what , array( 'MTrack.Repos', 'MTrack.Issue', 'MTrack.Wiki'))) {
25                 
26                 return true; // not a diffinative answer...
27             }
28             return false;
29         }
30         
31         return $this->authUser->hasPerm($what, $cando); 
32     }
33     
34     function projectPerm($project_id, $what, $cando)
35     {
36         if (!$project_id) {
37             return false;
38         }
39         $p = DB_DataObject::factory('Projects');
40         $p->get($project_id);
41         if (!$this->authUser) {
42             if ($p->code != '*PUBLIC') {
43                 return false; // only public projects
44             }
45             if ($cando != 'S') {
46                 return false;
47             }
48             // all permissions to view public stuff.
49             return true;
50         }
51         if (!$this->authUser->hasPerm($what, $cando)) {
52             echo "NO PERMS $what $cando";
53             echo '<PRE>'; print_r($this->authUser->getPerms());
54             return false;
55         }
56         // membership rules?
57         //echo "COMPTYPE " . $this->authUser->company()->comptype ;
58         if ($this->authUser->company()->comptype == 'OWNER') {
59                 
60             if ($this->authUser->hasPerm('Core.Projects_All', $cando)) { // they can do what they like on all projects.
61                return true;
62             }
63            // return $p->hasPerm($what, $cando);
64         }
65         // otherwise they have to be a team member of that project.
66         
67         $pd = DB_DataObject::factory('ProjectDirectory');
68         $pd->project_id = $project_id;
69         $pd->user_id = $this->authUser->id;
70         $pd->whereAdd("role != ''");
71         
72         if (!$pd->count()) {
73             return false;
74         }
75         return true;
76          
77     }
78     
79     
80     function currentProject($val = false)
81     {
82         // we do need the option for me to look at all projects...
83         
84         
85         static $currentProject = false;
86         if (empty($_SESSION[__CLASS__])) {
87             $_SESSION[__CLASS__] = array();
88         }
89         
90         if ($val !== false) {
91             // attempt to set it..
92             $_SESSION[__CLASS__]['active_project_id'] = $val ;
93             $currentProject = $val ; 
94             // reset to ensure not cached..
95         }
96         $ar = $this->userProjects();
97         //print_r($ar);
98         if (!isset($ar[$currentProject])) {
99             $currentProject = false;
100             $_SESSION[__CLASS__]['active_project_id'] = false;
101         }
102         if ($currentProject !== false) {
103             return $currentProject;
104         }
105          
106         //print_r($ar);
107         
108         if (empty($_SESSION[__CLASS__]['active_project_id']) ||
109             !isset($ar[$_SESSION[__CLASS__]['active_project_id']]))
110         {
111             
112         
113             //$p = DB_DataObject::factory('Projects');
114             //$p->get('code', '*PUBLIC');
115             $id = 0;
116             foreach($ar as $k=>$v) {
117                 $id= $k;
118                 break;
119             }
120             
121         
122             $_SESSION[__CLASS__]['active_project_id'] = $id;
123             $currentProject = $_SESSION[__CLASS__]['active_project_id'];
124             return $id; // always allowed..
125         }
126         $currentProject = $_SESSION[__CLASS__]['active_project_id'];
127         return $_SESSION[__CLASS__]['active_project_id'];
128         
129         
130     }
131     
132     
133     function userProjects()
134     {
135         
136         $p = DB_DataObject::factory('Projects');
137         if (!$this->authUser) {
138             $p->code = '*PUBLIC';
139            
140             $ar = $p->fetchAll('id', 'name');
141         } else {
142             //DB_DAtaObject::debugLevel(1);
143             $p->applyFilters(array(), $this->authUser);
144             if (!$this->authUser->hasPerm('Core.Projects_All', 'S')) { 
145                 $p->whereAdd("Projects.id in (SELECT ProjectDirectory.project_id FROM ProjectDirectory WHERE
146                         person_id = ". $this->authUser->id . " and role != '')");
147             }
148             $p->whereAdd('id in (SELECT distinct(project_id) FROM mtrack_repos)');
149             // $pd->whereAdd("role != ''");
150             
151             $p->orderBy('Projects.name ASC');
152             unset($p->client_id); // default projects serach enforces this..
153             $ar = $p->fetchAll('id', 'name');
154         }
155         return $ar;
156         
157     }
158     
159     
160     function loadProjectList()
161     {
162        // DB_DataObject::debugLevel(1);
163
164         $ar = $this->userProjects();
165          
166         $this->elements['active_project_id'] = new HTML_Template_Flexy_Element();
167         $this->elements['active_project_id']->setOptions($ar);
168          
169         $this->elements['active_project_id']->setValue($this->currentProject());
170    
171         
172         
173     }
174     
175     
176     function getAuthUser()
177     {
178         $u = DB_DataObject::factory('Person');
179         if (!$u->isAuth()) {
180             return false;
181         }
182         return $u->getAuthUser();
183     }
184     /**
185      * base getAuth allows everyone in..
186      */
187     
188     function getAuth()
189     {
190         $this->registerClasses(); // to be destroyed??
191         
192         $ff = HTML_FlexyFramework::get();
193         if ($ff->cli) {
194             return true;
195         }
196         
197         // default timezone first..
198         $ff = HTML_FlexyFramework::get();
199         if (isset($ff->MTrack['timezone'])) {
200             date_default_timezone_set($ff->MTrack['timezone']);
201         }
202         
203         //MTrackConfig::boot(); // eak.. .remove me...
204       
205         $this->authUser = DB_DataObject::factory('Person')->getAuthUser();
206         
207         $this->loadProjectList();
208         
209         if (!$this->authUser) {
210             return true; // we do allow people in this far..
211         }
212         $this->authUserArray = $this->authUser->toArray();
213         unset($this->authUserArray['passwd']);
214          
215         // timezone setting... -- this may be a good addon to our core person class.
216         
217         if (!empty($this->authUser->timezone)) {
218             date_default_timezone_set($this->authUser->timezone);
219         }
220         
221         
222         
223          
224         /// fixme...
225         //$this->authUser = 
226         return true; // anyone at present..
227     }
228     function get($loc='')
229     {
230         // 
231         if (!empty($loc)) {
232             die ("invalid location". htmlspecialchars($loc));
233         }
234         if (!$this->authUser) {
235              return HTML_FlexyFramework::run('Wiki'); 
236         }
237         return HTML_FlexyFramework::run('Wiki/Today'); 
238  
239     }
240     function post()
241     {
242         header("Status: 404 Not Found");
243         die("not valid");
244     }
245     
246     
247     function initOptions()
248     {
249         
250          
251         $q = MTrackDB::q('select priorityname, value from priorities');
252
253         foreach ($q->fetchAll() as $row) {
254             $this->priorities[$row[0]] = $row[1];
255         }
256         $q = MTrackDB::q('select sevname, ordinal from severities');
257         
258         foreach ($q->fetchAll() as $row) {
259             $this->severities[$row[0]] = $row[1];
260         }
261
262     }
263     
264     function registerClasses()
265     {
266         require_once 'MTrack/Wiki.php';
267         require_once 'MTrack/Wiki/Item.php';
268       //  require_once 'MTrack/Milestone.php';
269   
270         
271         require_once 'MTrackWeb/LinkHandler.php';
272         require_once 'MTrack/Wiki/HTMLFormatter.php';
273         
274         $this->link = new MTrackWeb_LinkHandler();
275         MTrack_Wiki_HTMLFormatter::registerLinkHandler($this->link);
276  
277
278         $r = DB_DataObject::factory('mtrack_repos');
279         $r->loadFromPath('default/wiki');
280         MTrack_Wiki_Item::$repo = $r->impl();
281         
282         
283         
284         //MTrack_Wiki::register_macro('MilestoneSummary', array('MTrack_Milestone', 'macro_MilestoneSummary'));
285        // MTrack_Wiki::register_macro('BurnDown', array('MTrack_Milestone', 'macro_BurnDown'));
286         //MTrack_Wiki::register_macro('RunReport', array('MTrack_Report', 'macro_RunReport')); << fixme how are we to hanlde this..
287         //MTrack_Wiki::register_macro('TicketQuery', array('MTrack_Report', 'macro_TicketQuery'));
288         MTrack_Wiki::register_macro('IncludeWikiPage', array('MTrack_Wiki', 'macro_IncludeWiki'));
289         MTrack_Wiki::register_macro('IncludeHelpPage', array('MTrack_Wiki', 'macro_IncludeHelp'));
290         MTrack_Wiki::register_macro('Comment', array('MTrack_Wiki', 'macro_comment'));
291         MTrack_Wiki::register_processor('comment', array('MTrack_Wiki', 'processor_comment'));
292         MTrack_Wiki::register_processor('html', array('MTrack_Wiki', 'processor_html'));
293         MTrack_Wiki::register_processor('dataset', array('MTrack_Wiki', 'processor_dataset'));
294
295  
296         //MTrackSearchDB::register_indexer('ticket', array('MTrackIssue', 'index_issue'));
297         //MTrackSearchDB::register_indexer('wiki', array('MTrack_Wiki_Item', 'index_item'));
298
299
300
301         //MTrackWatch::registerEventTypes('ticket', array( 'ticket' => 'Tickets' ));
302         //MTrackWatch::registerEventTypes('milestone', array( 'ticket' => 'Tickets', 'changeset' => 'Code changes' ));
303         //MTrackWatch::registerEventTypes('repo', array( 'ticket' => 'Tickets', 'changeset' => 'Code changes' ));
304
305         // should this get registered here??
306         //MTrackCommitChecker::addCheck('Wiki');
307         
308         
309         
310    }
311     
312     function favicon()
313     {
314         return false;
315         /// FIXME - we should allow upload of a favion...
316         $ff = HTML_FlexyFramework::get();
317         
318         
319     }
320      
321     
322     /* renders the attachment list for a given object */
323     // was Attachments::render
324     // move it to MTrackWebAttachemnt...
325     
326   function attachmentsToHtml($object)
327   {
328     return 'TODO';
329     if (is_object($object)) {
330         $object = $object->toIdString(); // eg. ticket:1
331     }
332     $atts = MTrackDB::q('
333       select * from attachments
334       left join changes on (attachments.cid = changes.cid)
335       where attachments.object = ? order by changedate, filename',
336         $object)->fetchAll(PDO::FETCH_ASSOC);
337
338     if (count($atts) == 0) return '';
339
340     $max_dim = 150;
341
342     $html = "<div class='attachment-list'><b>Attachments</b><ul>";
343     foreach ($atts as $row) {
344       $url = "{$this->baseURL}/Attachment/$object/". $row['cid'] . '/' . $row['filename'];
345       
346       $html .= "<li><a class='attachment'" .
347         " href='$url'>".
348         "$row[filename]</a> ($row[size]) added by " .
349         $this->link->username($row['who'], array(
350           'no_image' => true
351         )) .
352         " " . $this->link->date($row['changedate']);
353         require_once 'MTrack/Attachment.php';
354       list($width, $height) = getimagesize(MTrackAttachment::local_path($row['hash']));
355       if ($width + $height) {
356         /* limit maximum size */
357         if ($width > $max_dim) {
358           $height *= $max_dim / $width;
359           $width = $max_dim;
360         }
361         if ($height > $max_dim) {
362           $width *= $max_dim / $height;
363           $height = $max_dim;
364         }
365         $html .= "<br><a href='$url'><img src='$url' width='$width' border='0' height='$height'></a>";
366       }
367
368       $html .= "</li>\n";
369     }
370     $html .= "</ul></div>";
371     return $html;
372   }
373     function jerr($str, $errors=array()) // standard error reporting..
374     {
375         require_once 'Services/JSON.php';
376         $json = new Services_JSON();
377         
378         // log all errors!!!
379         //$this->addEvent("ERROR", false, $str);
380         
381         if ((isset($_SERVER['CONTENT_TYPE']) && preg_match('#multipart/form-data#i', $_SERVER['CONTENT_TYPE']))) {
382             header('Content-type: text/html');
383             echo "<HTML><HEAD></HEAD><BODY>";
384             echo  $json->encodeUnsafe(array(
385                     'success'=> false, 
386                     'message' => $str, // compate with exeption / loadexception.
387
388                     'errors' => $errors ? $errors : true, // used by forms to flag errors.
389                     'authFailure' => !empty($errors['authFailure']),
390                 ));
391             echo "</BODY></HTML>";
392             exit;
393         }
394         
395         echo $json->encode(array(
396             'success'=> false, 
397             'data'=> array(), 
398             'message' => $str, // compate with exeption / loadexception.
399             'errors' => $errors ? $errors : true, // used by forms to flag errors.
400             'authFailure' => !empty($errors['authFailure']),
401         ));
402         exit;
403         
404     }
405     function jok($str)
406     {
407         
408         require_once 'Services/JSON.php';
409         $json = new Services_JSON();
410         
411         if ( (isset($_SERVER['CONTENT_TYPE']) && preg_match('#multipart/form-data#i', $_SERVER['CONTENT_TYPE']))
412         
413         ) {
414             header('Content-type: text/html');
415             echo "<HTML><HEAD></HEAD><BODY>";
416             echo  $json->encodeUnsafe(array('success'=> true, 'data' => $str));
417             echo "</BODY></HTML>";
418             exit;
419         }
420         
421         
422         echo  $json->encode(array('success'=> true, 'data' => $str));
423         exit;
424         
425     }
426     /**
427      * output data for grids or tree
428      * @ar {Array} ar Array of data
429      * @total {Number|false} total number of records (or false to return count(ar)
430      * @extra {Array} extra key value list of data to pass as extra data.
431      * 
432      */
433     function jdata($ar,$total=false, $extra=array())
434     {
435         // should do mobile checking???
436         if ($total == false) {
437             $total = count($ar);
438         }
439         $extra=  $extra ? $extra : array();
440         require_once 'Services/JSON.php';
441         $json = new Services_JSON();
442         echo $json->encode(array('success' =>  true, 'total'=> $total, 'data' => $ar) + $extra);    
443         exit;
444         
445         
446     }
447     
448     /**
449      * ---------------- Logging ---------------   
450      */
451     
452     /**
453      * addEventOnce:
454      * Log an action (only if it has not been logged already.
455      * 
456      * @param {String} action  - group/name of event
457      * @param {DataObject|false} obj - dataobject action occured on.
458      * @param {String} any remarks 
459      */
460     
461     function addEventOnce($act, $obj = false, $remarks = '') 
462     {
463         $au = $this->getAuthUser();
464         $e = DB_DataObject::factory('Events');
465         $e->init($act,$obj,$remarks); 
466         if ($e->find(true)) {
467             return;
468         }
469         $this->addEvent($act, $obj, $remarks);
470     }
471     /**
472      * addEvent:
473      * Log an action.
474      * 
475      * @param {String} action  - group/name of event
476      * @param {DataObject|false} obj - dataobject action occured on.
477      * @param {String} any remarks 
478      */
479     
480     function addEvent($act, $obj = false, $remarks = '') 
481     {
482         $au = $this->getAuthUser();
483         $e = DB_DataObject::factory('Events');
484         $e->init($act,$obj,$remarks); 
485          
486         $e->event_when = date('Y-m-d H:i:s');
487         
488         $eid = $e->insert();
489         $ff  = HTML_FlexyFramework::get();
490         if (empty($ff->Pman['event_log_dir'])) {
491             return;
492         }
493         $file = $ff->Pman['event_log_dir']. date('/Y/m/d/'). $eid . ".php";
494         if (!file_exists(dirname($file))) {
495             mkdir(dirname($file),0700,true);
496         }
497         file_put_contents($file, var_export(array(
498             'REQUEST_URI' => empty($_SERVER['REQUEST_URI']) ? 'cli' : $_SERVER['REQUEST_URI'],
499             'GET' => empty($_GET) ? array() : $_GET,
500             'POST' => empty($_POST) ? array() : $_POST,
501         ), true));
502         
503         
504         
505     }
506
507     
508     
509
510 }