DataObjects/Events.php
[Pman.Core] / DataObjects / Events.php
1 <?php
2 /**
3  * Table Definition for Events
4  *
5  * objects can implement relatedWhere(), which should return
6  *    'tablename' => array of ids
7  *
8  * 
9  */
10 class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
11
12 class Pman_Core_DataObjects_Events extends DB_DataObject 
13 {
14     ###START_AUTOCODE
15     /* the code below is auto generated do not remove the above tag */
16
17     public $__table = 'Events';                          // table name
18     public $id;                              // int(11)  not_null primary_key auto_increment
19     public $person_name;                     // string(128)  
20     public $event_when;                      // datetime(19)  binary
21     public $action;                          // string(32)  
22     public $ipaddr;                          // string(16)  
23     public $on_id;                           // int(11)  
24     public $on_table;                        // string(64)  
25     public $person_id;                       // int(11)  
26     public $remarks;                         // blob(65535)  blob
27     public $person_table;                    // string(64)
28
29     /* the code above is auto generated do not remove the tag below */
30     ###END_AUTOCODE
31     
32     
33     
34     
35     //  ------------ROO HOOKS------------------------------------
36     function applyFilters($q, $au ,$roo)
37     {
38         $tn = $this->tableName();
39         // if not empty on_table
40         echo $this->tableName();
41         if(!empty($q['person_table'])){
42             $jt = DB_DataObject::factory($q['person_table']);
43
44             $et = DB_DataObject::factory($tn);
45             
46             if(!array_key_exists("{$jt->tableName()}_id", $this->tableColumns())){ // coz we have triiger on mysql...
47                 
48                 $keys = $jt->keys();
49             
50                 $this->_join = "LEFT JOIN {$jt->tableName()} AS join_person_id_id ON (join_person_id_id.{$keys[0]}=Events.person_id)";
51                 $this->selectAdd("(select count(*) from Events where Events.dup_id = evet.id) as cnt ");
52                 $this->selectAs($et,'%s','evet');
53
54                 $this->selectAs($jt, 'person_id_%s', 'join_person_id_id');
55
56                 if (method_exists($jt,'nameColumn')) {
57                     $this->selectAdd("join_person_id_id.{$jt->nameColumn()} as person_id_name");
58                 }
59
60                 if (method_exists($jt,'emailColumn')) {
61                     $this->selectAdd("join_person_id_id.{$jt->emailColumn()} as person_id_email");
62                 }
63                 
64             }
65         
66         } else {
67             
68             $person = $au->tableName(); //'Person';  -- projects may not use person as the auth table...
69             $cfg = HTML_FlexyFramework::get()->Pman;
70             if (!empty($cfg['authTable'])) {
71                 $person =$cfg['authTable'];
72             }
73             
74             $jt = DB_DataObject::factory($person);
75             $this->whereAdd("
76                     person_table  = '{$jt->tableName()}'
77                     OR
78                     person_table = ''
79                     OR person_table IS NULL"
80             ); // default to  our standard.. - unless otherwise requested..
81         }
82         
83         
84         if (!empty($q['query']['from'])) {
85             $dt = date('Y-m-d' , strtotime($q['query']['from']));
86             $this->whereAdd(" {$tn}.event_when >=  '$dt' ");
87         }
88         if (!empty($q['query']['to'])) {
89             $dt = date('Y-m-d' , strtotime($q['query']['to']));
90             $this->whereAdd(" {$tn}.event_when <=  '$dt' ");
91         }
92         /*
93         if (!empty($q['query']['grouped']) && $q['query']['grouped'] == 'gr') {
94             // grouped..
95             DB_DataObject::Debuglevel(1);
96             $this->groupBy('on_id');
97             $this->selectAdd('
98                 (SELECT count(id) FROM core_event_audit WHERE event_id = Events.id) as changed
99                 ');
100         }
101         */
102         
103         if (!$au->hasPerm("Admin.Admin_Tab", 'S')) {
104             //DB_DataObject::DebugLevel(1);
105             // they can only view their changes..
106             $this->whereAdd("($tn.person_id = {$au->id} OR $tn.person_id = 0)");
107 //            $this->person_id = $au->id;
108             
109         }
110         // _join = tablename,tablename...
111         
112         /// on_table=cohead
113         //   &_join=cohead
114         //   &_join_cols=cohead_number
115         //    &_columns=on_id_cohead_number,event_when << this is ignored at present.
116         // max(event_when) is not supported... by any query yet..
117         
118         if (isset($q['on_table']) && !strlen($q['on_table'])) {
119             // empty ontable queries.. these are valid..
120             $this->whereAdd("$tn.on_table = ''");
121         }
122       
123         if (isset($q['query']['person_sum'])) {
124             //DB_DataObject::debugLevel(1);
125             $this->_extra_cols = array('qty' );
126             $this->selectAdd("count($tn.id) as qty");
127             $this->selectAdd("count( distinct $tn.on_id) as uqty");
128             $this->whereAdd('LENGTH(join_person_id_id.name) > 0 ');
129             $this->groupBy('person_id,join_person_id_id.name,join_person_id_id.email');
130         }
131          if (isset($q['query']['table_sum'])) {
132             //DB_DataObject::debugLevel(1);
133             $this->_extra_cols = array('qty' , 'uqty');
134             $this->selectAdd("count($tn.id) as qty");
135             $this->selectAdd("count( distinct $tn.on_table, $tn.on_id) as uqty");
136             
137             $this->groupBy('on_table');
138         }
139          if (isset($q['query']['day_sum'])) {
140             //DB_DataObject::debugLevel(1);
141             $this->_extra_cols = array('qty' , 'uqty');
142             $this->selectAdd("DATE_FORMAT(event_when, '%Y-%m-%d') as on_day");
143             $this->selectAdd("count($tn.id) as qty");
144             $this->selectAdd("count( distinct $tn.on_id) as uqty");
145             
146             $this->groupBy('on_day');
147         }
148         
149         if (isset($q['_join'])) {
150             //DB_DataObject::DebugLevel(1);
151             $joins = explode(',',$q['_join']);
152             
153             $this->selectAdd(); // ???
154             $distinct = false;
155             
156             foreach($joins as $t) {
157                 $t = preg_replace('/[^a-z_]+/', '', $t); // protection.
158                 $x = DB_DataObject::Factory($t);
159                 if (!is_a($x,'DB_DataObject')) {
160                     continue;
161                 }
162                 $jtn = $x->tableName();
163                 $jk = array_shift($x->keys());
164                 $this->_join .= "
165                 
166                     LEFT JOIN {$jtn} as join_on_id_{$jtn} ON {$tn}.on_id = join_on_id_{$jtn}.{$jk}
167                         AND on_table = '{$jtn}'
168                 ";
169                 $keys = array_keys($x->tableColumns());
170                 if (isset($q['_join_cols'])) {
171                     $jcs = explode(',',$q['_join_cols'] );
172                     //DB_DataObject::DebugLevel(1);
173                     
174                     foreach($jcs as $jc) { 
175                         if (! in_array($jc, $keys)) {
176                             continue;
177                         }
178                         if ($distinct) { 
179                         
180                        
181                             $this->selectAdd( " join_on_id_{$jtn}.{$jc}   as on_id_{$jc} ");
182                         } else {
183                             $this->selectAdd( " distinct(join_on_id_{$jtn}.{$jc}  ) as on_id_{$jc} ");
184                             $distinct = true;
185                         }
186                         $this->groupBy("on_id_{$jc} ");
187                         $this->whereAdd("join_on_id_{$jtn}.{$jc} IS NOT NULL");
188                     }
189                     $this->selectAdd( "MAX(events.event_when) as event_when");
190                     $this->orderBy('event_when DESC');
191                    // $this->selectAs(array($q['_join_cols']) , 'on_id_%s', "join_on_id_{$jtn}");
192                 } else { 
193                     $this->selectAs($x, 'on_id_%s', "join_on_id_{$jtn}");
194                 }
195             }
196                  
197             
198         }
199         
200         if (isset($q['_related_on_id']) && isset($q['_related_on_table'])) {
201             // example: sales order - has invoices,
202             ///DB_DataObject::DebugLevel(1);
203             $ev  =$this->factory('Events');
204             $ev->setFrom(array(
205                 'on_id' => $q['_related_on_id'],
206                 'on_table' => $q['_related_on_table'],
207                                ));
208             $obj = $ev->object();
209             
210             if (!$obj) {
211                 $roo->jerr("ontable is invalid");
212             }
213             if (!method_exists($obj,'relatedWhere')) {
214                 $roo->jerr( $q['_related_on_table'] . " Does not have method relatedWhere :" .
215                            implode(',', get_class_methods($obj)));
216             }
217             if ($obj && method_exists($obj,'relatedWhere')) {
218                 $ar = $obj->relatedWhere();
219                 $tn = $this->tableName();
220                 
221                 $w = array();
222                 $w[] = "( {$tn}.on_table = '" .
223                         $this->escape($q['_related_on_table']) .
224                         "' AND {$tn}.on_id = ". ((int)  $q['_related_on_id']) .
225                     ")";
226                 
227                 
228                 foreach($ar as $k=>$v) {
229                     if (empty($v)) {
230                         continue;
231                     }                
232                      $w[] = "( {$tn}.on_table = '$k' AND {$tn}.on_id IN (". implode(',', $v). "))";
233                     
234                 }
235                 $this->whereAdd(implode(' OR ' , $w));
236             }
237             
238             
239             
240             
241             
242         }
243         // since roo does not support autojoin yet..
244         if (!isset($q['_distinct'])) {
245             //$this->autoJoinExtra();
246         }
247         
248         if(!empty($q['query']['action'])) {
249             $act = $this->escape($q['query']['action']);
250             $this->whereAdd("Events.action LIKE '%{$act}%'");
251         }
252         
253         if(!empty($q['query']['on_table'])) {
254             $tnb = $this->escape($q['query']['on_table']);
255             $this->whereAdd("Events.on_table LIKE '%{$tnb}%'");
256         } 
257         
258     }
259       
260     
261     
262     /**
263      * check who is trying to access this. false == access denied..
264      * @return {boolean} true if access is allowed.
265      */
266     function checkPerm($lvl, $au) 
267     {
268         if ($lvl == 'S') {
269             return true;
270         }
271         // listing is controleed by applyfilters..
272         return $au->hasPerm("Admin.Admin_Tab", 'S');
273     }
274     /**
275      * object :
276      * return the object that this relates to.
277      * 
278      * @return {DB_DataObject} related object
279      */
280     function object()
281     {
282         $o = DB_DataObject::factory($this->on_table);
283         $o->get($this->on_id);
284         return $o;
285         
286     }
287     
288     
289     /**
290      * init:
291      * Initialize an event - ready to insert..
292      * 
293      * @param {String} action  - group/name of event
294      * @param {DataObject|false} obj - dataobject action occured on.
295      * @param {String} any remarks 
296      */
297     
298     function init($act, $obj, $remarks)
299     {
300         $ff = HTML_FlexyFramework::get();
301         $pg = $ff->page;
302         $au = $pg->getAuthUser();
303         
304         if ($ff->cli) { // && empty($au) && isset($obj->person_id)) {
305             $au = false;
306            // $au = DB_DataObject::Factory('Person'); // not always a person..
307            // $au->get($obj->person_id);
308         } 
309           
310         $this->person_name = $au && !empty($au->name) ? $au->name : '';
311         if (empty($au) || (isset($au->id) && empty($au->id))) {
312             // not authenticated - and a standard id based object
313             $this->person_id = 0;
314         } else {
315             $col = $au->tableName() == "Person" ? 'person_id' : $au->tableName() . '_id';
316             // does $col exist?
317             $cols = $this->tableColumns();
318             $col = isset($cols[$col]) ? $col : 'person_id'; // for BC.... - revert to using person_id
319             $this->{$col} = $au->pid();
320             //$this->person_id = $au ? (!empty($au->id) ? $au->id : $au->pid()) : -1;
321         }
322         $this->person_table = $au ? $au->tableName() : '';
323         $this->ipaddr = isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : 'cli';
324         if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
325             $this->ipaddr = $_SERVER['HTTP_X_FORWARDED_FOR'];
326         }
327         
328         $this->action = $act;
329         $this->on_table = $obj ? $obj->tableName() : '';
330         $pk = $obj ? $obj->keys()  : false;
331         $this->on_id  = $obj && $pk ? $obj->{$pk[0]}: 0;
332         $rem  = array();
333         // should this really go in remarks? - 
334         if ($obj && method_exists($obj,'toEventString')) {
335             if($obj->toEventString() !== false){
336                 $rem[] = $obj->toEventString();
337             }
338         }
339         $rem[] = $remarks;
340         $this->remarks = implode(' : ', $rem);
341     }
342     
343     /**
344      * Generate an audit for this field.
345      *
346      * @param {DB_DataObject} new data
347      * @param {DB_DataObject} old data
348      * 
349      * @return {int} number of entries logged.
350      */
351     
352     function audit($new, $old = false)
353     {
354         if ($old == $new) {
355             return 0; // they are the same...
356         }
357          
358         $ret = 0;
359         foreach(array_keys($new->tableColumns()) as $k) {
360             // should we JSON serialize this?
361             $n = empty($new->$k) ? '' : $new->$k;
362             $o = empty($old->$k) || empty($old->$k) ? '' : $old->$k;
363             if ($n == $o) {
364                 continue;
365             }
366             $this->auditField($k, $o, $n, $old);
367             $ret++;
368         }
369         return $ret;
370     }
371     /**
372      * Record an audited change, in theory so we can audit data that is not just
373      * database Fields...
374      *
375      * @param {string} $name    table field anme
376      * @param {mixed} $ov  old value
377      * @param {mixed} $onv  new value
378      * @param {mixed} $old  old object (false if we are creating..)
379      */
380     function auditField($name, $ov, $nv, $old=false )
381     {
382         // hack..
383         if (is_object($nv)) {
384             return;
385         
386         }
387         
388         $x = DB_DataObject::factory('core_event_audit');
389         $x->setFrom(array(
390             'event_id' => $this->id,
391             'name' => $name,
392             'old_audit_id' => $old ? $x->findLast($this, $name) : 0,
393             'newvalue' => $nv
394
395         ));
396         $x->insert();
397     
398     }
399     
400     function beforeInsert($request,$roo)
401     {
402         if(empty($this->event_when)){
403             $this->event_when = $this->sqlValue("NOW()");
404         }
405         
406         if(empty($this->person_id)){
407             $this->person_id = $roo->authUser->id;
408             $this->person_name = $roo->authUser->name;
409             $this->person_table = $roo->authUser->tableName();
410         }
411         
412         if(empty($this->ipaddr)){
413             $this->ipaddr = isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : 'cli';
414             if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
415                 $this->ipaddr = $_SERVER['HTTP_X_FORWARDED_FOR'];
416             }
417         }
418     }
419     
420     function beforeUpdate($old, $request,$roo)
421     {
422         if(!empty($request['_restore'])){
423             $this->restore($roo);
424         }
425     }
426     
427     function onInsert($request,$roo)
428     {
429         $this->writeEventLog();
430     }
431     
432     static $deleted = array();
433     
434     
435     // log deleting of a record so that it can be written later..
436     function logDeletedRecord($obj = false)
437     {
438         if (is_array($obj)) {
439             $ret = false;
440             foreach($obj as $o) {
441                 $aret = $this->logDeletedRecord($o);
442                 $ret = $ret ? $ret : $aret;
443             }
444             return true;
445         }
446         
447         if(empty($obj) || !is_a($obj, 'DB_DataObject')){
448             return false;
449         }
450         
451         
452         $del = $obj->toArray();
453         $del['_table'] = $obj->tableName();
454         
455         self::$deleted[] = $del;
456         return true;
457     }
458     static $extra_data = false;
459     
460     static function writeEventLogExtra($data) {
461         self::$extra_data = $data;
462     }
463     
464     function logDir()
465     {
466         $ff  = HTML_FlexyFramework::get();
467         if (function_exists('posix_getpwuid')) {
468             $uinfo = posix_getpwuid( posix_getuid () ); 
469          
470             $user = $uinfo['name'];
471         } else {
472             $user = getenv('USERNAME'); // windows.
473         }
474         
475         // DEPRICATED...
476         if (!empty($ff->Pman['event_log_dir'])) {
477             return $ff->Pman['event_log_dir'] . '/'.$user;
478         }
479         if (!empty($ff->Pman['storedir'])) {
480             return $ff->Pman['storedir'] .'/Events/'.$user;
481         
482         }
483         return false;
484     }
485     
486     
487     
488     function writeEventLog($extra_data  = false)
489     {
490         $logdir = $this->logDir();
491         if (!$logdir) {
492             return false;
493         }
494         
495          
496         //print_r($this);
497         $file = $logdir.  date('/Y/m/d/'). $this->id . ".json";
498         if (!file_exists(dirname($file))) {
499             
500             @mkdir(dirname($file),0700,true); // this might fail if it does not have correct permissions..
501             if (!file_exists(dirname($file))) {
502                 die("could not create $file - permissons are not correct"); // fatal, otherwise we loop!?
503             }
504             
505         }
506         
507         // Remove all the password from logs...
508         $p =  empty($_POST) ? array() : $_POST;
509         foreach(array('passwd', 'password','passwd1',  'passwd2','password1', 'password2') as $rm) {
510             if (isset($p[$rm])) {
511                 $p[$rm] = '******';
512             }
513         }
514         
515         
516         $i=0;
517         $files = array();
518          
519         $i = 0;
520         foreach ($_FILES as $k=>$f){
521             // does not handle any other file[] arrary very well..
522             if (empty($f['tmp_name']) || !file_exists($f['tmp_name'])) {
523                 continue;
524             }
525             $i++;
526             $files[$k] = $f;
527             
528              
529             $files[$k]['tmp_name'] =  $this->id . '-'. $i;
530             $nf = $logdir .   date('/Y/m/d/').   $files[$k]['tmp_name']; 
531             if (!copy($f['tmp_name'], $nf)) {
532                 print_r("failed to copy {$f['tmp_name']}...\n");
533             }
534         }
535         $out = array(
536             'REQUEST_URI' => empty($_SERVER['REQUEST_URI']) ? 'cli' : $_SERVER['REQUEST_URI'],
537             'HTTP_USER_AGENT' => empty($_SERVER['HTTP_USER_AGENT']) ? '' : $_SERVER['HTTP_USER_AGENT'],
538             'GET' => empty($_GET) ? array() : $_GET,
539             'POST' =>$p,
540             'FILES' => $files,
541             
542         );
543         if (!empty(self::$deleted)) {
544             $out['DELETED_DATAOBJECTS'] = self::$deleted;
545         }
546         if ($extra_data !== false) {
547             $out['EXTRA'] = $extra_data;
548         }
549         if ( self::$extra_data !== false) {
550             $out['EXTRA_DATA'] =  self::$extra_data;
551         }
552         
553         file_put_contents($file, json_encode($out));
554         
555         
556     }
557     
558     function toRooArray( $q)
559     {
560         $ret = $this->toArray();
561         
562         // fill toEventString.
563         if (!empty($q['_with_obj_summary']) && !empty($this->on_id)) {
564             $obj = $this->object();
565               
566             if ($obj && $obj->pid() && method_exists($obj,'toEventString')) {
567                 $es = $obj->toEventString();
568                 
569                 if (empty($this->remarks) || strpos($this->remarks, $es) < 0) {
570                     $ret['remarks'] = $es . ' ' . $this->remarks;
571                 }
572             } else if (empty($this->remarks)){
573                 $ret['remarks'] = "DELETED";
574                 
575             }
576         }
577         //print_r($ret);
578         return $ret;
579         
580     }
581     
582     function toRooSingleArray($au, $q)
583     {
584         $ret = $this->toArray();
585         
586          
587         
588         if(empty($q['_retrieve_source'])){
589             return $ret;
590         }
591         
592         $file = $this->retrieveEventLog();
593         
594         if(!$file){
595             return "No records?!";
596         }
597         
598         $source = json_decode(file_get_contents($file));
599         
600         return $source;
601     }
602     
603     function retrieveEventLog()
604     {
605         
606         $logdir = $this->logDir();
607         if (!$logdir) {
608             return false;
609          
610         }
611         
612         $date = date('/Y/m/d/', strtotime($this->event_when));
613         
614         $file = $logdir. $date. $this->id . ".json";
615         if (!file_exists(dirname($file))) {
616             return false;
617         }
618         
619         return $file;
620     }
621     
622     function restore($roo)
623     {
624         $file = $this->retrieveEventLog();
625         
626         if(empty($file) || !file_exists($file)){
627             $roo->jerr('Could not retrieve the event log file');
628         }
629         
630         $log = json_decode(file_get_contents($file), true);
631         
632         if(empty($log['POST']) || empty($log['POST']['_delete']) || empty($log['DELETED_DATAOBJECTS'])){
633             $roo->jerr('Invalid url');
634         }
635         
636         $restored = array();
637         
638         foreach ($log['DELETED_DATAOBJECTS'] as $d){
639             if(
640                     empty($d['id']) || 
641                     empty($d['_table']) || 
642                     (
643                             !empty($restored[$d['_table']]) && 
644                             in_array($d['id'], $restored[$d['_table']])
645                     )
646             ){
647                 continue;
648             }
649             
650             if(!isset($restored[$d['_table']])){
651                 $restored[$d['_table']] = array();
652             }
653             
654             $restored[$d['_table']][] = $d['id'];
655             
656             $table = DB_DataObject::factory($d['_table']);
657             
658             if (!is_a($table,'DB_DataObject')) {
659                 continue;
660             }
661             
662             unset($d['_table']);
663             
664             $table->setFrom($d);
665             
666             /*
667              * need to use the old id
668              */
669             $table->id = $d['id'];
670             
671             $table->sequenceKey(false,false);
672             
673             $table->insert();
674             
675             if($table->tableName() == 'crm_mailing_list_member'){
676                 $ml = DB_DataObject::factory('crm_mailing_list');
677                 if(!$ml->get($table->mailing_list_id)){
678                     continue;
679                 }
680
681                 $mlm = DB_DataObject::factory('crm_mailing_list_member');
682                 $mlm->setFrom(array(
683                     'mailing_list_id' => $table->mailing_list_id,
684                     'is_active' => 1
685                 ));
686
687                 $o = clone($ml);
688                 $ml->no_members = $mlm->count();
689                 $ml->update($o);
690             }
691         }
692         
693         $roo->jok('RESTORE');
694     }
695     function selectAddPersonEmail()
696     {
697         $this->selectAdd('join_person_id_id.email as email');
698         
699     }
700 }