3 require_once 'MTrack/DB.php';
4 require_once 'MTrack/Config.php';
5 require_once 'MTrack/Component.php';
6 require_once 'MTrack/Wiki.php';
8 class MTrack_DataObject_Event {
10 var $effort = array();
14 static function fetchRange($issue, $start =0, $limit=10)
21 'select * from changes where object = ?
22 order by changedate asc LIMIT ?, ?',
23 "ticket:{$issue->tid}",$start, $limit);
25 // limit will not really work due to the later merging..
27 'select * from changes where object = ?
28 order by changedate asc',
29 "ticket:{$issue->tid}");
31 foreach ($q->fetchAll(PDO::FETCH_ASSOC) as $CS) {
32 $changes[$CS['cid']] = self::init($CS);
33 $changes[$CS['cid']]->issue = $issue;
37 $cidlist = join(',', $cids);
39 $q= MTrackDB::q("select * from change_audit where cid in ($cidlist)");
40 foreach ($q->fetchAll(PDO::FETCH_ASSOC) as $citem) {
42 $changes[$citem['cid']]->audit[] = $citem;
43 //$change_audit[$citem['cid']][] = $citem;
46 /* also need to include cases where the ticket was modified as a side-effect
47 * of other manipulations (such as milestones being closed and tickets being
48 * re-targeted. Such manipulations do not directly reference this ticket,
49 * and so do not need to be included in the effort_audit array that is
55 c.cid as cid, c.who as who,
56 c.object as object, c.changedate as changedate,
57 c.reason as reason, ca.fieldname as fieldname,
58 ca.action as action, ca.oldvalue as oldvalue,
61 left join changes c on (ca.cid = c.cid)
63 ca.cid not in ($cidlist) and
64 ca.fieldname like 'ticket:{$issue->tid}:%'
67 foreach ($q->fetchAll(PDO::FETCH_ASSOC) as $CS) {
69 if (!isset($changes[$CS['cid']])) {
70 $changes[$CS['cid']] = self::init($CS);
71 $changes[$CS['cid']]->issue = $issue;
74 $changes[$CS['cid']]->audit[] = $CS;
78 "select * from effort where cid in ($cidlist) and tid=?", $issue->tid)
79 ->fetchAll(PDO::FETCH_ASSOC) as $eff) {
80 $changes[$eff['cid']]->effort[]= $eff;
85 static function init($ar)
87 $r = new MTrack_DataObject_Event;
88 foreach($ar as $k=>$v) {
99 <div class="ticketevent">
100 <a class="pmark" href="#comment:3">#3 - COMMIT</a>
101 <a name="comment:3"><abbr title="Fri, Jan 28 2011 04:44" class="timeinterval">5 days ago</abbr>
103 <a title="www-data" href="http://www.apdealflow.com/mtrack/user.php?user=www-data" class="userlink">www-data</a>
105 Fix <a class="ticketlink" href="http://www.apdealflow.com/mtrack/ticket.php/21">#21</a>- deal table page control button not stable (new defect)
112 $link = HTML_FlexyFramework::get()->page->link;
114 $cid = "comment:{$this->cid}";
116 // tidied up by jquery..
117 $timestamp = $link->date($this->changedate, false);
122 // default is that something changed..
128 $comment_fields = array();
130 foreach ($this->audit as $citem) {
134 $ar = explode(':', $citem['fieldname'], 3);
135 if (count($ar) != 3) {
138 list($tbl,,$field) = $ar;
140 if ($tbl != 'ticket') {
141 // can get here if we created a new keyword, for example
148 $comments[] = $citem['value'];
149 $type = 'Comment added';
150 $comment_title = array_shift(explode("\n", $citem['value']));
159 $comment_fields[] = $field;
160 $ar = MTrackComponent::loadByIds($citem['value']);
161 $ar = array_map( function($e) { return $e->toHtml(); }, $ar);
162 $citem['value'] = join(', ', $ar);
168 $comment_fields[] = $field;
169 $citem['value'] = $this->get_milestones_list($citem['value']);
175 $comment_fields[] = $field;
176 $ar = MTrackKeyword::loadByIds($citem['value']);
177 $ar = array_map( function($e) { return $e->toHtml(); }, $ar);
178 $citem['value'] = join(', ', $ar);
182 $comment_fields[] = $field;
183 if ($citem['value'] !== null) {
184 $citem['value'] += 0;
186 if ($citem['oldvalue'] !== null) {
187 $citem['oldvalue'] += 0;
192 $comment_fields[] = $field;
193 if ($field[0] == '@') {
194 $main = isset($pseudo_fields[$field]) ? $pseudo_fields[$field] : '';
195 $field = substr($field, 1, -1);
197 $main = $this->issue->$field;
203 require_once 'MTrack/Ticket_CustomFields.php';
204 $f = MTrackTicket_CustomFields::getInstance()->fieldByName($field);
209 $label = htmlentities($f->label, ENT_QUOTES, 'utf-8');
211 if ($field == 'attachment' && strlen($citem['oldvalue'])) {
212 $label = "Attachment: $citem[oldvalue]";
214 $label = ucfirst($field);
218 if ($citem['oldvalue'] == null) {
219 /* don't bother printing out a set if this is the initial thing
220 * and if the field values are currently the same */
222 if ($main != $citem['value'] || $this->cid != 'top') {
224 /* Special case for description; since it is multi-line and often
225 * very large, render it as a diff against the current ticket
226 * description field */
227 if ($field == 'description') {
228 if ($this->issue->description == $citem['value']) {
229 $comment_body .= "<b>Description</b>: no longer empty; see above<br>";
233 $initial_lines = count(explode("\n", $this->issue->description));
234 $diff = $this->diff_strings($this->issue->description, $citem['value']);
237 foreach (explode("\n", $diff) as $line) {
238 if (!strlen($line)) continue;
239 if ($line[0] == '-') {
241 } else if ($line[0] == '+') {
245 if (abs($diff_add - $diff_rem) > $initial_lines / 2) {
246 $comment_body .= "<b>initial $label</b><br>" .
247 MTrack_Wiki::format_to_html($citem['value']);
249 $diff = $this->collapse_diff($diff);
250 $comment_body .= "<b>initial $label</b> (diff to above):<br>$diff\n";
253 $comment_body .= "<b>$label</b> $citem[value]<br>\n";
259 if ($citem['action'] == 'changed') {
260 $lines = explode("\n", $citem['value'], 3);
261 if (count($lines) >= 2) {
262 $diff = $this->diff_strings($citem['oldvalue'], $citem['value']);
263 $diff = $this->collapse_diff($diff);
264 $comment_body .= "<b>$label</b> $citem[action]\n$diff\n";
266 $comment_body .= "<b>$label</b> $citem[action] to $citem[value]<br>\n";
271 $comment_body .= "<b>$label</b> $citem[action]<br>\n";
275 $commit_info = array();
276 if ($comment_title &&
277 preg_match('/\(In \[changeset:([^,]+),([a-z0-9]+)\]\)(.*)$/i', $comment_title, $commit_info)) {
281 $comment_title = '<a class="changesetlink" href="'. $GLOBALS['ABSWEB'] . 'changeset.php/'.
282 $commit_info[1].'/'.$commit_info[2]. '">[' . $commit_info[2] . ']</a>'.$commit_info[3];
286 if ($this->cid == $this->issue->created) {
288 $comment_title = 'Issue Created';
296 <div class="ticketevent">
297 <span class="ticketevent-expand" id="ticketevent-expand-' . $this->cid . '">+ ' . $type.'</span>
298 <a class="pmark" href="#'.$cid.'">#'.$this->cid.'</a>
300 <span class="ticketevent-expand" id="ticketevent-expand-title-' . $this->cid . '">' .
301 (strlen($comment_title) ? $comment_title : implode(', ', $comment_fields)) . '
304 <span style="float:right">' .
305 $link->username($this->who, array('no_image' => true, 'fullname' => true)) . '
306 - <a name="'.$cid.'">'.$timestamp.'</a>
310 <div class="ticketchangeinfo" id="ticketchangeinfo-' . $this->cid . '">' .
311 $link->username($this->who, array('no_name' => true, 'size' => 48));
316 foreach ($this->effort as $eff) {
317 $exp = (float)$eff['expended'];
318 if ($eff['expended'] != 0) {
319 $comment_body .= "<b>spent</b> $exp hours<br>\n";
330 foreach ($comments as $cid => $text) {
331 // look for changesets in the comments..
332 // and display them as expandable linsk..
333 $html .= MTrack_Wiki::format_to_html($text);
342 // list the files that where changed...
343 //$html.= print_r($M, true);
344 $rp = '/' . $commit_info[1] . '/' . $commit_info[2];
346 $repo = MTrackSCM::factory($rp);
347 $cd = $repo->historyWithChangelog(null, 1, 'rev', $rp);
351 if (!is_array($cd->ent->files) || !count($cd->ent->files)) {
355 $num = count(array_keys($cd->ent->files));
362 $file_summary = array();
363 foreach($map as $k=>$v) {
366 foreach ($cd->ent->files as $id => $file) {
369 $type = isset($map[$file->status]) ? $map[$file->status] : '??? '. $file->status;
373 // will bork on unknown...
380 <div class="ticketevent ticketevent-fileitem">
381 <span class="ticketevent-expand" id="ticketevent-expand-' . $this->cid . '.' . $id .'">+ ' . $type.'</span>
382 <span title="' . $fullrp . '?part=' . $id. '" class="ticketevent-expand" id="ticketevent-expand-title-' . $this->cid . '.' . $id . '">' .
383 $file->nameToHtml() . '
385 <span title="' . $fullrp . '?part=' . $id. '" class="ticketevent-expand-diff changesetlink">[View Diff]</span>
386 <span title="' . $fullrp . '" class="ticketevent-expand-view changesetlink">[View File]</span>
387 <span title="' . $fullrp . '" class="ticketevent-expand-view changesetlink">[View History]</span>
389 <div class="ticketchangeinfo" id="ticketchangeinfo-' . $this->cid . '.' . $id . '"></div>
398 foreach($summary as $k=>$v) {
402 $ar[] = $v . ' ' . $k;
405 <div class="ticketevent ticketevent-fileitem">
406 <span class="ticketevent-expand" id="ticketevent-expand-' . $this->cid . '.0">+ MULTIPLE FILES: </span>
407 <span title="' . $fullrp . '?part=' . 0 . '" class="ticketevent-expand" id="ticketevent-expand-title-' . $this->cid . '.' . $id . '">' .
408 implode(', ', $ar) . '
410 <span title="' . $fullrp . '" class="ticketevent-expand-diff changesetlink">[View Diff]</span>
411 <span title="' . $fullrp . '" class="ticketevent-expand-view changesetlink">[View File]</span>
412 <span title="' . $fullrp . '" class="ticketevent-expand-view changesetlink">[View History]</span>
414 <div class="ticketchangeinfo" id="ticketchangeinfo-' . $this->cid . '"></div>
419 //$html .= print_r($cd, true);
429 function collapse_diff($diff)
432 require_once 'MTrackWeb/Changeset.php';
433 $cs = new MTrackWeb_Changeset();
434 $id = 'diff_' . $idnum++;
436 "<button onclick='\$("#$id").toggle(); return false;'>Toggle diff</button>".
437 "<div id='$id' style='display:none'>" .
438 $cs->diff($diff) . "</div>";
441 function diff_strings($before, $now)
444 $tempdir = sys_get_temp_dir();
445 $afile = tempnam($tempdir, "mtrack");
446 $bfile = tempnam($tempdir, "mtrack");
447 file_put_contents($afile, $before);
448 file_put_contents($bfile, $now);
449 static $diff = false;
451 require_once 'System.php';
452 $diff= System::which('diff');
454 if (PHP_OS == 'SunOS') {
455 // TODO: make an option to allow use of gnu diff on solaris
456 $diff = shell_exec("$diff -u $afile $bfile");
457 $diff = str_replace($afile, 'before', $diff);
458 $diff = str_replace($bfile, 'now', $diff);
460 $diff = shell_exec("$diff --label before --label now -u $afile $bfile");
464 $diff = htmlentities($diff, ENT_COMPAT, 'utf-8');