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