3 * Table Definition for mtrack_change
5 class_exists('DB_DataObject') ? '' : require_once 'DB/DataObject.php';
7 class Pman_MTrack_DataObjects_Mtrack_change extends DB_DataObject
10 /* the code below is auto generated do not remove the above tag */
12 public $__table = 'mtrack_change'; // table name
13 public $id; // int(11) not_null primary_key auto_increment
14 public $person_id; // int(11)
15 public $ontable; // string(128)
16 public $onid; // int(11) not_null
17 public $changedate; // datetime(19) not_null binary
18 public $reason; // blob(65535) blob
21 /* the code above is auto generated do not remove the tag below */
25 function objectCached()
28 if (empty($this->ontable) || empty($this->onid)) {
32 if (isset($cache[$this->ontable.':'. $this->onid])) {
33 $cache[$this->ontable.':'. $this->onid];
35 $o = DB_DataObject::factory($this->ontable);
38 $cache[$this->ontable.':'. $this->onid] = $o;
44 //checkPerm('S'/'E'/'A', $authuser) - can
45 function checkPerm($perm, $au)
48 if ($au && $au->company()->comptype == 'OWNER') {
49 // owner can do anything..????
53 if ($perm == 'E' || $perm == 'D' ) { // Edit and delete ..not allowed..
57 if (!$au && $perm != 'S') {
58 // non-authenticated users can only list stuff..
63 //DB_DataObject::debugLevel(1);
64 $obj = $this->objectCached();
68 if (!method_exists($obj, 'checkPerm')) {
73 return $obj->checkPerm($perm, $au);
80 function applyFilters($q, $au, $roo)
84 if (!empty($q['timeline'])) {
85 return $this->applyFilterTimeline($q,$au, $roo);
88 if (!empty($q['_is_update_request'])) {
95 $obj = $this->objectCached();
98 // global searching on non-object...
99 // needed for timelime, but not ready yet...
102 $this->whereAdd('1=0');
106 if (!method_exists($obj, 'checkPerm')) {
107 $this->whereAdd('1=0');
111 if (!$au || (!$obj->checkPerm('S', $au) || !$obj->checkPerm('E', $au)) ) {
112 $this->whereAdd('1=0');
120 // this is the query for timelines..
121 function applyFilterTimeline($q, $au, $roo)
125 $start = empty($q['on_date']) ? date('Y-m-d') :
126 date('Y-m-d', strtotime($q['on_date']));
129 //DB_DataObject::debugLevel(1);
132 $pd = DB_DataObject::factory('ProjectDirectory');
133 $pd->whereAdd("role != ''");
134 $pids = $pd->projects($au);
136 $roo->jerr("User is not a member of any projects");
139 if (!empty($q['project_id'])) {
140 if (!in_array($q['project_id'], $pids)) {
141 $roo->jerr("Selected project not in your permitted project list.");
143 $pids = array($q['project_id']);
146 $pids = implode(',', $pids);
150 ( ontable='mtrack_ticket' AND
151 onid IN (SELECT id FROM mtrack_ticket where project_id IN ( $pids ))
154 ( ontable='mtrack_repos' AND
155 onid IN (SELECT id FROM mtrack_repos where project_id IN ( $pids ))
158 $this->orderBy('changedate DESC');
160 if (!empty($q['viewtype']) && $q['viewtype'] == 'summary') {
161 //DB_DataObject::debugLevel(1);
164 changedate >= '$start 00:00:00'
166 changedate < '$start 00:00:00' + INTERVAL 1 DAY
171 //$this->joinAdd(DB_DataObject::factory('Person'), 'LEFT');
173 DATE_FORMAT(changedate, '%Y-%m-%d') as changeday,
174 join_person_id_id.id as person_id,
175 join_person_id_id.name as person_name,
176 Projects.id as project_id,
177 mtrack_repos.shortname as repo_name,
178 mtrack_repos.id as repo_id,
180 Projects.code as project_code,
182 COUNT(mtrack_change.id) as nchanges
185 LEFT JOIN Projects ON
186 Projects.id = IF (ontable='mtrack_repos',
187 (SELECT project_id FROM mtrack_repos where onid = mtrack_repos.id ),
188 (SELECT project_id FROM mtrack_ticket where onid = mtrack_ticket.id )
190 LEFT JOIN mtrack_repos ON
191 mtrack_repos.id = IF (ontable='mtrack_repos', onid, 0)
196 $this->groupBy("changeday,
197 join_person_id_id.id,
198 join_person_id_id.name,
201 mtrack_repos.shortname,
203 $this->orderBy('project_code asc, repo_name ASC, person_name asc');
205 $roo->jdata($this->fetchAll(false,false,'toArray'));
209 $this->whereAdd("changedate >= '$start_day 00:00:00' AND
210 changedate < '$start_day 00:00:00' + INTERVAL 1 DAY");
212 //DB_DataObject::debugLevel(1);
218 // do not accept use input for this..
219 function autoJoinObject($tbl)
223 $d = DB_DataObject::Factory($tbl);
224 $ji = $d->autoJoin();
225 //echo '<PRE>';print_R($ji);
227 foreach($ji['join_names'] as $cname=>$fname) {
228 $this->selectAdd($fname . ' as ontable_id_' . $cname );
231 //$this->selectAdd($d->_query['data_select']); -- this will cause the same dataIndex...
233 LEFT JOIN {$d->tableName()} ON {$this->tableName()}.onid = {$d->tableName()}.id
236 $this->selectAs($d, 'ontable_%s');
247 static $cache = array();
248 if (isset($cache[$this->person_id])) {
249 return $cache[$this->person_id];
251 $p = DB_DataObject::factory('core_person');
252 $p->get($this->person_id);
253 $cache[$this->person_id] = $p;
258 function getCommit($repo, $hash, $runhistory=true)
260 $this->object = $repo->toIdString(); // should be repo:1
262 if ($this->find(true)) {
267 throw new Exception("Can not find revision");
269 $this->refreshHistory($repo);
270 if ( $this->find(true)) {
273 }; /// yes I know we say you should not run this twice...
279 *@param {TrackCommitHookChangeEvent} ce the change event..
281 function createFromCommit($ce, $checker, $ticket = false)
283 $rev_ar = explode(',', $ce->rev);
284 $rev = substr(array_pop($rev_ar), 0, -1);
287 $tc->ontable = 'mtrack_repos';
288 $tc->onid = $checker->repo->id;
290 $tc->cgtype = 'COMMIT';
291 $tc->branch = $ce->branch;
292 if ($tc->count()) { // if we have already tracked this..
304 $tc->ontable = $ticket->tableName();
305 $tc->onid = $ticket->id;
306 $tc->changedate = date('Y-m-d H:i:s', $ce->ctime);
307 $tc->reason = $ce->changelog;
308 $tc->person_id = $ce->changeby_id;
310 $tcid = $tc->insert();
315 $this->ontable = 'mtrack_repos';
316 $this->onid = $checker->repo->id;
317 $this->changedate = date('Y-m-d H:i:s', $ce->ctime);
318 $this->reason = $ce->changelog;
319 $this->person_id = $ce->changeby_id;
320 $this->branch = $ce->branch;
324 // add all the chanedge files..
325 foreach($ce->fileActions as $f => $cg) {
327 $au = DB_DataObject::factory('mtrack_change_audit');
328 $au->change_id = $this->id;
329 $au->ticket_change_id = $tcid;
330 $au->fieldname = $rev;
331 $au->action = 'commit-'.$cg;
336 $this->onInsert(array(), HTML_FlexyFramework::get()->page);
338 // finnaly trigger watchers
340 if (!$ticket && preg_match('/_T([0-9]+)_/', $ce->branch, $matches)) {
341 $ticket = DB_DataObject::factory('mtrack_ticket');
342 if (!$ticket->get($matches[1])) {
347 $ts = DB_DataObject::Factory('cash_invoice_entry');
348 $ts->updateFromCommit($ce, $ticket);
356 // audit should contain files changed..
359 function onInsert($request,$roo)
362 // for a commit ? - ontable = repos, onid = the repo id...
363 // for a change... ontable - will be the ticked, and onid will be the ticket id..
365 $obj = $this->objectCached();
367 if ($obj->tableName() == 'mtrack_ticket') {
368 $obj = $obj->project();
371 $target = empty($this->branch) ? $obj : $obj->branchObject($this->branch);
375 $core_watch = DB_DataObject::Factory('core_watch');
379 "medium='ENDOFDAYMAIL'",
381 date('Y-m-d 23:59:59'),
382 $target->tableName(),
390 * scans repo history and imports it... ??? does not know about branches yet...
392 function refreshHistory($repo)
394 $c = DB_DataObject::factory('mtrack_changes');
395 $c->object = $repo->toIdString();
396 $c->orderBy('changedate DESC');
397 $c->whereAdd("rev != ''");
399 if ($c->find(true)) {
402 // history returns an array of scmEvents... - should actually return an array of this object...
403 $recs = $repo->history('', null, $last ? 'rev' : null, $last ? $last :null);
405 foreach($recs as $r) {
406 // see if we have a copy of it already.
407 $c = DB_DataObject::factory('mtrack_change');
408 $c->object = $repo->toIdString();
409 $c->changedate != $r->ctime;
411 $c->whereAdd("rev != ''");
412 if (!$c->find(true)) {
413 // not found, create a new one..
418 $cr->reason = $r->changelog;
419 $cr->who = $r->changeby;
421 foreach($cr->files as $f) {
422 // we could do with adding 'X' lines changed on this
423 $ca = DB_DataObject::factory('change_audit');
425 $ca->fieldname = $cr->object. ':file';
426 $ca->action = $f->status . ($f->added ? ' +' . $f->added : '') . ($f->removed ? ' -' . $f->removed : '') ;
427 $ca->value = $f->name;
438 function beginChange($object, $reason = '', $when = null)
440 // $db->beginTransaction();
441 //$this->query('BEGIN');
442 $pg = HTML_FlexyFramework::get()->page;
445 $this->person_id = $au->id;
446 $this->ontable = $object->tableName(); // string(128)
447 $this->onid = $object->id; // should use keys( really..)
448 $this->reason = $reason;
449 //$d = date_create("@" . (empty($when) ? time() : $when), new DateTimeZone('UTC'));
450 $this->changedate = date('Y-m-d H:i:s'); // everythign at server time..
451 //$d->format('Y-m-d\TH:i:s.u\Z');
452 $this->cgtype = $reason == 'Changed' ? 'CHANGE' : 'COMMENT';
454 $this->onInsert(array(), $pg);
460 if ($this->count == 0) {
461 // throw new Exception("no changes were made as part of this changeset");
463 if (self::$use_txn) {
464 //$this->query('COMMIT');
469 function addentry($fieldname, $action, $old, $value = null)
472 // final sanity check..
473 $o = DB_DataObject::factory($this->ontable);
474 $info = $o->tableColumns();
475 $far = explode(':',$fieldname);
476 $col = array_pop($far);
477 if (!isset($info[$col])) {
482 if ($info[$col] & (defined('DB_DATAOBJECT_INT') ? DB_DATAOBJECT_INT : PDO_DataObject::INT)) {
483 if (((int) $old) == ((int) $value)) {
490 $ca = DB_DataObject::factory('mtrack_change_audit');
492 'change_id' => $this->id,
493 'fieldname' => $fieldname,
506 * add('xxx:yyy:zzz' , new , old)
507 * add('xxx:yyy', new_do, old_do) // two dataobjects.. (will diff the two..
508 * add($new_do, $old_do)
512 function add($fieldname, $new, $old = false)
514 //print_r(array("ADD", $fieldname, $new, $old));
515 //echo "check: $fieldname ($old) => ($new)\n";
517 if (is_object($fieldname)) {
518 return $this->add($this->ontable.':'. $this->onid , $fieldname, $new );
520 if (is_object($new)) {
521 // should check keys() - so it does not log primary key addition.
523 $cols = array_keys($new->tableColumns());
524 $keys = $new->keys();
525 $links = $new->links();
527 foreach($cols as $k) {
528 if (in_array($k, $keys)) {
531 $alinks = isset($links[$k]) ? explode(':', $links[$k]) : false;
532 if ($alinks && $this->tablename() == array_shift($alinks)) {
535 if (!$old && !isset($new->{$k})) {
539 $ret += $this->add($fieldname .':'. $k, $new->{$k}, !$old ? '' : $old->{$k});
548 if ($old !== false) {
549 return $this->addentry($fieldname, 'set', $old, $new);
552 if ($new === false) {
553 return $this->addentry($fieldname, 'deleted', $old, $new);
556 return $this->addentry($fieldname, 'changed', $old, $new);
565 function cachedAudit()
567 static $cache = array();
569 if (!isset($cache[$this->id])) {
570 $cache[$this->id]= $this->audit();
572 return $cache[$this->id];
574 function cachedAuditToJSONArray()
577 $ar = $this->cachedAudit();
583 $add = $a->toJSONArray($this);
594 function relatedCommits()
596 if (empty($this->rev)) {
599 // occurs on a ticket... when listing...
600 $mc = DB_DataObject::Factory('mtrack_change');
601 $mc->rev = $this->rev;
602 $mc->ontable = 'mtrack_repos';
603 if (!$mc->find(true)) {
606 // got the repo.. and the commit..
608 $repo = $mc->objectCached();
610 return $repo->historyToSummary(
611 $repo->impl()->history('.', 1, 'rev', $this->rev),
623 $a = DB_DataObject::Factory('mtrack_change_audit');
625 {$a->tableName()}.change_id = {$this->id} OR
626 {$a->tableName()}.ticket_change_id = {$this->id}
628 // var_dump($a->find());exit;
630 return $a->fetchAll();
633 function changesSince($object,$since)
635 $q = DB_DataObject::factory('mtrack_change');
636 $q->onid = $object->id;
637 $q->ontable = $object->tableName();
638 $q->whereAdd("changedate > '$since'");
639 $q->orderBy('changedate ASC');
641 // we are going to end up with a list of objects that have changed.
642 // eg. a ticket or a repo..
644 return $q->fetchAll();
650 function cachedAuditToString()
654 $ar = $this->cachedAudit();
655 foreach($ar as $audit) {
656 $add = $audit->toAuditString($this);
657 if ($add === false) {
663 return implode("\n",$body);
666 function toRooArray()
668 $ret = $this->toArray();
669 $ret['audit'] = $this->cachedAuditToJSONArray();
670 $ret['commit'] = $this->relatedCommits();
676 function beforeInsert($req, $roo)
678 // originally this was blocked - we are going to try and use it now???
679 if (empty($roo->authUser)) {
680 $roo->jerr("Invalid user inserting");
682 $this->person_id = $roo->authUser->id;
685 $obj = $this->objectCached();
687 if (!$obj || !$obj->checkPerm('E', $roo->authUser)) {
688 $roo->jerr("Invalid object / permission denied");
691 $this->changedate = $this->sqlValue('NOW()');
694 function beforeUpdate($old,$req,$roo)
696 $roo->jerr("update not allowed by user interface.");
701 function changedate($format)
703 return date($format, strtotime($this->changedate));
705 function postListFilter($data, $authUser, $q)
707 if (empty($q['ontable']) || empty($q['onid']) || $q['ontable'] != 'mtrack_ticket') {
710 //DB_DataObject::debugLevel(1);
711 // look up in the accounting system what time was spent on the ticket..
712 $ie = DB_DataObject::factory('cash_invoice_entry');
713 $ie->ticket_id = $q['onid'];
714 $ie->orderBy('entered_dt ASC'); // doesnt matter really - we will sort it..
718 cash_invoice_entry.id * -1 as id,
719 staff_id as person_id,
720 join_staff_id_id.name as person_id_name,
721 entered_dt as changedate,
722 'TIMESHEET' as cgtype ,
723 CONCAT(qtyvalue , ' Hours worked: ', cash_invoice_entry.description) as reason,
727 $hours = $ie->fetchAll(false,false,'toArray');
729 $ret = array_merge($data , $hours);
731 usort($ret, function ($a,$b) use($q) {
732 $aa = $a['changedate'];
733 $bb = $b['changedate'];
737 if ($q['dir'] == 'ASC') {
738 return strtotime($aa) < strtotime($bb) ? -1 : 1;
740 return strtotime($aa) > strtotime($bb) ? -1 : 1;
750 function sendTelegram()
752 if ($this->ontable != 'mtrack_ticket') {
758 require_once 'Net/Telegram.php';
759 $tg = new Net_Telegram(HTML_FlexyFramework::get()->Pman_Telegram['token']);
761 $t = $this->objectCached();
763 foreach ($this->audit() as $a) {
764 $str[] = $a->toAuditString($this);
769 $d = DB_DataObject::factory('core_person');
770 $d->whereAddIn('id', array($t->created_person_id, $t->developer_id), 'int');
771 $d->whereAdd('telegram_id > 0');
772 $sendto = $d->fetchAll('id','telegram_id');
774 // creator //created_person_id
775 // assigned to developer_id
776 // exclude whoever modfiied it? (disable for testing.)
777 foreach($sendto as $pid => $tid) {
778 if ($this->person_id == $pid) {
781 $res = $tg->factory('SendMessage',array(
783 'parse_mode' => 'MarkdownV2',
784 'text' => "/ticket@{$this->onid} *". $tg->escape("[{$t->project_id_name}]] {$t->summary}") . "*\n\n".
785 "{$this->cgtype} by ". $tg->escape($this->person()->name) . "\n\n" . $tg->escape(implode("\n", $str))