diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php index 43ae645c765a97524d7479e6995c5261319d522d..65777740f83f68a77afa15937e404bd5b6cfe54a 100644 --- a/include/class.dynamic_forms.php +++ b/include/class.dynamic_forms.php @@ -1168,6 +1168,22 @@ class DynamicFormEntry extends VerySimpleModel { return $this->getForm()->render($staff, $title, $options); } + function getChanges() { + $fields = array(); + foreach ($this->getAnswers() as $a) { + $field = $a->getField(); + if (!$field->hasData() || $field->isPresentationOnly()) + continue; + $val = $v = $field->to_database($field->getClean()); + if (is_array($val)) + $v = $val[0]; + if ($a->value == $v) + continue; + $fields[$field->get('id')] = array($a->value, $val); + } + return $fields; + } + /** * addMissingFields * @@ -1489,6 +1505,38 @@ class SelectionField extends FormField { return $value; } + // PHP 5.4 Move this to a trait + function whatChanged($before, $after) { + $before = (array) $before; + $after = (array) $after; + $added = array_diff($after, $before); + $deleted = array_diff($before, $after); + $added = array_map(array($this, 'display'), $added); + $deleted = array_map(array($this, 'display'), $deleted); + + if ($added && $deleted) { + $desc = sprintf( + __('added <strong>%1$s</strong> and removed <strong>%2$s</strong>'), + implode(', ', $added), implode(', ', $deleted)); + } + elseif ($added) { + $desc = sprintf( + __('added <strong>%1$s</strong>'), + implode(', ', $added)); + } + elseif ($deleted) { + $desc = sprintf( + __('removed <strong>%1$s</strong>'), + implode(', ', $deleted)); + } + else { + $desc = sprintf( + __('changed to <strong>%1$s</strong>'), + $this->display($after)); + } + return $desc; + } + function asVar($value, $id=false) { $values = $this->to_php($value, $id); if (is_array($values)) { diff --git a/include/class.forms.php b/include/class.forms.php index 0b6da8f275f0f5a75fc08c3f618279bdd2aff058..97b52d7cfa7da05b8acc673069607bbc54452c88 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -626,6 +626,19 @@ class FormField { return false; } + /** + * Describe the difference between the to two values. Note that the + * values should be passed through ::parse() or to_php() before + * utilizing this method. + */ + function whatChanged($before, $after) { + if ($before) + $desc = __('changed from <strong>%2$s</strong> to <strong>%1$s</strong>'); + else + $desc = __('set to <strong>%1$s</strong>'); + return sprintf($desc, $this->display($after), $this->display($before)); + } + /** * Convert the field data to something matchable by filtering. The * primary use of this is for ticket filtering. @@ -1312,6 +1325,37 @@ class ChoiceField extends FormField { return (string) $value; } + function whatChanged($before, $after) { + $before = (array) $before; + $after = (array) $after; + $added = array_diff($after, $before); + $deleted = array_diff($before, $after); + $added = array_map(array($this, 'display'), $added); + $deleted = array_map(array($this, 'display'), $deleted); + + if ($added && $deleted) { + $desc = sprintf( + __('added <strong>%1$s</strong> and removed <strong>%2$s</strong>'), + implode(', ', $added), implode(', ', $deleted)); + } + elseif ($added) { + $desc = sprintf( + __('added <strong>%1$s</strong>'), + implode(', ', $added)); + } + elseif ($deleted) { + $desc = sprintf( + __('removed <strong>%1$s</strong>'), + implode(', ', $deleted)); + } + else { + $desc = sprintf( + __('changed to <strong>%1$s</strong>'), + $this->display($after)); + } + return $desc; + } + /* Return criteria to which the choice should be filtered by */ diff --git a/include/class.thread.php b/include/class.thread.php index 0167e2aacf0ba2c3868dedab3bd72e6e6b03859c..38eb59fcaf00cfd546fe883f3addfe2055a53218 100644 --- a/include/class.thread.php +++ b/include/class.thread.php @@ -1497,6 +1497,8 @@ class ThreadEvent extends VerySimpleModel { 'collab' => 'group', 'created' => 'magic', 'overdue' => 'time', + 'transferred' => 'share-alt', + 'edited' => 'pencil', ); return @$icons[$this->state] ?: 'chevron-sign-right'; } @@ -1535,6 +1537,26 @@ class ThreadEvent extends VerySimpleModel { 'edited:status' => __('<b>{username}</b> changed the status to <strong>{<TicketStatus>data.status}</strong> {timestamp}'), 'overdue' => __('Flagged as overdue by the system {timestamp}'), 'transferred' => __('<b>{username}</b> transferred this to <strong>{dept}</strong> {timestamp}'), + 'edited:fields' => function($evt) { + $base = __('Updated by <b>{username}</b> {timestamp} — %s'); + $data = $evt->getData(); + $fields = $changes = array(); + foreach (DynamicFormField::objects()->filter(array( + 'id__in' => array_keys($data['fields']) + )) as $F) { + $fields[$F->id] = $F; + } + foreach ($data['fields'] as $id=>$f) { + $field = $fields[$id]; + list($old, $new) = $f; + $impl = $field->getImpl($field); + $before = $impl->to_php($old); + $after = $impl->to_php($new); + $changes[] = sprintf('<strong>%s</strong> %s', + $field->getLocal('label'), $impl->whatChanged($before, $after)); + } + return sprintf($base, implode(', ', $changes)); + }, ); $self = $this; $data = $this->getData(); diff --git a/include/class.ticket.php b/include/class.ticket.php index 0f9ed9386d066a649aaeae6c3b1067bb4d467474..13626636fc7097e7ebc89066e9fbd62f60840aa7 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -2578,7 +2578,6 @@ implements RestrictedAccess, Threadable, TemplateVariable { $fields['slaId'] = array('type'=>'int', 'required'=>0, 'error'=>__('Select a valid SLA')); $fields['duedate'] = array('type'=>'date', 'required'=>0, 'error'=>__('Invalid date format - must be MM/DD/YY')); - $fields['note'] = array('type'=>'text', 'required'=>1, 'error'=>__('A reason for the update is required')); $fields['user_id'] = array('type'=>'int', 'required'=>0, 'error'=>__('Invalid user-id')); if(!Validator::process($fields, $vars, $errors) && !$errors['err']) @@ -2629,16 +2628,16 @@ implements RestrictedAccess, Threadable, TemplateVariable { if(!db_query($sql) || !db_affected_rows()) return false; - if(!$vars['note']) - $vars['note']=sprintf(_S('Ticket details updated by %s'), $thisstaff->getName()); - - $this->logNote(_S('Ticket Updated'), $vars['note'], $thisstaff); + if ($vars['note']) + $this->logNote(_S('Ticket Updated'), $vars['note'], $thisstaff); // Decide if we need to keep the just selected SLA $keepSLA = ($this->getSLAId() != $vars['slaId']); // Update dynamic meta-data + $changes = array(); foreach ($forms as $f) { + $changes += $f->getChanges(); // Drop deleted forms $idx = array_search($f->getId(), $vars['forms']); if ($idx === false) { @@ -2650,6 +2649,8 @@ implements RestrictedAccess, Threadable, TemplateVariable { } } + $this->logEvent('edited', array('fields' => $changes)); + // Reload the ticket so we can do further checking $this->reload();