Pman.php
[Pman.Base] / Pman.php
1 <?php 
2 /**
3  * Pman Base class
4  * 
5  * Provides:
6  *  - base application setup (variables etc to javascript)
7  * 
8  *  - authentication and permission info about user / application
9  *  - json output methods.
10  *  - file upload error checking - checkFileUploadError
11  *  - logging to event table
12  *  - sendTemplate code (normally use the Person version for sending to specific people..)
13  * 
14  *  - doc managment code?? - remarks and tracking??? - MOVEME
15  *  - authentication link checking?? MOVEME?
16  *  - authentication reset password ?? MOVEME?
17  *  ?? arrayClean.. what's it doing here?!? ;)
18  * 
19  * Usefull implemetors
20  * DB_DataObject*:*toEventString (for logging - this is generically prefixed to all database operations.)
21  *   - any data object where this method exists, the result will get prefixed to the log remarks
22  */
23
24 class Pman extends HTML_FlexyFramework_Page 
25 {
26     var $appName= "";
27     var $appLogo= "";
28     var $appShortName= "";
29     var $appVersion = "1.8";
30     var $version = 'dev';
31     var $onloadTrack = 0;
32     var $linkFail = "";
33     var $showNewPass = 0;
34     var $logoPrefix = '';
35     var $appModules = '';
36     var $appDisabled = array(); // array of disabled modules..
37                     // (based on config option disable)
38     
39     var $authUser; // always contains the authenticated user..
40     
41     var $disable_jstemplate = false; /// disable inclusion of jstemplate code..
42     var $company = false;
43     
44     /**
45      * ------------- Standard getAuth/get/post methods of framework.
46      * 
47      * 
48      */
49     
50     function getAuth() // everyone allowed in!!!!!
51     {
52         $this->loadOwnerCompany();
53         
54         return true;
55         
56     }
57     
58     function init() 
59     {
60         if (isset($this->_hasInit)) {
61             return;
62         }
63         $this->_hasInit = true;
64          // move away from doing this ... you can access bootLoader.XXXXXX in the master template..
65         $boot = HTML_FlexyFramework::get();
66         // echo'<PRE>';print_R($boot);exit;
67         $this->appName= $boot->appName;
68         $this->appNameShort= $boot->appNameShort;
69         
70         
71         $this->appModules= $boot->enable;
72         $this->isDev = empty($boot->Pman['isDev']) ? false : $boot->Pman['isDev'];
73         $this->appDisable = $boot->disable;
74         $this->appDisabled = explode(',', $boot->disable);
75         $this->version = $boot->version; 
76         $this->uiConfig = empty($boot->Pman['uiConfig']) ? false : $boot->Pman['uiConfig']; 
77         
78         if (!empty($ff->Pman['local_autoauth']) && 
79             ($_SERVER['SERVER_ADDR'] == '127.0.0.1') &&
80             ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') 
81         ) {
82             $this->isDev = true;
83         }
84         //var_dump($this->appModules);
85         foreach(explode(',',$this->appModules) as $m) {
86             $cls = 'Pman_'. $m . '_Pman';
87             //echo $cls;
88             //echo $this->rootDir . '/'.str_replace('_','/', $cls). '.php';
89             
90             if (!file_exists($this->rootDir . '/'.str_replace('_','/', $cls). '.php')) {
91                 continue;
92             }
93             require_once str_replace('_','/', $cls). '.php';
94             $c = new $cls();
95             if (method_exists($c,'init')) {
96                 $c->init($this);
97             }
98         }
99         
100         
101     }
102     
103     function get($base) 
104     {
105         $this->init();
106             //$this->allowSignup= empty($opts['allowSignup']) ? 0 : 1;
107         $bits = explode('/', $base);
108         //print_R($bits);
109         if ($bits[0] == 'Link') {
110             $this->linkFail = $this->linkAuth(@$bits[1],@$bits[2]);
111             header('Content-type: text/html; charset=utf-8');
112             return;
113         }
114         
115         // should really be moved to Login...
116         
117         if ($bits[0] == 'PasswordReset') {
118             $this->linkFail = $this->resetPassword(@$bits[1],@$bits[2],@$bits[3]);
119             header('Content-type: text/html; charset=utf-8');
120             return;
121         } 
122          
123         $au = $this->getAuthUser();
124         if ($au) {
125             $ff= HTML_FlexyFramework::get();
126            
127             if (!empty($ff->Pman['auth_comptype']) && $au->id > 0 &&
128                 ( !$au->company_id || ($ff->Pman['auth_comptype'] != $au->company()->comptype))) {
129          
130                 $au->logout();
131                 
132                 $this->jerr("Login not permited to outside companies - please reload");
133             }
134             $this->addEvent("RELOAD");
135         }
136         
137         
138         if (strlen($base)) {
139             $this->addEvent("BADURL", false, $base);
140             $this->jerr("invalid url");
141         }
142         // deliver template
143         if (isset($_GET['onloadTrack'])) {
144             $this->onloadTrack = (int)$_GET['onloadTrack'];
145         }
146         // getting this to work with xhtml is a nightmare
147         // = nbsp / <img> issues screw everyting up.
148          //var_dump($this->isDev);
149         // force regeneration on load for development enviroments..
150         
151         HTML_FlexyFramework::get()->generateDataobjectsCache($this->isDev);
152         
153         //header('Content-type: application/xhtml+xml; charset=utf-8');
154         
155         
156         
157         if ($this->company && $this->company->logo_id) {
158             $im = DB_DataObject::Factory('Images');
159             $im->get($this->company->logo_id);
160             $this->appLogo = $this->baseURL . '/Images/Thumb/300x100/'. $this->company->logo_id .'/' . $im->filename;
161         }
162         
163         header('Content-type: text/html; charset=utf-8');
164          
165     }
166     function post($base) {
167         return $this->get($base);
168     }
169     
170     
171     // --------------- AUTHENTICATION or  system information
172     /**
173      * loadOwnerCompany:
174      * finds the compay with comptype=='OWNER'
175      *
176      * @return {Pman_Core_DataObjects_Companies} the owner company
177      */
178     function loadOwnerCompany()
179     {
180         // only applies if authtable is person..
181         $ff = HTML_FlexyFramework::get();
182         if (!empty($ff->Pman['authTable']) && $ff->Pman['authTable'] != 'Person') {
183             return false;
184         }
185         
186         $this->company = DB_DataObject::Factory('Companies');
187         if (!is_a($this->company, 'DB_DataObject')) { // non-core pman projects
188             return false; 
189         }
190         $this->company->get('comptype', 'OWNER');
191         return $this->company;
192     }
193     
194     
195     
196     /**
197      * getAuthUser: - get the authenticated user..
198      *
199      * @return {DB_DataObject} of type Pman[authTable] if authenticated.
200      */
201     
202     function getAuthUser()
203     {
204         if (!empty($this->authUser)) {
205             return $this->authUser;
206         }
207         $ff = HTML_FlexyFramework::get();
208         $tbl = empty($ff->Pman['authTable']) ? 'Person' : $ff->Pman['authTable'];
209         
210         $u = DB_DataObject::factory( $tbl );
211         if (!$u->isAuth()) {
212             return false;
213         }
214         $this->authUser =$u->getAuthUser();
215         return $this->authUser ;
216     }
217     /**
218      * hasPerm:
219      * wrapper arround authuser->hasPerm
220      * @see Pman_Core_DataObjects_User::hasPerm
221      *
222      * @param {String} $name  The permission name (eg. Projects.List)
223      * @param {String} $lvl   eg. (C)reate (E)dit (D)elete ... etc.
224      * 
225      */
226     function hasPerm($name, $lvl)  // do we have a permission
227     {
228         static $pcache = array();
229         $au = $this->getAuthUser();
230         return $au && $au->hasPerm($name,$lvl);
231         
232     }
233    
234     /**
235      * modulesList:  List the modules in the application
236      *
237      * @return {Array} list of modules
238      */
239     function modulesList()
240     {
241         $boot = HTML_FlexyFramework::get();
242         // echo'<PRE>';print_R($boot);exit;
243          
244          
245         $mods = explode(',', $boot->enable);
246         if (in_array('Core',$mods)) { // core has to be the first  modules loaded as it contains Pman.js
247             array_unshift($mods,   'Core');
248         }
249         
250         if (in_array($boot->appNameShort,$mods)) { // Project has to be the last  modules loaded as it contains Pman.js
251             unset($mods[array_search($boot->appNameShort, $mods)]);
252             $mods[] = $boot->appNameShort;
253         }
254         
255         $mods = array_unique($mods);
256          
257         $disabled =  explode(',', $boot->disable ? $boot->disable : '');
258         $ret = array();
259         foreach($mods as $mod) {
260             // add the css file..
261             if (in_array($mod, $disabled)) {
262                 continue;
263             }
264             $ret[] = $mod;
265         }
266         return $ret;
267     }
268     
269      
270     
271     
272     function hasModule($name) 
273     {
274         $this->init();
275         if (!strpos( $name,'.') ) {
276             // use enable / disable..
277             return in_array($name, $this->modules()); 
278         }
279         
280         $x = DB_DataObject::factory('Group_Rights');
281         $ar = $x->defaultPermData();
282         if (empty($ar[$name]) || empty($ar[$name][0])) {
283             return false;
284         }
285         return true;
286     }
287     
288      
289     
290     
291
292     
293     
294     
295         
296     /**
297      * ---------------- Global Tools ---------------   
298      */
299     function checkFileUploadError()  // check for file upload errors.
300     {    
301         if (
302             empty($_FILES['File']) 
303             || empty($_FILES['File']['name']) 
304             || empty($_FILES['File']['tmp_name']) 
305             || empty($_FILES['File']['type']) 
306             || !empty($_FILES['File']['error']) 
307             || empty($_FILES['File']['size']) 
308         ) {
309             $this->jerr("File upload error: <PRE>" . print_r($_FILES,true) . print_r($_POST,true) . "</PRE>");
310         }
311     }
312     
313     
314     /**
315      * generate a tempory file with an extension (dont forget to delete it)
316      */
317     
318     function tempName($ext)
319     {
320         $x = tempnam(ini_get('session.save_path'), HTML_FlexyFramework::get()->appNameShort.'TMP');
321         unlink($x);
322         return $x .'.'. $ext;
323     }
324     /**
325      * ------------- Authentication testing ------ ??? MOVEME?
326      * 
327      * 
328      */
329     function linkAuth($trid, $trkey) 
330     {
331         $tr = DB_DataObject::factory('Documents_Tracking');
332         if (!$tr->get($trid)) {
333             return "Invalid URL";
334         }
335         if (strtolower($tr->authkey) != strtolower($trkey)) {
336             $this->AddEvent("ERROR-L", false, "Invalid Key");
337             return "Invalid KEY";
338         }
339         // check date..
340         $this->onloadTrack = (int) $tr->doc_id;
341         if (strtotime($tr->date_sent) < strtotime("NOW - 14 DAYS")) {
342             $this->AddEvent("ERROR-L", false, "Key Expired");
343             return "Key Expired";
344         }
345         // user logged in and not
346         $au = $this->getAuthUser();
347         if ($au && $au->id && $au->id != $tr->person_id) {
348             $au->logout();
349             
350             return "Logged Out existing Session\n - reload to log in with correct key";
351         }
352         if ($au) { // logged in anyway..
353             $this->AddEvent("LOGIN", false, "With Key (ALREADY)");
354             header('Location: ' . $this->baseURL.'?onloadTrack='.$this->onloadTrack);
355             exit;
356             return false;
357         }
358         
359         // authenticate the user...
360         // slightly risky...
361         $u = DB_DataObject::factory('Person');
362          
363         $u->get($tr->person_id);
364         $u->login();
365         $this->AddEvent("LOGIN", false, "With Key");
366         
367         // we need to redirect out - otherwise refererer url will include key!
368         header('Location: ' . $this->baseURL.'?onloadTrack='.$this->onloadTrack);
369         exit;
370         
371         return false;
372         
373         
374         
375         
376     }
377     
378     
379     /**
380      * ------------- Authentication password reset ------ ??? MOVEME?
381      * 
382      * 
383      */
384     
385     
386     function resetPassword($id,$t, $key)
387     {
388         
389         $au = $this->getAuthUser();
390         if ($au) {
391             return "Already Logged in - no need to use Password Reset";
392         }
393         
394         $u = DB_DataObject::factory('Person');
395         //$u->company_id = $this->company->id;
396         $u->active = 1;
397         if (!$u->get($id) || !strlen($u->passwd)) {
398             return "invalid id";
399         }
400         
401         // validate key.. 
402         if ($key != $u->genPassKey($t)) {
403             return "invalid key";
404         }
405         $uu = clone($u);
406         $u->no_reset_sent = 0;
407         $u->update($uu);
408         
409         if ($t < strtotime("NOW - 1 DAY")) {
410             return "expired";
411         }
412         $this->showNewPass = implode("/", array($id,$t,$key));
413         return false;
414     }
415     
416     /**
417      * jerrAuth: standard auth failure - with data that let's the UI know..
418      */
419     function jerrAuth()
420     {
421         $au = $this->authUser();
422         if ($au) {
423             // is it an authfailure?
424             $this->jerr("Permission denied to view this resource", array('authFailure' => true));
425         }
426         $this->jerr("Not authenticated", array('authFailure' => true));
427     }
428      
429      
430      
431     /**
432      * ---------------- Standard JSON outputers. - used everywhere
433      */
434     
435     function jerr($str, $errors=array(), $content_type = false) // standard error reporting..
436     {
437         $this->addEvent("ERROR", false, $str);
438          
439         $cli = HTML_FlexyFramework::get()->cli;
440         if ($cli) {
441             echo "ERROR: " .$str . "\n";
442             exit;
443         }
444         
445         
446         if ($content_type == 'text/plain') {
447             header('Content-Disposition: attachment; filename="error.txt"');
448             header('Content-type: '. $content_type);
449             echo "ERROR: " .$str . "\n";
450             exit;
451         } 
452         
453         
454         
455         require_once 'Services/JSON.php';
456         $json = new Services_JSON();
457         
458         // log all errors!!!
459         
460         
461         if (!empty($_REQUEST['returnHTML']) || 
462             (isset($_SERVER['CONTENT_TYPE']) && preg_match('#multipart/form-data#i', $_SERVER['CONTENT_TYPE']))
463         ) {
464             header('Content-type: text/html');
465             echo "<HTML><HEAD></HEAD><BODY>";
466             echo  $json->encodeUnsafe(array(
467                     'success'=> false, 
468                     'errorMsg' => $str,
469                     'message' => $str, // compate with exeption / loadexception.
470
471                     'errors' => $errors ? $errors : true, // used by forms to flag errors.
472                     'authFailure' => !empty($errors['authFailure']),
473                 ));
474             echo "</BODY></HTML>";
475             exit;
476         }
477         
478         if (isset($_REQUEST['_debug'])) {
479             echo '<PRE>'.htmlspecialchars(print_r(array(
480                 'success'=> false, 
481                 'data'=> array(), 
482                 'errorMsg' => $str,
483                 'message' => $str, // compate with exeption / loadexception.
484                 'errors' => $errors ? $errors : true, // used by forms to flag errors.
485                 'authFailure' => !empty($errors['authFailure']),
486             ),true));
487             exit;
488                 
489         }
490         
491         echo $json->encode(array(
492             'success'=> false, 
493             'data'=> array(), 
494             'errorMsg' => $str,
495             'message' => $str, // compate with exeption / loadexception.
496             'errors' => $errors ? $errors : true, // used by forms to flag errors.
497             'authFailure' => !empty($errors['authFailure']),
498         ));
499         
500         
501         exit;
502         
503     }
504     function jok($str)
505     {
506         $cli = HTML_FlexyFramework::get()->cli;
507         if ($cli) {
508             echo "OK: " .$str . "\n";
509             exit;
510         }
511         require_once 'Services/JSON.php';
512         $json = new Services_JSON();
513         
514         if (!empty($_REQUEST['returnHTML']) || 
515             (isset($_SERVER['CONTENT_TYPE']) && preg_match('#multipart/form-data#i', $_SERVER['CONTENT_TYPE']))
516         
517         ) {
518             header('Content-type: text/html');
519             echo "<HTML><HEAD></HEAD><BODY>";
520             // encode html characters so they can be read..
521             echo  str_replace(array('<','>'), array('\u003c','\u003e'),
522                         $json->encodeUnsafe(array('success'=> true, 'data' => $str)));
523             echo "</BODY></HTML>";
524             exit;
525         }
526         
527         
528         echo  $json->encode(array('success'=> true, 'data' => $str));
529         
530         exit;
531         
532     }
533     /**
534      * output data for grids or tree
535      * @ar {Array} ar Array of data
536      * @total {Number|false} total number of records (or false to return count(ar)
537      * @extra {Array} extra key value list of data to pass as extra data.
538      * 
539      */
540     function jdata($ar,$total=false, $extra=array(), $cachekey = false)
541     {
542         // should do mobile checking???
543         if ($total == false) {
544             $total = count($ar);
545         }
546         $extra=  $extra ? $extra : array();
547         require_once 'Services/JSON.php';
548         $json = new Services_JSON();
549         if (isset($_SERVER['CONTENT_TYPE']) && preg_match('#multipart/form-data#i', $_SERVER['CONTENT_TYPE'])) {
550             
551             header('Content-type: text/html');
552             echo "<HTML><HEAD></HEAD><BODY>";
553             // encode html characters so they can be read..
554             echo  str_replace(array('<','>'), array('\u003c','\u003e'),
555                         $json->encodeUnsafe(array('success' =>  true, 'total'=> $total, 'data' => $ar) + $extra));
556             echo "</BODY></HTML>";
557             exit;
558         }
559         
560         
561         // see if trimming will help...
562         if (!empty($_REQUEST['_pman_short'])) {
563             $nar = array();
564             
565             foreach($ar as $as) {
566                 $add = array();
567                 foreach($as as $k=>$v) {
568                     if (is_string($v) && !strlen(trim($v))) {
569                         continue;
570                     }
571                     $add[$k] = $v;
572                 }
573                 $nar[] = $add;
574             }
575             $ar = $nar;
576               
577         }
578         
579       
580         $ret =  $json->encode(array('success' =>  true, 'total'=> $total, 'data' => $ar) + $extra);  
581         
582         if (!empty($cachekey)) {
583             
584             $fn = ini_get('session.save_path') . '/json-cache'.date('/Y/m/d').'.'. $cachekey . '.cache.json';
585             if (!file_exists(dirname($fn))) {
586                 mkdir(dirname($fn), 0777,true);
587             }
588             file_put_contents($fn, $ret);
589         }
590         echo $ret;
591         exit;
592     }
593     
594     
595     
596     /** a daily cache **/
597     function jdataCache($cachekey)
598     {
599         $fn = ini_get('session.save_path') . '/json-cache'.date('/Y/m/d').'.'. $cachekey . '.cache.json';
600         if (file_exists($fn)) {
601             header('Content-type: application/json');
602             echo file_get_contents($fn);
603             exit;
604         }
605         return false;
606         
607     }
608     
609    
610     
611     /**
612      * ---------------- OUTPUT
613      */
614     function hasBg($fn) // used on front page to check if logos exist..
615     {
616         return file_exists($this->rootDir.'/Pman/'.$this->appNameShort.'/templates/images/'.  $fn);
617     }
618      /**
619      * outputJavascriptIncludes:
620      *
621      * output <script....> for all the modules in the applcaiton
622      *
623      */
624     function outputJavascriptIncludes()  
625     {
626         
627         $mods = $this->modulesList();
628         
629         foreach($mods as $mod) {
630             // add the css file..
631         
632             
633             $files = $this->moduleJavascriptList($mod.'/widgets');
634              foreach($files as $f) {
635                 echo '<script type="text/javascript" src="'. $f. '"></script>'."\n";
636             }
637             
638             $files = $this->moduleJavascriptList($mod);
639             foreach($files as $f) {
640                 echo '<script type="text/javascript" src="'. $f. '"></script>'."\n";
641             }
642             
643         }
644         if (empty($this->disable_jstemplate)) {
645         // and finally the JsTemplate...
646             echo '<script type="text/javascript" src="'. $this->baseURL. '/Core/JsTemplate"></script>'."\n";
647         }
648          
649     }
650      /**
651      * outputCSSIncludes:
652      *
653      * output <link rel=stylesheet......> for all the modules in the applcaiton
654      *
655      *
656      * This could css minify as well.
657      */
658     function outputCSSIncludes() // includes on CSS links.
659     {
660         
661         $mods = $this->modulesList();
662         
663         
664         foreach($mods as $mod) {
665             // add the css file..
666             $dir = $this->rootDir.'/Pman/'.$mod;
667             $ar = glob($dir . '/*.css');
668             foreach($ar as $fn) { 
669                 $css = $this->rootURL .'/Pman/'.$mod.'/'.basename($fn) . '?ts=' . filemtime($fn);
670                 echo '<link rel="stylesheet" type="text/css" href="'.$css.'" />'."\n";
671             }
672              
673             
674         }
675          
676     }
677       
678     /**
679      * Gather infor for javascript files..
680      *
681      * @param {String} $mod the module to get info about.
682      * @return {StdClass}  details about module.
683      */
684     function moduleJavascriptFilesInfo($mod)
685     {
686         
687         static $cache = array();
688         
689         if (isset($cache[$mod])) {
690             return $cache[$mod];
691         }
692         
693         
694         $ff = HTML_FlexyFramework::get();
695         
696         $base = dirname($_SERVER['SCRIPT_FILENAME']);
697         $dir =   $this->rootDir.'/Pman/'. $mod;
698         $path = $this->rootURL ."/Pman/$mod/";
699         
700         $ar = glob($dir . '/*.js');
701         
702         $files = array();
703         $arfiles = array();
704         $maxtime = 0;
705         $mtime = 0;
706         foreach($ar as $fn) {
707             $f = basename($fn);
708             // got the 'module file..'
709             $mtime = filemtime($dir . '/'. $f);
710             $maxtime = max($mtime, $maxtime);
711             $arfiles[$fn] = $mtime;
712             $files[] = $path . $f . '?ts='.$mtime;
713         }
714         
715         ksort($arfiles); // just sort by name so it's consistant for serialize..
716         
717         $compile  = empty($ff->Pman['public_cache_dir']) ? 0 : 1;
718         $basedir = $compile ? $ff->Pman['public_cache_dir'] : false;
719         $baseurl = $compile ? $ff->Pman['public_cache_url'] : false;
720         
721         $lsort = create_function('$a,$b','return strlen($a) > strlen($b) ? 1 : -1;');
722         usort($files, $lsort);
723         
724         $smod = str_replace('/','.',$mod);
725         
726         $output = date('Y-m-d-H-i-s-', $maxtime). $smod .'-'.md5(serialize($arfiles)) .'.js';
727         
728         
729         // why are translations done like this - we just build them on the fly frmo the database..
730         $tmtime = file_exists($this->rootDir.'/_translations_/'. $smod.'.js')
731             ? filemtime($this->rootDir.'/_translations_/'. $smod.'.js') : 0;
732         
733         $cache[$mod]  = (object) array(
734             'smod' =>               $smod, // module name without '/'
735             'files' =>              $files, // list of all files.
736             'filesmtime' =>         $arfiles,  // map of mtime=>file
737             'maxtime' =>            $maxtime, // max mtime
738             'compile' =>            $this->isDev ? false : $compile,
739             'translation_file' =>   $base .'/_translations_/' . $smod .  '.js',
740             'translation_mtime' =>  $tmtime,
741             'output' =>             $output,
742             'translation_data' =>   preg_replace('/\.js$/', '.__translation__.js', $output),
743             'translation_base' =>   $dir .'/', //prefix of filename (without moudle name))
744             'basedir' =>            $basedir,   
745             'baseurl' =>            $baseurl,
746             'module_dir' =>         $dir,  
747         );
748         return $cache[$mod];
749     }
750      
751     
752     /**
753      *  moduleJavascriptList: list the javascript files in a module
754      *
755      *  The original version of this.. still needs more thought...
756      *
757      *  Compiled is in Pman/_compiled_/{$mod}/{LATEST...}.js
758      *  Translations are in Pman/_translations_/{$mod}.js
759      *  
760      *  if that stuff does not exist just list files in  Pman/{$mod}/*.js
761      *
762      *  Compiled could be done on the fly..
763      * 
764      *
765      *
766      *  @param {String} $mod  the module to look at - eg. Pman/{$mod}/*.js
767      *  @return {Array} list of include paths (either compiled or raw)
768      *
769      */
770
771     
772     
773     function moduleJavascriptList($mod)
774     {
775         
776         
777         $dir =   $this->rootDir.'/Pman/'. $mod;
778         
779         
780         if (!file_exists($dir)) {
781             echo '<!-- missing directory '. htmlspecialchars($dir) .' -->';
782             return array();
783         }
784         
785         $info = $this->moduleJavascriptFilesInfo($mod);
786        
787         
788           
789         if (empty($info->files)) {
790             return array();
791         }
792         // finally sort the files, so they are in the right order..
793         
794         // only compile this stuff if public_cache is set..
795         
796          
797         // suggestions...
798         //  public_cache_dir =   /var/www/myproject_cache
799         //  public_cache_url =   /myproject_cache    (with Alias apache /myproject_cache/ /var/www/myproject_cache/)
800         
801         // bit of debugging
802         if (!$info->compile) {
803             echo "<!-- Javascript compile turned off (isDev on, or public_cache_dir not set) -->\n";
804             return $info->files;
805         }
806         
807         // where are we going to write all of this..
808         // This has to be done via a 
809         if (!file_exists($info->basedir.'/'.$info->output) || !filesize($info->basedir.'/'.$info->output)) {
810             require_once 'Pman/Core/JsCompile.php';
811             $x = new Pman_Core_JsCompile();
812             
813             $x->pack($info->filesmtime,$info->basedir.'/'.$info->output, $info->translation_base);
814         } else {
815             echo "<!-- file exists not exist: {$info->basedir}/{$info->output} -->\n";
816         }
817         
818         if (file_exists($info->basedir.'/'.$info->output) &&
819                 filesize($info->basedir.'/'.$info->output)) {
820             
821             $ret =array(
822                 $info->baseurl.'/'. $info->output,
823               
824             );
825             // output all the ava
826             // fixme  - this needs the max datetime for the translation file..
827             $ret[] = $this->baseURL."/Admin/InterfaceTranslations/".$mod.".js"; //?ts=".$info->translation_mtime;
828             
829             //if ($info->translation_mtime) {
830             //    $ret[] = $this->rootURL."/_translations_/". $info->smod.".js?ts=".$info->translation_mtime;
831             //}
832             return $ret;
833         }
834         
835         
836         
837         // give up and output original files...
838         
839          
840         return $info->files;
841
842         
843     }
844     
845     /**
846      * Error handling...
847      *  PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($this, 'onPearError'));
848      */
849     
850     static $permitError = false;
851     
852     function onPearError($err)
853     {
854         static $reported = false;
855         if ($reported) {
856             return;
857         }
858         
859         if (Pman::$permitError) {
860              
861             return;
862             
863         }
864         
865         
866         $reported = true;
867         $out = $err->toString();
868         
869         
870         //print_R($bt); exit;
871         $ret = array();
872         $n = 0;
873         foreach($err->backtrace as $b) {
874             $ret[] = @$b['file'] . '(' . @$b['line'] . ')@' .   @$b['class'] . '::' . @$b['function'];
875             if ($n > 20) {
876                 break;
877             }
878             $n++;
879         }
880         //convert the huge backtrace into something that is readable..
881         $out .= "\n" . implode("\n",  $ret);
882      
883         
884         $this->jerr($out);
885         
886         
887         
888     }
889     
890     
891     /**
892      * ---------------- Logging ---------------   
893      */
894     
895     /**
896      * addEventOnce:
897      * Log an action (only if it has not been logged already.
898      * 
899      * @param {String} action  - group/name of event
900      * @param {DataObject|false} obj - dataobject action occured on.
901      * @param {String} any remarks
902      * @return {false|DB_DataObject} Event object.,
903      */
904     
905     function addEventOnce($act, $obj = false, $remarks = '') 
906     {
907         if (!empty(HTML_FlexyFramework::get()->Pman['disable_events'])) {
908             return;
909         }
910         $e = DB_DataObject::factory('Events');
911         $e->init($act,$obj,$remarks); 
912         if ($e->find(true)) {
913             return false;
914         }
915         return $this->addEvent($act, $obj, $remarks);
916     }
917     /**
918      * addEvent:
919      * Log an action.
920      * 
921      * @param {String} action  - group/name of event
922      * @param {DataObject|false} obj - dataobject action occured on.
923      * @param {String} any remarks
924      * @return {DB_DataObject} Event object.,
925      */
926     
927     function addEvent($act, $obj = false, $remarks = '') 
928     {
929         
930         if (!empty(HTML_FlexyFramework::get()->Pman['disable_events'])) {
931             return;
932         }
933         $au = $this->getAuthUser();
934        
935         $e = DB_DataObject::factory('Events');
936         $e->init($act,$obj,$remarks); 
937          
938         $e->event_when = date('Y-m-d H:i:s');
939         
940         $eid = $e->insert();
941         
942         // fixme - this should be in onInsert..
943         $wa = DB_DataObject::factory('core_watch');
944         if (method_exists($wa,'notifyEvent')) {
945             $wa->notifyEvent($e); // trigger any actions..
946         }
947         
948         
949         $e->onInsert(isset($_REQUEST) ? $_REQUEST : array() , $this);
950         
951        
952         return $e;
953         
954     }
955     // ------------------ DEPERCIATED ----------------------------
956      
957     // DEPRECITAED - use moduleslist
958     function modules()  { return $this->modulesList();  }
959     
960     // DEPRECIATED.. - use getAuthUser...
961     function staticGetAuthUser()  { $x = new Pman(); return $x->getAuthUser();  }
962      
963     
964     // DEPRICATED  USE Pman_Core_Mailer
965     
966     function emailTemplate($templateFile, $args)
967     {
968     
969         require_once 'Pman/Core/Mailer.php';
970         $r = new Pman_Core_Mailer(array(
971             'template'=>$templateFile,
972             'contents' => $args,
973             'page' => $this
974         ));
975         return $r->toData();
976          
977     }
978     // DEPRICATED - USE Pman_Core_Mailer 
979     // WHAT Part about DEPRICATED Does no one understand??
980     function sendTemplate($templateFile, $args)
981     {
982         require_once 'Pman/Core/Mailer.php';
983         $r = new Pman_Core_Mailer(array(
984             'template'=>$templateFile,
985             'contents' => array(),
986             'page' => $this
987         ));
988         return $r->send();
989         
990     
991     }
992 }