From 523fe43b91241550f1b1f753d213ca2fcc5df67a Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Tue, 19 Sep 2017 12:49:00 -0400 Subject: [PATCH 01/19] Create new tables, add new language strings --- install/mods-for-hesk/sql/installSql.php | 14 ++++++++++++-- language/en/text.php | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/install/mods-for-hesk/sql/installSql.php b/install/mods-for-hesk/sql/installSql.php index 18cb6dc4..60c3e5d4 100644 --- a/install/mods-for-hesk/sql/installSql.php +++ b/install/mods-for-hesk/sql/installSql.php @@ -1137,9 +1137,9 @@ function execute320Scripts() { hesk_dbConnect(); executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` - ADD COLUMN `mfh_description` VARCHAR(255)"); + ADD COLUMN `mfh_description` TEXT"); executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "custom_fields` - ADD COLUMN `mfh_description` VARCHAR(255)"); + ADD COLUMN `mfh_description` TEXT"); // Purge the custom field caches as we're adding a new field foreach ($hesk_settings['languages'] as $key => $value) { @@ -1147,5 +1147,15 @@ function execute320Scripts() { hesk_unlink(HESK_PATH . "cache/cf_{$language_hash}.cache.php"); } + executeQuery("CREATE TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` ( + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `language_key` VARCHAR(100) NOT NULL, + `date` TIMESTAMP NOT NULL)"); + executeQuery("CREATE TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail_to_replacement_values` ( + `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `audit_trail_id` INT NOT NULL, + `replacement_index` INT NOT NULL, + `replacement_value` TEXT NOT NULL)"); + updateVersion('3.2.0'); } \ No newline at end of file diff --git a/language/en/text.php b/language/en/text.php index 61f0c1cd..baaccd0c 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -2188,5 +2188,23 @@ $hesklang['permission_group_colon'] = 'Permission Group:'; $hesklang['permission_group'] = 'Permission Group'; $hesklang['changing_permissions_will_reset_permission_group'] = 'Changing a user\'s categories / features will reset their permission group! Click "Discard Changes" to reset the user\'s categories / features.'; +// --> Ticket audit trail +$hesklang['audit_moved_category']='%s moved ticket to category %s'; // %s = new category, user making change +$hesklang['audit_assigned']='%s assigned ticket to %s'; // %s = assigned user, user making change +$hesklang['audit_closed']='%s closed ticket'; +$hesklang['audit_opened']='%s opened ticket'; +$hesklang['audit_locked']='%s locked ticket'; +$hesklang['audit_unlocked']='%s unlocked ticket'; +$hesklang['audit_created']='%s created ticket'; +$hesklang['audit_priority']='%s changed priority to %s'; // %s = date,new priority, user making change +$hesklang['audit_status']='%s changed status to %s'; // %s = date, new status, user making change +$hesklang['audit_autoassigned']='%s automatically assigned to ticket'; +$hesklang['audit_submitted_via_piping']='Ticket submitted via e-mail piping'; +$hesklang['audit_attachment_deleted']='%s deleted attachment %s'; // %s = date, deleted attachment, user making change +$hesklang['audit_merged']='%s merged ticket with ticket %s'; // %s = date, merged ticket ID, user making change +$hesklang['audit_time_worked']='%s updated time worked to %s'; // %s = date, new time worked, user making change +$hesklang['audit_submitted_by']='%s submitted ticket'; +$hesklang['audit_submitted_via_pop']='Ticket submitted via POP3 fetching'; + // DO NOT CHANGE BELOW if (!defined('IN_SCRIPT')) die('PHP syntax OK!'); From ca3bfcde1c3d801e79f688aa3fcc9e052d1a750f Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Tue, 19 Sep 2017 12:56:27 -0400 Subject: [PATCH 02/19] Add missing column --- install/mods-for-hesk/sql/installSql.php | 1 + language/en/text.php | 1 + 2 files changed, 2 insertions(+) diff --git a/install/mods-for-hesk/sql/installSql.php b/install/mods-for-hesk/sql/installSql.php index 60c3e5d4..cce64b4a 100644 --- a/install/mods-for-hesk/sql/installSql.php +++ b/install/mods-for-hesk/sql/installSql.php @@ -1149,6 +1149,7 @@ function execute320Scripts() { executeQuery("CREATE TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `ticket_id` INT NOT NULL, `language_key` VARCHAR(100) NOT NULL, `date` TIMESTAMP NOT NULL)"); executeQuery("CREATE TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail_to_replacement_values` ( diff --git a/language/en/text.php b/language/en/text.php index baaccd0c..66384d9c 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -1146,6 +1146,7 @@ $hesklang['maxpost']='You probably tried to submit more data than this server ac // --> Ticket history log // Unless otherwise specified, first %s will be replaced with date and second with name/username +// THESE STRINGS ARE DEPRECATED AS OF MODS FOR HESK 3.2.0 $hesklang['thist1']='
  • %s | moved to category %s by %s
  • '; // %s = date, new category, user making change $hesklang['thist2']='
  • %s | assigned to %s by %s
  • '; // %s = date, assigned user, user making change $hesklang['thist3']='
  • %s | closed by %s
  • '; From 7b8ae3a1d87d8400efc2f55828baddbea3da20fe Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Tue, 19 Sep 2017 17:21:07 -0400 Subject: [PATCH 03/19] The audit table should support multiple types --- install/mods-for-hesk/sql/installSql.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install/mods-for-hesk/sql/installSql.php b/install/mods-for-hesk/sql/installSql.php index cce64b4a..19991d8c 100644 --- a/install/mods-for-hesk/sql/installSql.php +++ b/install/mods-for-hesk/sql/installSql.php @@ -1149,7 +1149,8 @@ function execute320Scripts() { executeQuery("CREATE TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` ( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY, - `ticket_id` INT NOT NULL, + `entity_id` INT NOT NULL, + `entity_type` VARCHAR(50) NOT NULL, `language_key` VARCHAR(100) NOT NULL, `date` TIMESTAMP NOT NULL)"); executeQuery("CREATE TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail_to_replacement_values` ( From 35f03ee26e754eead37fef710202cc2e6eaac870 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Tue, 19 Sep 2017 22:03:39 -0400 Subject: [PATCH 04/19] Getting started with new audit trail entries --- change_status.php | 16 ++++++++-------- inc/common.inc.php | 33 ++++++++++++++++++++++++++++++++- inc/posting_functions.inc.php | 2 +- submit_ticket.php | 10 ++++++++-- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/change_status.php b/change_status.php index 5fee55e1..133a7fda 100644 --- a/change_status.php +++ b/change_status.php @@ -52,7 +52,7 @@ if ($status == 3) // Closed } $status = $closedStatus; $action = $hesklang['closed']; - $revision = sprintf($hesklang['thist3'], hesk_date(), $hesklang['customer']); + $revision_key = 'audit_closed'; if ($hesk_settings['custopen'] != 1) { $locked = 1; @@ -73,7 +73,7 @@ if ($status == 3) // Closed $status = $statusRow['ID']; $action = $hesklang['opened']; - $revision = sprintf($hesklang['thist4'], hesk_date(), $hesklang['customer']); + $revision_key = 'audit_opened'; // We will ask the customer why is the ticket being reopened $_SESSION['force_form_top'] = true; @@ -94,12 +94,9 @@ hesk_verifyEmailMatch($trackingID); $_SESSION['t_track'] = $trackingID; $_SESSION['t_email'] = $hesk_settings['e_email']; -// Load statuses -require_once(HESK_PATH . 'inc/statuses.inc.php'); - // Is current ticket status even changeable by customers? -$ticket = hesk_dbFetchAssoc( hesk_dbQuery( "SELECT `status`, `staffreplies`, `lastreplier` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `trackid`='".hesk_dbEscape($trackingID)."' LIMIT 1") ); -if (!hesk_can_customer_change_status($ticket['status'])) { +$ticket = hesk_dbFetchAssoc( hesk_dbQuery( "SELECT `id`, `status`, `staffreplies`, `lastreplier` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `trackid`='".hesk_dbEscape($trackingID)."' LIMIT 1") ); +if (!mfh_can_customer_change_status($ticket['status'])) { hesk_process_messages($hesklang['scno'],'ticket.php'); } @@ -121,7 +118,10 @@ if ($oldStatus == 2) { // Modify values in the database -hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='{$status}', `locked`='{$locked}' $closedby_sql , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "' AND `locked` != '1'"); +hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='{$status}', `locked`='{$locked}' $closedby_sql WHERE `trackid`='" . hesk_dbEscape($trackingID) . "' AND `locked` != '1'"); + +// Insert audit trail record +mfh_insert_audit_trail_record($ticket['id'], 'TICKET', $revision_key, hesk_date(), array(0 => $hesklang['customer'])); // Did we modify anything* if (hesk_dbAffectedRows() != 1) { diff --git a/inc/common.inc.php b/inc/common.inc.php index 94f487dc..28e63339 100644 --- a/inc/common.inc.php +++ b/inc/common.inc.php @@ -2155,4 +2155,35 @@ function mfh_get_hidden_fields_for_language($keys) { $output .= ''; return $output; -} \ No newline at end of file +} + +/** + * Date will always be the current date/time + */ +function mfh_insert_audit_trail_record($entity_id, $entity_type, $language_key, $date, $replacement_values) { + global $hesk_settings; + + hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` (`entity_id`, `entity_type`, + `language_key`, `date`) VALUES (" . intval($entity_id) . ", '" . hesk_dbEscape($entity_type) . "', + '" . hesk_dbEscape($language_key) . "', '" . hesk_dbEscape($date) . "')"); + + $audit_id = hesk_dbInsertID(); + + foreach ($replacement_values as $replacement_index => $replacement_value) { + hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail_to_replacement_values` + (`audit_trail_id`, `replacement_index`, `replacement_value`) VALUES (" . intval($audit_id) . ", + " . intval($replacement_index) . ", '" . hesk_dbEscape($replacement_value) . "')"); + } + + return $audit_id; +} + +function mfh_can_customer_change_status($status) +{ + global $hesk_settings; + + $res = hesk_dbQuery("SELECT `Closable` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` WHERE `ID` = " . intval($status)); + $row = hesk_dbFetchAssoc($res); + + return $row['Closable'] == 'yes' || $row['Closable'] == 'conly'; +} // END hesk_get_ticket_status() \ No newline at end of file diff --git a/inc/posting_functions.inc.php b/inc/posting_functions.inc.php index a2cd5221..dfe6b5a6 100644 --- a/inc/posting_functions.inc.php +++ b/inc/posting_functions.inc.php @@ -115,7 +115,7 @@ function hesk_newTicket($ticket, $isVerified = true) " . hesk_dbEscape($ticket['screen_resolution_height']) . ", " . hesk_dbEscape($ticket['screen_resolution_width']) . ", {$due_date}, - '" . hesk_dbEscape($ticket['history']) . "' + '', {$custom_what} ) "); diff --git a/submit_ticket.php b/submit_ticket.php index 03c710e4..06090ef6 100644 --- a/submit_ticket.php +++ b/submit_ticket.php @@ -405,13 +405,11 @@ if ($hesk_settings['kb_enable'] && $hesk_settings['kb_recommendanswers'] && isse // All good now, continue with ticket creation $tmpvar['owner'] = 0; -$tmpvar['history'] = sprintf($hesklang['thist15'], hesk_date(), $tmpvar['name']); // Auto assign tickets if aplicable $autoassign_owner = hesk_autoAssignTicket($tmpvar['category']); if ($autoassign_owner) { $tmpvar['owner'] = $autoassign_owner['id']; - $tmpvar['history'] .= sprintf($hesklang['thist10'], hesk_date(), $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')'); } // Insert attachments @@ -463,6 +461,14 @@ if ($createTicket) { //-- email has been verified, and a ticket can be created $ticket = hesk_newTicket($tmpvar); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_submitted_by', hesk_date(), + array(0 => $tmpvar['name'])); + + if ($autoassign_owner) { + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(), + array(0 => $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')')); + } + // Notify the customer if ($hesk_settings['notify_new'] && $email_available) { hesk_notifyCustomer($modsForHesk_settings); From b95876e6a117144839fbad268d618217c4db7b73 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Wed, 20 Sep 2017 08:10:51 -0400 Subject: [PATCH 05/19] Add new audit trail entries for admin_reply_ticket --- admin/admin_reply_ticket.php | 31 +++++++++++++++++++++---------- language/en/text.php | 1 + 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/admin/admin_reply_ticket.php b/admin/admin_reply_ticket.php index 96ab9f9f..7abe3b11 100644 --- a/admin/admin_reply_ticket.php +++ b/admin/admin_reply_ticket.php @@ -211,9 +211,18 @@ if (!empty($_POST['set_priority'])) { 3 => $hesklang['low'] ); - $revision = sprintf($hesklang['thist8'], hesk_date(), $options[$priority], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + $plain_options = array( + 0 => 'critical', + 1 => 'high', + 2 => 'medium', + 3 => 'low' + ); + + $priority_sql = ",`priority`='$priority' "; - $priority_sql = ",`priority`='$priority', `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') "; + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_priority', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $plain_options[$priority])); } else { $priority_sql = ""; } @@ -238,8 +247,8 @@ if ($ticket['locked']) { $newStatus = hesk_dbFetchAssoc($newStatusRs); if ($newStatus['IsClosed'] && hesk_checkPermission('can_resolve', 0)) { - $revision = sprintf($hesklang['thist3'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); - $sql_status = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . ", `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') "; + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_closed', hesk_date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $sql_status = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " "; // Lock the ticket if customers are not allowed to reopen tickets if ($hesk_settings['custopen'] != 1) { @@ -247,8 +256,9 @@ if ($ticket['locked']) { } } else { // Ticket isn't being closed, just add the history to the sql query (or tried to close but doesn't have permission) - $revision = sprintf($hesklang['thist9'], hesk_date(), $hesklang[$newStatus['Key']], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); - $sql_status = " , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') "; + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_status', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => mfh_getDisplayTextForStatusId($new_status))); } } } // -> Submit as Customer reply @@ -259,8 +269,9 @@ elseif ($submit_as_customer) { $new_status = $customerReplyStatus['ID']; if ($ticket['status'] != $new_status) { - $revision = sprintf($hesklang['thist9'], hesk_date(), $hesklang['wait_reply'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); - $sql_status = " , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') "; + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_status', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => mfh_getDisplayTextForStatusId($new_status))); } } // -> Default: submit as "Replied by staff" else { @@ -282,8 +293,8 @@ if ($time_worked == '00:00:00') { } if (!empty($_POST['assign_self']) && (hesk_checkPermission('can_assign_self', 0) || (isset($_REQUEST['isManager']) && $_REQUEST['isManager']))) { - $revision = sprintf($hesklang['thist2'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); - $sql .= " , `owner`=" . intval($_SESSION['id']) . ", `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') "; + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_assigned_self', hesk_date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $sql .= " , `owner`=" . intval($_SESSION['id']) . " "; } $sql .= " $priority_sql "; diff --git a/language/en/text.php b/language/en/text.php index 66384d9c..593322c2 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -2192,6 +2192,7 @@ $hesklang['changing_permissions_will_reset_permission_group'] = 'Changing a user // --> Ticket audit trail $hesklang['audit_moved_category']='%s moved ticket to category %s'; // %s = new category, user making change $hesklang['audit_assigned']='%s assigned ticket to %s'; // %s = assigned user, user making change +$hesklang['audit_assigned_self'] = '%s assigned ticket to themself'; $hesklang['audit_closed']='%s closed ticket'; $hesklang['audit_opened']='%s opened ticket'; $hesklang['audit_locked']='%s locked ticket'; From 4ac430bc19c1d1239157ad938bbcb267e24b2787 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Thu, 21 Sep 2017 22:12:55 -0400 Subject: [PATCH 06/19] Replace several audit trail spots --- admin/admin_submit_ticket.php | 11 +++++++++-- admin/admin_ticket.php | 12 +++++++++--- admin/assign_owner.php | 18 ++++++++++++++---- admin/change_status.php | 18 ++++++++++++++---- admin/delete_tickets.php | 29 +++++++++++++++++++---------- admin/index.php | 4 ++-- admin/lock.php | 23 +++++++++++++---------- inc/posting_functions.inc.php | 2 +- language/en/text.php | 15 +++++++++------ 9 files changed, 90 insertions(+), 42 deletions(-) diff --git a/admin/admin_submit_ticket.php b/admin/admin_submit_ticket.php index 9eb40c3a..80d1269e 100644 --- a/admin/admin_submit_ticket.php +++ b/admin/admin_submit_ticket.php @@ -176,11 +176,11 @@ foreach ($hesk_settings['custom_fields'] as $k=>$v) { $tmpvar['trackid'] = hesk_createID(); // Log who submitted ticket -$tmpvar['history'] = sprintf($hesklang['thist7'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); $tmpvar['openedby'] = $_SESSION['id']; // Owner $tmpvar['owner'] = 0; +$autoassign_owner = null; if (hesk_checkPermission('can_assign_others', 0)) { $tmpvar['owner'] = intval(hesk_POST('owner')); @@ -192,7 +192,6 @@ if (hesk_checkPermission('can_assign_others', 0)) { $autoassign_owner = hesk_autoAssignTicket($tmpvar['category']); if ($autoassign_owner) { $tmpvar['owner'] = intval($autoassign_owner['id']); - $tmpvar['history'] .= sprintf($hesklang['thist10'], hesk_date(), $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')'); } else { $tmpvar['owner'] = 0; } @@ -315,6 +314,14 @@ $tmpvar['screen_resolution_width'] = "NULL"; // Insert ticket to database $ticket = hesk_newTicket($tmpvar); +mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_created', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + +if ($autoassign_owner) { + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(), + array(0 => $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')')); +} + // Notify the customer about the ticket? if ($notify && $email_available) { hesk_notifyCustomer($modsForHesk_settings); diff --git a/admin/admin_ticket.php b/admin/admin_ticket.php index 9743f626..6a96fdf6 100644 --- a/admin/admin_ticket.php +++ b/admin/admin_ticket.php @@ -439,8 +439,11 @@ if ($hesk_settings['time_worked'] && ($can_reply || $can_edit) && isset($_POST[' $time_worked = hesk_getTime($h . ':' . $m . ':' . $s); /* Update database */ - $revision = sprintf($hesklang['thist14'], hesk_date(), $time_worked, $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); - hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `time_worked`='" . hesk_dbEscape($time_worked) . "', `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); + //audit_time_worked who - value + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_time_worked', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $time_worked)); + hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `time_worked`='" . hesk_dbEscape($time_worked) . "' WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); /* Show ticket */ hesk_process_messages($hesklang['twu'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS'); @@ -528,7 +531,10 @@ if (isset($_GET['delatt']) && hesk_token_check()) { hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "'"); /* Update ticket or reply in the database */ - $revision = sprintf($hesklang['thist12'], hesk_date(), $att['real_name'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + // audit_attachment_deleted + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_attachment_deleted', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $att['real_name'])); if ($reply) { hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` SET `attachments`=REPLACE(`attachments`,'" . hesk_dbEscape($att_id . '#' . $att['real_name'] . '#' . $att['saved_name']) . ",','') WHERE `id`='" . intval($reply) . "'"); hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `id`='" . intval($ticket['id']) . "'"); diff --git a/admin/assign_owner.php b/admin/assign_owner.php index 793bdfdd..a52c3fc9 100755 --- a/admin/assign_owner.php +++ b/admin/assign_owner.php @@ -52,8 +52,9 @@ $owner = intval(hesk_REQUEST('owner')); /* If ID is -1 the ticket will be unassigned */ if ($owner == -1) { - $revision = sprintf($hesklang['thist2'], hesk_date(), '' . $hesklang['unas'] . '', $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); - $res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0 , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unassigned', date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0 WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); hesk_process_messages($hesklang['tunasi2'], $_SERVER['PHP_SELF'], 'SUCCESS'); } elseif ($owner < 1) { @@ -96,8 +97,17 @@ if ($ticket['owner'] && $ticket['owner'] != $owner && hesk_REQUEST('unassigned') /* Assigning to self? */ if ($can_assign_others || ($owner == $_SESSION['id'] && $can_assign_self)) { - $revision = sprintf($hesklang['thist2'], hesk_date(), $row['name'] . ' (' . $row['user'] . ')', $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); - $res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`={$owner} , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); + if ($owner == $_SESSION['id'] && $can_assign_self) { + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_assigned_self', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + } else { + // current user -> assigned user + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_assigned', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $row['name'] . ' (' . $row['user'] . ')')); + } + + $res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`={$owner} WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); if ($owner != $_SESSION['id'] && !hesk_checkPermission('can_view_ass_others', 0)) { $_SERVER['PHP_SELF'] = 'admin_main.php'; diff --git a/admin/change_status.php b/admin/change_status.php index 42d002f1..63c30832 100644 --- a/admin/change_status.php +++ b/admin/change_status.php @@ -37,6 +37,10 @@ hesk_token_check(); /* Ticket ID */ $trackingID = hesk_cleanID() or die($hesklang['int_error'] . ': ' . $hesklang['no_trackID']); +$ticket_id_rs = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid` = '" . hesk_dbEscape($trackingID) . "'"); +$ticket_id_row = hesk_dbFetchAssoc($ticket_id_rs); +$ticket_id = $ticket_id_row['id']; + /* Valid statuses */ $statusSql = "SELECT `ID` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses`"; $status_options = array(); @@ -62,10 +66,13 @@ if ($statusRow['IsClosed']) // Closed } $action = $hesklang['ticket_been'] . ' ' . $hesklang['close']; - $revision = sprintf($hesklang['thist3'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_closed', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + if ($hesk_settings['custopen'] != 1) { $locked = 1; + mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_automatically_locked', hesk_date(), array()); } // Notify customer of closed ticket? @@ -91,21 +98,24 @@ if ($statusRow['IsClosed']) // Closed } elseif ($statusRow['IsNewTicketStatus'] == 0) //Ticket is still open, but not new { $action = sprintf($hesklang['tsst'], $status_options[$status]); - $revision = sprintf($hesklang['thist9'], hesk_date(), $status_options[$status], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_status', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $status_options[$status])); // Ticket is not resolved $closedby_sql = ' , `closedat`=NULL, `closedby`=NULL '; } else // Ticket is marked as "NEW" { $action = $hesklang['ticket_been'] . ' ' . $hesklang['opened']; - $revision = sprintf($hesklang['thist4'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_opened', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); // Ticket is not resolved $closedby_sql = ' , `closedat`=NULL, `closedby`=NULL '; } -hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='{$status}', `locked`='{$locked}' $closedby_sql , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); +hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='{$status}', `locked`='{$locked}' $closedby_sql WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); if (hesk_dbAffectedRows() != 1) { hesk_error("$hesklang[int_error]: $hesklang[trackID_not_found]."); diff --git a/admin/delete_tickets.php b/admin/delete_tickets.php index 7bc77b44..8a654873 100644 --- a/admin/delete_tickets.php +++ b/admin/delete_tickets.php @@ -81,10 +81,10 @@ $i = 0; // Possible priorities $priorities = array( - 'critical' => array('value' => 0, 'text' => $hesklang['critical'], 'formatted' => '' . $hesklang['critical'] . ''), - 'high' => array('value' => 1, 'text' => $hesklang['high'], 'formatted' => '' . $hesklang['high'] . ''), - 'medium' => array('value' => 2, 'text' => $hesklang['medium'], 'formatted' => '' . $hesklang['medium'] . ''), - 'low' => array('value' => 3, 'text' => $hesklang['low'], 'formatted' => $hesklang['low']), + 'critical' => array('value' => 0, 'lang' => 'critical', 'text' => $hesklang['critical'], 'formatted' => '' . $hesklang['critical'] . ''), + 'high' => array('value' => 1, 'lang' => 'high', 'text' => $hesklang['high'], 'formatted' => '' . $hesklang['high'] . ''), + 'medium' => array('value' => 2, 'lang' => 'medium', 'text' => $hesklang['medium'], 'formatted' => '' . $hesklang['medium'] . ''), + 'low' => array('value' => 3, 'lang' => 'low', 'text' => $hesklang['low'], 'formatted' => $hesklang['low']), ); // Change priority @@ -113,8 +113,10 @@ if (array_key_exists($_POST['a'], $priorities)) { hesk_okCategory($ticket['category']); - $revision = sprintf($hesklang['thist8'], hesk_date(), $priority['formatted'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); - hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `priority`='{$priority['value']}', `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `id`={$this_id}"); + mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_priority', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $priority['lang'])); + hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `priority`='{$priority['value']}' WHERE `id`={$this_id}"); $i++; } @@ -133,8 +135,6 @@ elseif ($_POST['a'] == 'delete') { require(HESK_PATH . 'inc/email_functions.inc.php'); } - $revision = sprintf($hesklang['thist3'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); - foreach ($_POST['id'] as $this_id) { if (is_array($this_id)) { continue; @@ -222,7 +222,8 @@ else { hesk_token_check('POST'); require(HESK_PATH . 'inc/email_functions.inc.php'); - $revision = sprintf($hesklang['thist3'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_closed', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); foreach ($_POST['id'] as $this_id) { if (is_array($this_id)) { @@ -239,7 +240,7 @@ else { $closedStatusRS = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` WHERE `IsStaffClosedOption` = 1"); $closedStatus = hesk_dbFetchAssoc($closedStatusRS); - hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='" . $closedStatus['ID'] . "', `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . ", `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `id`='" . intval($this_id) . "'"); + hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='" . $closedStatus['ID'] . "', `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " WHERE `id`='" . intval($this_id) . "'"); $i++; // Notify customer of closed ticket? @@ -284,6 +285,14 @@ function hesk_fullyDeleteTicket() /* Delete ticket notes */ hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` WHERE `ticket`='" . intval($ticket['id']) . "'"); + /* Delete audit trail records */ + hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail_to_replacement_values` + WHERE `audit_trail_id` IN ( + SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` + WHERE `entity_type` = 'TICKET' AND `entity_id` = " . intval($ticket['id']) . ")"); + hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` WHERE `entity_type`='TICKET' + AND `entity_id` = " . intval($ticket['id'])); + /* Delete ticket reply drafts */ hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "reply_drafts` WHERE `ticket`=" . intval($ticket['id'])); diff --git a/admin/index.php b/admin/index.php index cef05749..b822ed29 100644 --- a/admin/index.php +++ b/admin/index.php @@ -202,7 +202,6 @@ function do_login() /* Close any old tickets here so Cron jobs aren't necessary */ if ($hesk_settings['autoclose']) { - $revision = sprintf($hesklang['thist3'], hesk_date(), $hesklang['auto']); $dt = date('Y-m-d H:i:s', time() - $hesk_settings['autoclose'] * 86400); @@ -226,6 +225,7 @@ function do_login() $ticket['dt'] = hesk_date($ticket['dt'], true); $ticket['lastchange'] = hesk_date($ticket['lastchange'], true); $ticket = hesk_ticketToPlain($ticket, 1, 0); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_automatically_closed', hesk_date(), array()); hesk_notifyCustomer($modsForHesk_settings, 'ticket_closed'); } } @@ -234,7 +234,7 @@ function do_login() // Update ticket statuses and history in database if we're allowed to do so $defaultCloseRs = hesk_dbQuery('SELECT `ID` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `IsAutocloseOption` = 1'); $defaultCloseStatus = hesk_dbFetchAssoc($defaultCloseRs); - hesk_dbQuery("UPDATE `" . $hesk_settings['db_pfix'] . "tickets` SET `status`=" . intval($defaultCloseStatus['ID']) . ", `closedat`=NOW(), `closedby`='-1', `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `status` = '" . $closedStatus['ID'] . "' AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); + hesk_dbQuery("UPDATE `" . $hesk_settings['db_pfix'] . "tickets` SET `status`=" . intval($defaultCloseStatus['ID']) . ", `closedat`=NOW(), `closedby`='-1' WHERE `status` = '" . $closedStatus['ID'] . "' AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); } } diff --git a/admin/lock.php b/admin/lock.php index 57bedfd6..71591724 100644 --- a/admin/lock.php +++ b/admin/lock.php @@ -37,27 +37,30 @@ hesk_token_check(); /* Ticket ID */ $trackingID = hesk_cleanID() or die($hesklang['int_error'] . ': ' . $hesklang['no_trackID']); + +// Get ticket info +$result = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid`='" . hesk_dbEscape($trackingID) . "' LIMIT 1"); +if (hesk_dbNumRows($result) != 1) { + hesk_error($hesklang['ticket_not_found']); +} +$ticket = hesk_dbFetchAssoc($result); + /* New locked status */ if (empty($_GET['locked'])) { $status = 0; $tmp = $hesklang['tunlock']; - $revision = sprintf($hesklang['thist6'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unlocked', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); $closedby_sql = ' , `closedat`=NULL, `closedby`=NULL '; } else { $status = 1; $tmp = $hesklang['tlock']; - $revision = sprintf($hesklang['thist5'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_locked', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); $closedby_sql = ' , `closedat`=NOW(), `closedby`=' . intval($_SESSION['id']) . ' '; // Notify customer of closed ticket? if ($hesk_settings['notify_closed']) { - // Get ticket info - $result = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid`='" . hesk_dbEscape($trackingID) . "' LIMIT 1"); - if (hesk_dbNumRows($result) != 1) { - hesk_error($hesklang['ticket_not_found']); - } - $ticket = hesk_dbFetchAssoc($result); - $closedStatusRS = hesk_dbQuery('SELECT `ID` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `IsClosed` = 1'); $ticketIsOpen = true; while ($row = hesk_dbFetchAssoc($closedStatusRS)) { @@ -82,7 +85,7 @@ $statusRs = hesk_dbQuery($statusSql); $statusRow = hesk_dbFetchAssoc($statusRs); $statusId = $statusRow['ID']; -hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`= {$statusId},`locked`='{$status}' $closedby_sql , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); +hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`= {$statusId},`locked`='{$status}' $closedby_sql WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); /* Back to ticket page and show a success message */ hesk_process_messages($tmp, 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . rand(10000, 99999), 'SUCCESS'); \ No newline at end of file diff --git a/inc/posting_functions.inc.php b/inc/posting_functions.inc.php index dfe6b5a6..7e81bfbf 100644 --- a/inc/posting_functions.inc.php +++ b/inc/posting_functions.inc.php @@ -115,7 +115,7 @@ function hesk_newTicket($ticket, $isVerified = true) " . hesk_dbEscape($ticket['screen_resolution_height']) . ", " . hesk_dbEscape($ticket['screen_resolution_width']) . ", {$due_date}, - '', + '' {$custom_what} ) "); diff --git a/language/en/text.php b/language/en/text.php index 593322c2..e0b05533 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -2193,13 +2193,16 @@ $hesklang['changing_permissions_will_reset_permission_group'] = 'Changing a user $hesklang['audit_moved_category']='%s moved ticket to category %s'; // %s = new category, user making change $hesklang['audit_assigned']='%s assigned ticket to %s'; // %s = assigned user, user making change $hesklang['audit_assigned_self'] = '%s assigned ticket to themself'; -$hesklang['audit_closed']='%s closed ticket'; -$hesklang['audit_opened']='%s opened ticket'; -$hesklang['audit_locked']='%s locked ticket'; -$hesklang['audit_unlocked']='%s unlocked ticket'; +$hesklang['audit_unassigned'] = '%s unassigned ticket'; +$hesklang['audit_closed']='%s closed ticket'; // thist3 +$hesklang['audit_automatically_closed'] ='Ticket automatically closed'; +$hesklang['audit_opened']='%s opened ticket'; // thist4 +$hesklang['audit_locked']='%s locked ticket'; // thist5 +$hesklang['audit_automatically_locked'] = 'Ticket automatically locked'; +$hesklang['audit_unlocked']='%s unlocked ticket'; // thist6 $hesklang['audit_created']='%s created ticket'; -$hesklang['audit_priority']='%s changed priority to %s'; // %s = date,new priority, user making change -$hesklang['audit_status']='%s changed status to %s'; // %s = date, new status, user making change +$hesklang['audit_priority']='%s changed priority to %s'; // %s = date,new priority, user making change, thist8 +$hesklang['audit_status']='%s changed status to %s'; // %s = date, new status, user making change, thist9 $hesklang['audit_autoassigned']='%s automatically assigned to ticket'; $hesklang['audit_submitted_via_piping']='Ticket submitted via e-mail piping'; $hesklang['audit_attachment_deleted']='%s deleted attachment %s'; // %s = date, deleted attachment, user making change From d5589cc1c27c6e7335e9b964a15ae54066f88cd3 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Fri, 22 Sep 2017 08:01:53 -0400 Subject: [PATCH 07/19] Some more audit trail fixes --- admin/move_category.php | 12 +++++++++--- language/en/text.php | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/admin/move_category.php b/admin/move_category.php index e049255e..b1870392 100755 --- a/admin/move_category.php +++ b/admin/move_category.php @@ -71,7 +71,11 @@ if (hesk_dbNumRows($res) != 1) { $ticket = hesk_dbFetchAssoc($res); /* Log that ticket is being moved */ -$history = sprintf($hesklang['thist1'], hesk_date(), $row['name'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); +//audit_moved_category +mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_moved_category', hesk_date(), array( + 0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $row['name'] +)); /* Is the ticket assigned to someone? If yes, check that the user has access to category or change to unassigned */ $need_to_reassign = 0; @@ -97,13 +101,15 @@ if ($need_to_reassign || !$ticket['owner']) { $autoassign_owner = hesk_autoAssignTicket($category); if ($autoassign_owner) { $ticket['owner'] = $autoassign_owner['id']; - $history .= sprintf($hesklang['thist10'], hesk_date(), $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')'); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(), array( + 0 => $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')' + )); } else { $ticket['owner'] = 0; } } -hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `category`='" . intval($category) . "', `owner`='" . intval($ticket['owner']) . "' , `history`=CONCAT(`history`,'" . hesk_dbEscape($history) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); +hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `category`='" . intval($category) . "', `owner`='" . intval($ticket['owner']) . "' WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); $ticket['category'] = $category; diff --git a/language/en/text.php b/language/en/text.php index e0b05533..97fb10d0 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -2190,7 +2190,7 @@ $hesklang['permission_group'] = 'Permission Group'; $hesklang['changing_permissions_will_reset_permission_group'] = 'Changing a user\'s categories / features will reset their permission group! Click "Discard Changes" to reset the user\'s categories / features.'; // --> Ticket audit trail -$hesklang['audit_moved_category']='%s moved ticket to category %s'; // %s = new category, user making change +$hesklang['audit_moved_category']='%s moved ticket to category %s'; // %s = new category, user making change, thist1 $hesklang['audit_assigned']='%s assigned ticket to %s'; // %s = assigned user, user making change $hesklang['audit_assigned_self'] = '%s assigned ticket to themself'; $hesklang['audit_unassigned'] = '%s unassigned ticket'; @@ -2203,7 +2203,7 @@ $hesklang['audit_unlocked']='%s unlocked ticket'; // thist6 $hesklang['audit_created']='%s created ticket'; $hesklang['audit_priority']='%s changed priority to %s'; // %s = date,new priority, user making change, thist8 $hesklang['audit_status']='%s changed status to %s'; // %s = date, new status, user making change, thist9 -$hesklang['audit_autoassigned']='%s automatically assigned to ticket'; +$hesklang['audit_autoassigned']='%s automatically assigned to ticket'; //thist10 $hesklang['audit_submitted_via_piping']='Ticket submitted via e-mail piping'; $hesklang['audit_attachment_deleted']='%s deleted attachment %s'; // %s = date, deleted attachment, user making change $hesklang['audit_merged']='%s merged ticket with ticket %s'; // %s = date, merged ticket ID, user making change From 05ede52ce5fa4539909343879f7bc576f5b37eae Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Fri, 22 Sep 2017 08:02:43 -0400 Subject: [PATCH 08/19] Add priority.php --- .gitignore | 1 - admin/priority.php | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 admin/priority.php diff --git a/.gitignore b/.gitignore index 70d3d8c3..44ac5da8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ admin/archive.php admin/custom_statuses.php admin/email_templates.php admin/generate_spam_question.php -admin/priority.php admin/test_connection.php attachments/index.htm cache/ diff --git a/admin/priority.php b/admin/priority.php new file mode 100644 index 00000000..e10c0605 --- /dev/null +++ b/admin/priority.php @@ -0,0 +1,59 @@ + 3) +{ + hesk_process_messages($hesklang['inpr'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'NOTICE'); +} + +$options = array( + 0 => ''.$hesklang['critical'].'', + 1 => ''.$hesklang['high'].'', + 2 => ''.$hesklang['medium'].'', + 3 => $hesklang['low'] +); + +$revision = sprintf($hesklang['thist8'],hesk_date(),$options[$priority],$_SESSION['name'].' ('.$_SESSION['user'].')'); + +hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `priority`='{$priority}', `history`=CONCAT(`history`,'".hesk_dbEscape($revision)."') WHERE `trackid`='".hesk_dbEscape($trackingID)."'"); +if (hesk_dbAffectedRows() != 1) +{ + hesk_process_messages($hesklang['inpr'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'NOTICE'); +} + +hesk_process_messages(sprintf($hesklang['chpri2'],$options[$priority]),'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS'); +?> From 939f470666b5b8a936c5e777ed6e08a32d2738c4 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Fri, 22 Sep 2017 08:08:16 -0400 Subject: [PATCH 09/19] Updated some more audit trails --- admin/priority.php | 17 +++++++++++++++-- inc/admin_functions.inc.php | 7 +++++-- language/en/text.php | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/admin/priority.php b/admin/priority.php index e10c0605..b2fe75e5 100644 --- a/admin/priority.php +++ b/admin/priority.php @@ -47,9 +47,22 @@ $options = array( 3 => $hesklang['low'] ); -$revision = sprintf($hesklang['thist8'],hesk_date(),$options[$priority],$_SESSION['name'].' ('.$_SESSION['user'].')'); +$plain_options = array( + 0 => 'critical', + 1 => 'high', + 2 => 'medium', + 3 => 'low' +); + +$ticketRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid` = '" . hesk_dbEscape($trackingID) . "'"); +$ticket = hesk_dbFetchAssoc($ticketRs); + +mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_priority', hesk_date(), array( + 0 => $_SESSION['name'].' ('.$_SESSION['user'].')', + 1 => $plain_options[$priority] +)); -hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `priority`='{$priority}', `history`=CONCAT(`history`,'".hesk_dbEscape($revision)."') WHERE `trackid`='".hesk_dbEscape($trackingID)."'"); +hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `priority`='{$priority}' WHERE `trackid`='".hesk_dbEscape($trackingID)."'"); if (hesk_dbAffectedRows() != 1) { hesk_process_messages($hesklang['inpr'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'NOTICE'); diff --git a/inc/admin_functions.inc.php b/inc/admin_functions.inc.php index f2edf27a..2420f648 100644 --- a/inc/admin_functions.inc.php +++ b/inc/admin_functions.inc.php @@ -201,7 +201,10 @@ function hesk_mergeTickets($merge_these, $merge_into) hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `id`='" . intval($row['id']) . "'"); /* Log that ticket has been merged */ - $history .= sprintf($hesklang['thist13'], hesk_date(), $row['trackid'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + mfh_insert_audit_trail_record($merge_into, 'TICKET', 'audit_merged', hesk_date(), array( + 0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $row['trackid'] + )); /* Add old ticket ID to target ticket "merged" field */ $merged .= '#' . $row['trackid']; @@ -234,7 +237,7 @@ function hesk_mergeTickets($merge_these, $merge_into) } /* Update history (log) and merged IDs of target ticket */ - hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET $replies_sql `time_worked`=ADDTIME(`time_worked`, '" . hesk_dbEscape($sec_worked) . "'), `merged`=CONCAT(`merged`,'" . hesk_dbEscape($merged . '#') . "'), `history`=CONCAT(`history`,'" . hesk_dbEscape($history) . "') WHERE `id`='" . intval($merge_into) . "'"); + hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET $replies_sql `time_worked`=ADDTIME(`time_worked`, '" . hesk_dbEscape($sec_worked) . "'), `merged`=CONCAT(`merged`,'" . hesk_dbEscape($merged . '#') . "') WHERE `id`='" . intval($merge_into) . "'"); return true; diff --git a/language/en/text.php b/language/en/text.php index 97fb10d0..353988ab 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -2206,7 +2206,7 @@ $hesklang['audit_status']='%s changed status to %s'; // %s = date, new status, u $hesklang['audit_autoassigned']='%s automatically assigned to ticket'; //thist10 $hesklang['audit_submitted_via_piping']='Ticket submitted via e-mail piping'; $hesklang['audit_attachment_deleted']='%s deleted attachment %s'; // %s = date, deleted attachment, user making change -$hesklang['audit_merged']='%s merged ticket with ticket %s'; // %s = date, merged ticket ID, user making change +$hesklang['audit_merged']='%s merged ticket %s with this ticket'; // %s = date, merged ticket ID, user making change, thist13 $hesklang['audit_time_worked']='%s updated time worked to %s'; // %s = date, new time worked, user making change $hesklang['audit_submitted_by']='%s submitted ticket'; $hesklang['audit_submitted_via_pop']='Ticket submitted via POP3 fetching'; From db99d2219ea350c15fa842f234f53600d6162b11 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Fri, 22 Sep 2017 12:50:04 -0400 Subject: [PATCH 10/19] Updated the rest of the audit trails --- inc/admin_functions.inc.php | 14 ++++++++++---- inc/common.inc.php | 5 +---- inc/pipe_functions.inc.php | 9 +++++++-- language/en/text.php | 4 ++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/inc/admin_functions.inc.php b/inc/admin_functions.inc.php index 2420f648..cadb5a88 100644 --- a/inc/admin_functions.inc.php +++ b/inc/admin_functions.inc.php @@ -422,14 +422,17 @@ function hesk_autoLogin($noredirect = 0) hesk_setcookie('hesk_p', "$hash", strtotime('+1 year')); /* Close any old tickets here so Cron jobs aren't necessary */ - if ($hesk_settings['autoclose']) { - $revision = sprintf($hesklang['thist3'], hesk_date(), $hesklang['auto']); + $closedStatusRs = hesk_dbQuery('SELECT `ID`, `Closable` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `IsDefaultStaffReplyStatus` = 1'); + $closedStatus = hesk_dbFetchAssoc($closedStatusRs); + // Are we allowed to close tickets in this status? + if (($closedStatus['Closable'] == 'yes' || $closedStatus['Closable'] == 'sonly') && $hesk_settings['autoclose']) { $dt = date('Y-m-d H:i:s', time() - $hesk_settings['autoclose'] * 86400); // Notify customer of closed ticket? if ($hesk_settings['notify_closed']) { // Get list of tickets - $result = hesk_dbQuery("SELECT * FROM `" . $hesk_settings['db_pfix'] . "tickets` WHERE `status` = '2' AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); + $result = hesk_dbQuery("SELECT * FROM `" . $hesk_settings['db_pfix'] . "tickets` WHERE `status` = " . $closedStatus['ID'] . " AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); + if (hesk_dbNumRows($result) > 0) { global $ticket; @@ -442,6 +445,7 @@ function hesk_autoLogin($noredirect = 0) $ticket['dt'] = hesk_date($ticket['dt'], true); $ticket['lastchange'] = hesk_date($ticket['lastchange'], true); $ticket = hesk_ticketToPlain($ticket, 1, 0); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_automatically_closed', hesk_date()); $modsForHesk_settings = mfh_getSettings(); hesk_notifyCustomer($modsForHesk_settings, 'ticket_closed'); } @@ -449,7 +453,9 @@ function hesk_autoLogin($noredirect = 0) } // Update ticket statuses and history in database - hesk_dbQuery("UPDATE `" . $hesk_settings['db_pfix'] . "tickets` SET `status`='3', `closedat`=NOW(), `closedby`='-1', `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `status` = '2' AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); + $defaultCloseRs = hesk_dbQuery('SELECT `ID` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `IsAutocloseOption` = 1'); + $defaultCloseStatus = hesk_dbFetchAssoc($defaultCloseRs); + hesk_dbQuery("UPDATE `" . $hesk_settings['db_pfix'] . "tickets` SET `status`= " . $defaultCloseStatus['ID'] . ", `closedat`=NOW(), `closedby`='-1' WHERE `status` = " . $closedStatus['ID'] . " AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); } /* If session expired while a HESK page is open just continue using it, don't redirect */ diff --git a/inc/common.inc.php b/inc/common.inc.php index 28e63339..be8f07eb 100644 --- a/inc/common.inc.php +++ b/inc/common.inc.php @@ -2157,10 +2157,7 @@ function mfh_get_hidden_fields_for_language($keys) { return $output; } -/** - * Date will always be the current date/time - */ -function mfh_insert_audit_trail_record($entity_id, $entity_type, $language_key, $date, $replacement_values) { +function mfh_insert_audit_trail_record($entity_id, $entity_type, $language_key, $date, $replacement_values = array()) { global $hesk_settings; hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` (`entity_id`, `entity_type`, diff --git a/inc/pipe_functions.inc.php b/inc/pipe_functions.inc.php index 4b92df4a..7a98f02d 100755 --- a/inc/pipe_functions.inc.php +++ b/inc/pipe_functions.inc.php @@ -269,7 +269,6 @@ function hesk_email2ticket($results, $pop3 = 0, $set_category = 1, $set_priority // Auto assign tickets if aplicable $tmpvar['owner'] = 0; - $tmpvar['history'] = $pop3 ? sprintf($hesklang['thist16'], hesk_date()) : sprintf($hesklang['thist11'], hesk_date()); $tmpvar['openedby'] = $pop3 ? -2 : -1; $autoassign_owner = hesk_autoAssignTicket($tmpvar['category']); @@ -278,7 +277,6 @@ function hesk_email2ticket($results, $pop3 = 0, $set_category = 1, $set_priority if ($autoassign_owner) { $tmpvar['owner'] = $autoassign_owner['id']; - $tmpvar['history'] .= sprintf($hesklang['thist10'], hesk_date(), $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')'); } // Custom fields will be empty as there is no reliable way of detecting them @@ -297,6 +295,13 @@ function hesk_email2ticket($results, $pop3 = 0, $set_category = 1, $set_priority // Insert ticket to database $ticket = hesk_newTicket($tmpvar); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', ($pop3 ? 'audit_submitted_via_pop' : 'audit_submitted_via_piping'), hesk_date()); + + if ($autoassign_owner) { + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(), + array(0 => $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')')); + } + // Notify the customer if ($hesk_settings['notify_new']) { $possible_SPAM = false; diff --git a/language/en/text.php b/language/en/text.php index 353988ab..a5dc2321 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -2204,12 +2204,12 @@ $hesklang['audit_created']='%s created ticket'; $hesklang['audit_priority']='%s changed priority to %s'; // %s = date,new priority, user making change, thist8 $hesklang['audit_status']='%s changed status to %s'; // %s = date, new status, user making change, thist9 $hesklang['audit_autoassigned']='%s automatically assigned to ticket'; //thist10 -$hesklang['audit_submitted_via_piping']='Ticket submitted via e-mail piping'; +$hesklang['audit_submitted_via_piping']='Ticket submitted via e-mail piping'; // thist11 $hesklang['audit_attachment_deleted']='%s deleted attachment %s'; // %s = date, deleted attachment, user making change $hesklang['audit_merged']='%s merged ticket %s with this ticket'; // %s = date, merged ticket ID, user making change, thist13 $hesklang['audit_time_worked']='%s updated time worked to %s'; // %s = date, new time worked, user making change $hesklang['audit_submitted_by']='%s submitted ticket'; -$hesklang['audit_submitted_via_pop']='Ticket submitted via POP3 fetching'; +$hesklang['audit_submitted_via_pop']='Ticket submitted via POP3 fetching'; // thist16 // DO NOT CHANGE BELOW if (!defined('IN_SCRIPT')) die('PHP syntax OK!'); From 62bda38b9178a7b6a791084db7d84be7a9a9c335 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Fri, 22 Sep 2017 13:07:35 -0400 Subject: [PATCH 11/19] Slowly started on displaying the new audit trail --- admin/admin_ticket.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/admin/admin_ticket.php b/admin/admin_ticket.php index 6a96fdf6..ab6df2e8 100644 --- a/admin/admin_ticket.php +++ b/admin/admin_ticket.php @@ -97,6 +97,17 @@ if (!$ticket['owner'] && !$can_view_unassigned) { hesk_error($hesklang['ycovtay']); } +// Get audit information +$auditRes = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` AS `audit` + LEFT JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail_to_replacement_values` AS `values` + ON `audit`.`id` = `values`.`audit_trail_id` + WHERE `entity_type` = 'TICKET' AND `entity_id` = " . intval($ticket['id'])); +$auditRecords = array(); +$lastAuditRecord = null; +while ($row = hesk_dbFetchAssoc($auditRes)) { + // TODO +} + /* Set last replier name */ if ($ticket['lastreplier']) { if (empty($ticket['repliername'])) { @@ -1611,7 +1622,7 @@ function print_form() } // End print_form() function mfh_print_message() { - global $ticket, $hesklang, $hesk_settings, $can_ban_emails, $can_ban_ips, $trackingID, $modsForHesk_settings; + global $ticket, $hesklang, $hesk_settings, $can_ban_emails, $can_ban_ips, $can_unban_emails, $can_unban_ips, $trackingID, $modsForHesk_settings; ?>
  • From 953747d90d8694c695b28f42a584f747c83e9c95 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Fri, 22 Sep 2017 18:29:14 -0400 Subject: [PATCH 12/19] Update composer lockfile --- api/composer.lock | 100 +++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/api/composer.lock b/api/composer.lock index c5a1a92d..130a7c7a 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -155,7 +155,7 @@ "docblock", "parser" ], - "time": "2017-07-22 11:08:38" + "time": "2017-07-22T11:08:38+00:00" }, { "name": "doctrine/cache", @@ -231,7 +231,7 @@ "cache", "caching" ], - "time": "2017-08-25 06:51:37" + "time": "2017-08-25T06:51:37+00:00" }, { "name": "doctrine/lexer", @@ -285,7 +285,7 @@ "lexer", "parser" ], - "time": "2017-07-24 09:37:08" + "time": "2017-07-24T09:37:08+00:00" }, { "name": "guzzlehttp/guzzle", @@ -401,7 +401,7 @@ "keywords": [ "promise" ], - "time": "2017-05-20 23:14:18" + "time": "2017-05-20T23:14:18+00:00" }, { "name": "guzzlehttp/psr7", @@ -466,7 +466,7 @@ "uri", "url" ], - "time": "2017-07-17 09:11:21" + "time": "2017-07-17T09:11:21+00:00" }, { "name": "mailgun/mailgun-php", @@ -765,7 +765,7 @@ "http", "httplug" ], - "time": "2017-08-05 15:50:10" + "time": "2017-08-05T15:50:10+00:00" }, { "name": "php-http/curl-client", @@ -829,12 +829,12 @@ "source": { "type": "git", "url": "https://github.com/php-http/discovery.git", - "reference": "7b50ab4d6c9fdaa1ed53ae310c955900af6e3372" + "reference": "d39a8798c473b6b896059a8de576598e4d17d992" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-http/discovery/zipball/7b50ab4d6c9fdaa1ed53ae310c955900af6e3372", - "reference": "7b50ab4d6c9fdaa1ed53ae310c955900af6e3372", + "url": "https://api.github.com/repos/php-http/discovery/zipball/d39a8798c473b6b896059a8de576598e4d17d992", + "reference": "d39a8798c473b6b896059a8de576598e4d17d992", "shasum": "" }, "require": { @@ -883,7 +883,7 @@ "message", "psr7" ], - "time": "2017-08-03 10:12:53" + "time": "2017-09-13T14:06:45+00:00" }, { "name": "php-http/guzzle6-adapter", @@ -943,7 +943,7 @@ "Guzzle", "http" ], - "time": "2017-05-29 15:06:15" + "time": "2017-05-29T15:06:15+00:00" }, { "name": "php-http/httplug", @@ -999,7 +999,7 @@ "client", "http" ], - "time": "2017-08-18 18:51:51" + "time": "2017-08-18T18:51:51+00:00" }, { "name": "php-http/message", @@ -1071,7 +1071,7 @@ "message", "psr-7" ], - "time": "2017-07-05 06:40:53" + "time": "2017-07-05T06:40:53+00:00" }, { "name": "php-http/message-factory", @@ -1121,7 +1121,7 @@ "stream", "uri" ], - "time": "2016-02-03 08:16:31" + "time": "2016-02-03T08:16:31+00:00" }, { "name": "php-http/multipart-stream-builder", @@ -1178,7 +1178,7 @@ "multipart stream", "stream" ], - "time": "2017-05-21 18:01:57" + "time": "2017-05-21T18:01:57+00:00" }, { "name": "php-http/promise", @@ -1228,7 +1228,7 @@ "keywords": [ "promise" ], - "time": "2016-01-28 07:54:12" + "time": "2016-01-28T07:54:12+00:00" }, { "name": "phpmailer/phpmailer", @@ -1354,7 +1354,7 @@ "container-interop", "psr" ], - "time": "2017-06-28 15:35:32" + "time": "2017-06-28T15:35:32+00:00" }, { "name": "psr/http-message", @@ -1404,7 +1404,7 @@ "request", "response" ], - "time": "2016-08-06 14:39:51" + "time": "2016-08-06T14:39:51+00:00" }, { "name": "symfony/options-resolver", @@ -1458,7 +1458,7 @@ "configuration", "options" ], - "time": "2017-08-03 09:34:20" + "time": "2017-08-03T09:34:20+00:00" }, { "name": "webmozart/assert", @@ -1508,7 +1508,7 @@ "check", "validate" ], - "time": "2016-11-23 20:04:41" + "time": "2016-11-23T20:04:41+00:00" }, { "name": "zendframework/zend-code", @@ -1614,7 +1614,7 @@ "events", "zf2" ], - "time": "2017-07-11 19:19:12" + "time": "2017-07-11T19:19:12+00:00" } ], "packages-dev": [ @@ -1624,23 +1624,21 @@ "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + "reference": "7af8066e48b8a4cbd90849bbe9234ab444057968" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/7af8066e48b8a4cbd90849bbe9234ab444057968", + "reference": "7af8066e48b8a4cbd90849bbe9234ab444057968", "shasum": "" }, "require": { "php": "^7.1" }, "require-dev": { - "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" + "phpunit/phpunit": "^6.2.3" }, "type": "library", "extra": { @@ -1670,7 +1668,7 @@ "constructor", "instantiate" ], - "time": "2017-07-22 11:58:36" + "time": "2017-09-19T12:41:22+00:00" }, { "name": "myclabs/deep-copy", @@ -1712,7 +1710,7 @@ "object", "object graph" ], - "time": "2017-04-12 18:52:22" + "time": "2017-04-12T18:52:22+00:00" }, { "name": "phar-io/manifest", @@ -1767,7 +1765,7 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-04-07 07:07:10" + "time": "2017-04-07T07:07:10+00:00" }, { "name": "phar-io/version", @@ -1822,12 +1820,12 @@ "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "a046af61c36e9162372f205de091a1cab7340f1c" + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/a046af61c36e9162372f205de091a1cab7340f1c", - "reference": "a046af61c36e9162372f205de091a1cab7340f1c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", "shasum": "" }, "require": { @@ -1868,7 +1866,7 @@ "reflection", "static analysis" ], - "time": "2017-04-30 11:58:12" + "time": "2017-09-11T18:02:19+00:00" }, { "name": "phpdocumentor/reflection-docblock", @@ -2023,7 +2021,7 @@ "spy", "stub" ], - "time": "2017-09-04 11:05:03" + "time": "2017-09-04T11:05:03+00:00" }, { "name": "phpunit/php-code-coverage", @@ -2087,7 +2085,7 @@ "testing", "xunit" ], - "time": "2017-08-25 06:32:04" + "time": "2017-08-25T06:32:04+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2134,7 +2132,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03 07:40:28" + "time": "2016-10-03T07:40:28+00:00" }, { "name": "phpunit/php-text-template", @@ -2224,7 +2222,7 @@ "keywords": [ "timer" ], - "time": "2017-03-07 15:42:04" + "time": "2017-03-07T15:42:04+00:00" }, { "name": "phpunit/php-token-stream", @@ -2273,7 +2271,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-08-20 05:47:52" + "time": "2017-08-20T05:47:52+00:00" }, { "name": "phpunit/phpunit", @@ -2416,7 +2414,7 @@ "mock", "xunit" ], - "time": "2017-08-03 14:08:16" + "time": "2017-08-03T14:08:16+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -2461,7 +2459,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04 10:23:55" + "time": "2017-03-04T10:23:55+00:00" }, { "name": "sebastian/comparator", @@ -2525,7 +2523,7 @@ "compare", "equality" ], - "time": "2017-08-20 14:03:32" + "time": "2017-08-20T14:03:32+00:00" }, { "name": "sebastian/diff", @@ -2577,7 +2575,7 @@ "keywords": [ "diff" ], - "time": "2017-08-03 08:09:46" + "time": "2017-08-03T08:09:46+00:00" }, { "name": "sebastian/environment", @@ -2627,7 +2625,7 @@ "environment", "hhvm" ], - "time": "2017-07-01 08:51:00" + "time": "2017-07-01T08:51:00+00:00" }, { "name": "sebastian/exporter", @@ -2694,7 +2692,7 @@ "export", "exporter" ], - "time": "2017-04-03 13:19:02" + "time": "2017-04-03T13:19:02+00:00" }, { "name": "sebastian/global-state", @@ -2745,7 +2743,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27 15:39:26" + "time": "2017-04-27T15:39:26+00:00" }, { "name": "sebastian/object-enumerator", @@ -2792,7 +2790,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03 12:35:26" + "time": "2017-08-03T12:35:26+00:00" }, { "name": "sebastian/object-reflector", @@ -2837,7 +2835,7 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29 09:07:27" + "time": "2017-03-29T09:07:27+00:00" }, { "name": "sebastian/recursion-context", @@ -2890,7 +2888,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-07 15:09:59" + "time": "2017-03-07T15:09:59+00:00" }, { "name": "sebastian/resource-operations", @@ -2932,7 +2930,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2016-10-03 07:43:09" + "time": "2016-10-03T07:43:09+00:00" }, { "name": "sebastian/version", @@ -2975,7 +2973,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03 07:35:21" + "time": "2016-10-03T07:35:21+00:00" }, { "name": "theseer/tokenizer", From 0ac67766ee3a85018652117abc6e23bf32ff35d2 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Fri, 22 Sep 2017 22:24:27 -0400 Subject: [PATCH 13/19] New audit trail now appears on the ticket page --- admin/admin_ticket.php | 277 +++++++++++++++++++++++++++++--------- admin/move_category.php | 1 - css/mods-for-hesk-new.css | 5 + 3 files changed, 217 insertions(+), 66 deletions(-) diff --git a/admin/admin_ticket.php b/admin/admin_ticket.php index ab6df2e8..f2e74a12 100644 --- a/admin/admin_ticket.php +++ b/admin/admin_ticket.php @@ -98,14 +98,34 @@ if (!$ticket['owner'] && !$can_view_unassigned) { } // Get audit information -$auditRes = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` AS `audit` +$audit_sort = $hesk_settings['new_top'] ? "ASC" : "DESC"; +$auditRes = hesk_dbQuery("SELECT `audit`.`id`, `audit`.`language_key`, `audit`.`date`, + `values`.`replacement_index`, `values`.`replacement_value` + FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` AS `audit` LEFT JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail_to_replacement_values` AS `values` ON `audit`.`id` = `values`.`audit_trail_id` - WHERE `entity_type` = 'TICKET' AND `entity_id` = " . intval($ticket['id'])); -$auditRecords = array(); -$lastAuditRecord = null; + WHERE `entity_type` = 'TICKET' AND `entity_id` = " . intval($ticket['id']) . " + ORDER BY `audit`.`date` {$audit_sort}"); +$audit_records = array(); +$current_audit_record = null; while ($row = hesk_dbFetchAssoc($auditRes)) { - // TODO + if ($current_audit_record == null || $current_audit_record['id'] != $row['id']) { + if ($current_audit_record != null) { + $audit_records[] = $current_audit_record; + } + $current_audit_record['id'] = $row['id']; + $current_audit_record['language_key'] = $row['language_key']; + $current_audit_record['date'] = $row['date']; + $current_audit_record['replacement_values'] = array(); + } + + if ($row['replacement_index'] != null) { + $current_audit_record['replacement_values'][intval($row['replacement_index'])] = $row['replacement_value']; + } +} + +if ($current_audit_record != null) { + $audit_records[] = $current_audit_record; } /* Set last replier name */ @@ -1783,7 +1803,38 @@ function mfh_print_message() { function hesk_printTicketReplies() { - global $hesklang, $hesk_settings, $result, $reply; + global $hesklang, $hesk_settings, $result, $reply, $audit_records; + + // Sort replies and audit messages. They'll be in the proper order already + $combined_records = array(); + foreach ($audit_records as $audit_record) { + $audit_record['SORT_TYPE'] = 'AUDIT_RECORD'; + $combined_records[] = $audit_record; + } + while ($reply = hesk_dbFetchAssoc($result)) { + $reply['SORT_TYPE'] = 'REPLY'; + $combined_records[] = $reply; + } + + // Re-sort them so they're in order by date + usort($combined_records, function ($a, $b) { + $a_date = null; + $b_date = null; + if ($a['SORT_TYPE'] == 'REPLY') { + $a_date = strtotime($a['dt']); + } else { + $a_date = strtotime($a['date']); + } + + if ($b['SORT_TYPE'] == 'REPLY') { + $b_date = strtotime($b['dt']); + } else { + $b_date = strtotime($b['date']); + } + + return $a_date - $b_date; + }); + echo '
      '; if (!$hesk_settings['new_top']) { @@ -1792,78 +1843,174 @@ function hesk_printTicketReplies() echo '
    • '; } - while ($reply = hesk_dbFetchAssoc($result)) { - $reply['dt'] = hesk_date($reply['dt'], true); - ?> -
    • - - - - - -
      - -

      -
      -
      -
      - -
      -
      - -
      + foreach ($combined_records as $record) { + if ($record['SORT_TYPE'] == 'REPLY') { + mfh_print_reply($record); + } else { + mfh_print_audit_record($record); + } + } + + if ($hesk_settings['new_top']) { + mfh_print_message(); + } else { + echo '
    • '; + } + echo '
    '; + + return; + +} // End hesk_printTicketReplies() + +function mfh_print_reply($reply) { + global $hesklang, $hesk_settings; + + $reply['dt'] = hesk_date($reply['dt'], true); + ?> +
  • + + + + + +
    + +

    +
    +
    +
    + +
    +
    +
    - + - -
  • - + + '; - } - echo ''; +function mfh_print_audit_record($record) { + global $hesklang; - return; + $record['date'] = hesk_date($record['date'], true); + $font_icon = null; + switch ($record['language_key']) { + case 'audit_moved_category': + $font_icon = 'fa-pie-chart'; + break; + case 'audit_assigned': + case 'audit_assigned_self': + $font_icon = 'fa-user-plus'; + break; + case 'audit_unassigned': + $font_icon = 'fa-user-minus'; + break; + case 'audit_autoassigned': + $font_icon = 'fa-bolt'; + break; + case 'audit_closed': + case 'audit_automatically_closed': + $font_icon = 'fa-check-circle'; + break; + case 'audit_opened': + $font_icon = 'fa-circle-o'; + break; + case 'audit_locked': + case 'audit_automatically_locked': + $font_icon = 'fa-lock'; + break; + case 'audit_unlocked': + $font_icon = 'fa-unlock-alt'; + break; + case 'audit_created': + case 'audit_submitted_by': + $font_icon = 'fa-user'; + break; + case 'audit_priority': + // The new priority is in arg[1] + $priority = $record['replacement_values'][1]; + if ($priority === 'critical') { + $font_icon = 'fa-long-arrow-up'; + } elseif ($priority === 'high') { + $font_icon = 'fa-angle-double-up'; + } elseif ($priority === 'medium') { + $font_icon = 'fa-angle-double-down'; + } else { + $font_icon = 'fa-long-arrow-down'; + } -} // End hesk_printTicketReplies() + // Now localize the text for display + $record['replacement_values'][1] = $hesklang[$priority]; + break; + case 'audit_status': + $font_icon = 'fa-exchange'; + break; + case 'audit_submitted_via_piping': + case 'audit_submitted_via_pop': + $font_icon = 'fa-envelope-o'; + break; + case 'audit_attachment_deleted': + $font_icon = 'fa-paperclip'; + break; + case 'audit_merged': + $font_icon = 'fa-code-fork'; + break; + case 'audit_time_worked': + $font_icon = 'fa-clock'; + break; + default: + $font_icon = 'fa-question-circle'; + break; + } + ?> +
  • + +
    + +

    + +

    +
    +
  • + $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', 1 => $row['name'] diff --git a/css/mods-for-hesk-new.css b/css/mods-for-hesk-new.css index 756fd12c..56ddeb91 100644 --- a/css/mods-for-hesk-new.css +++ b/css/mods-for-hesk-new.css @@ -350,4 +350,9 @@ div.ticket-info { border-color: #3c8dbc; box-shadow: none; outline: 0; +} + +.timeline-header.audit-record { + font-size: 12px !important; + } \ No newline at end of file From 44ab91829204259d7ea7ffb344b6a52e2f9b25a2 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sat, 23 Sep 2017 22:02:29 -0400 Subject: [PATCH 14/19] Make sure ticket is updated before adding audit record to make sure it appears in the right order --- admin/admin_reply_ticket.php | 47 +++++++++++++++++++++++++++--------- admin/admin_ticket.php | 12 ++++----- admin/assign_owner.php | 8 +++--- admin/change_status.php | 39 ++++++++++++++++++++++++------ admin/delete_tickets.php | 11 +++++---- admin/lock.php | 19 ++++++++++++--- admin/move_category.php | 21 ++++++++++------ admin/priority.php | 7 +++--- 8 files changed, 114 insertions(+), 50 deletions(-) diff --git a/admin/admin_reply_ticket.php b/admin/admin_reply_ticket.php index 7abe3b11..3ade28b2 100644 --- a/admin/admin_reply_ticket.php +++ b/admin/admin_reply_ticket.php @@ -198,6 +198,11 @@ if ($submit_as_customer) { $revision = ''; /* Change the status of priority? */ +$audit_priority = null; +$audit_closed = null; +$audit_status = null; +$audit_customer_status = null; +$audit_assigned_self = null; if (!empty($_POST['set_priority'])) { $priority = intval(hesk_POST('priority')); if ($priority < 0 || $priority > 3) { @@ -220,9 +225,8 @@ if (!empty($_POST['set_priority'])) { $priority_sql = ",`priority`='$priority' "; - mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_priority', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', - 1 => $plain_options[$priority])); + $audit_priority = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $plain_options[$priority]); } else { $priority_sql = ""; } @@ -247,7 +251,7 @@ if ($ticket['locked']) { $newStatus = hesk_dbFetchAssoc($newStatusRs); if ($newStatus['IsClosed'] && hesk_checkPermission('can_resolve', 0)) { - mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_closed', hesk_date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $audit_closed = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); $sql_status = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " "; // Lock the ticket if customers are not allowed to reopen tickets @@ -256,9 +260,8 @@ if ($ticket['locked']) { } } else { // Ticket isn't being closed, just add the history to the sql query (or tried to close but doesn't have permission) - mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_status', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', - 1 => mfh_getDisplayTextForStatusId($new_status))); + $audit_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => mfh_getDisplayTextForStatusId($new_status)); } } } // -> Submit as Customer reply @@ -269,9 +272,8 @@ elseif ($submit_as_customer) { $new_status = $customerReplyStatus['ID']; if ($ticket['status'] != $new_status) { - mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_status', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', - 1 => mfh_getDisplayTextForStatusId($new_status))); + $audit_customer_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => mfh_getDisplayTextForStatusId($new_status)); } } // -> Default: submit as "Replied by staff" else { @@ -293,7 +295,7 @@ if ($time_worked == '00:00:00') { } if (!empty($_POST['assign_self']) && (hesk_checkPermission('can_assign_self', 0) || (isset($_REQUEST['isManager']) && $_REQUEST['isManager']))) { - mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_assigned_self', hesk_date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $audit_assigned_self = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); $sql .= " , `owner`=" . intval($_SESSION['id']) . " "; } @@ -317,6 +319,29 @@ unset($sql); /* Update number of replies in the users table */ hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` SET `replies`=`replies`+1 WHERE `id`='" . intval($_SESSION['id']) . "'"); +//-- Insert necessary audit trail records +if ($audit_priority != null) { + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_priority', hesk_date(), $audit_priority); +} + +if ($audit_closed != null) { + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_closed', hesk_date(), $audit_closed); +} + +if ($audit_status != null) { + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_status', hesk_date(), $audit_status); +} + +if ($audit_customer_status != null) { + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_status', hesk_date(), + $audit_customer_status); +} + +if ($audit_assigned_self != null) { + mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_assigned_self', hesk_date(), $audit_assigned_self); +} + + // --> Prepare reply message // 1. Generate the array with ticket info that can be used in emails diff --git a/admin/admin_ticket.php b/admin/admin_ticket.php index f2e74a12..a587f42f 100644 --- a/admin/admin_ticket.php +++ b/admin/admin_ticket.php @@ -470,11 +470,10 @@ if ($hesk_settings['time_worked'] && ($can_reply || $can_edit) && isset($_POST[' $time_worked = hesk_getTime($h . ':' . $m . ':' . $s); /* Update database */ - //audit_time_worked who - value + hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `time_worked`='" . hesk_dbEscape($time_worked) . "' WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_time_worked', hesk_date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', - 1 => $time_worked)); - hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `time_worked`='" . hesk_dbEscape($time_worked) . "' WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); + 1 => $time_worked)); /* Show ticket */ hesk_process_messages($hesklang['twu'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS'); @@ -562,10 +561,6 @@ if (isset($_GET['delatt']) && hesk_token_check()) { hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "'"); /* Update ticket or reply in the database */ - // audit_attachment_deleted - mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_attachment_deleted', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', - 1 => $att['real_name'])); if ($reply) { hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` SET `attachments`=REPLACE(`attachments`,'" . hesk_dbEscape($att_id . '#' . $att['real_name'] . '#' . $att['saved_name']) . ",','') WHERE `id`='" . intval($reply) . "'"); hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `id`='" . intval($ticket['id']) . "'"); @@ -576,6 +571,9 @@ if (isset($_GET['delatt']) && hesk_token_check()) { hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `attachments`=REPLACE(`attachments`,'" . hesk_dbEscape($att_id . '#' . $att['real_name'] . '#' . $att['saved_name']) . ",','') WHERE `id`='" . intval($ticket['id']) . "'"); hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `attachments`=REPLACE(`attachments`,'" . hesk_dbEscape($att_id . '#' . $att['real_name']) . ",',''), `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `id`='" . intval($ticket['id']) . "'"); } + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_attachment_deleted', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $att['real_name'])); hesk_process_messages($hesklang['kb_att_rem'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS'); } diff --git a/admin/assign_owner.php b/admin/assign_owner.php index a52c3fc9..9afc5df7 100755 --- a/admin/assign_owner.php +++ b/admin/assign_owner.php @@ -52,9 +52,9 @@ $owner = intval(hesk_REQUEST('owner')); /* If ID is -1 the ticket will be unassigned */ if ($owner == -1) { + $res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0 WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unassigned', date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); - $res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0 WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); hesk_process_messages($hesklang['tunasi2'], $_SERVER['PHP_SELF'], 'SUCCESS'); } elseif ($owner < 1) { @@ -97,6 +97,8 @@ if ($ticket['owner'] && $ticket['owner'] != $owner && hesk_REQUEST('unassigned') /* Assigning to self? */ if ($can_assign_others || ($owner == $_SESSION['id'] && $can_assign_self)) { + $res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`={$owner} WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); + if ($owner == $_SESSION['id'] && $can_assign_self) { mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_assigned_self', hesk_date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); @@ -104,11 +106,9 @@ if ($can_assign_others || ($owner == $_SESSION['id'] && $can_assign_self)) { // current user -> assigned user mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_assigned', hesk_date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', - 1 => $row['name'] . ' (' . $row['user'] . ')')); + 1 => $row['name'] . ' (' . $row['user'] . ')')); } - $res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`={$owner} WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); - if ($owner != $_SESSION['id'] && !hesk_checkPermission('can_view_ass_others', 0)) { $_SERVER['PHP_SELF'] = 'admin_main.php'; } diff --git a/admin/change_status.php b/admin/change_status.php index 63c30832..9a7bfb74 100644 --- a/admin/change_status.php +++ b/admin/change_status.php @@ -58,6 +58,11 @@ if (!isset($status_options[$status])) { $locked = 0; +$audit_closed = null; +$audit_locked = null; +$audit_status = null; +$audit_opened = null; + $statusRow = hesk_dbFetchAssoc(hesk_dbQuery("SELECT `ID`, `IsClosed` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` WHERE ID = " . $status)); if ($statusRow['IsClosed']) // Closed { @@ -66,13 +71,12 @@ if ($statusRow['IsClosed']) // Closed } $action = $hesklang['ticket_been'] . ' ' . $hesklang['close']; - mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_closed', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $audit_closed = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); if ($hesk_settings['custopen'] != 1) { $locked = 1; - mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_automatically_locked', hesk_date(), array()); + $audit_locked = array(); } // Notify customer of closed ticket? @@ -98,17 +102,16 @@ if ($statusRow['IsClosed']) // Closed } elseif ($statusRow['IsNewTicketStatus'] == 0) //Ticket is still open, but not new { $action = sprintf($hesklang['tsst'], $status_options[$status]); - mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_status', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', - 1 => $status_options[$status])); + $audit_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $status_options[$status]); + // Ticket is not resolved $closedby_sql = ' , `closedat`=NULL, `closedby`=NULL '; } else // Ticket is marked as "NEW" { $action = $hesklang['ticket_been'] . ' ' . $hesklang['opened']; - mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_opened', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $audit_opened = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); // Ticket is not resolved $closedby_sql = ' , `closedat`=NULL, `closedby`=NULL '; @@ -117,6 +120,26 @@ if ($statusRow['IsClosed']) // Closed hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='{$status}', `locked`='{$locked}' $closedby_sql WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); +if ($audit_closed != null) { + mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_closed', hesk_date(), + $audit_closed); +} + +if ($audit_locked != null) { + mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_automatically_locked', hesk_date(), + array()); +} + +if ($audit_status != null) { + mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_status', hesk_date(), + $audit_status); +} + +if ($audit_opened != null) { + mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_opened', hesk_date(), + $audit_opened); +} + if (hesk_dbAffectedRows() != 1) { hesk_error("$hesklang[int_error]: $hesklang[trackID_not_found]."); } diff --git a/admin/delete_tickets.php b/admin/delete_tickets.php index 8a654873..45a7eaac 100644 --- a/admin/delete_tickets.php +++ b/admin/delete_tickets.php @@ -113,10 +113,10 @@ if (array_key_exists($_POST['a'], $priorities)) { hesk_okCategory($ticket['category']); + hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `priority`='{$priority['value']}' WHERE `id`={$this_id}"); mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_priority', hesk_date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', - 1 => $priority['lang'])); - hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `priority`='{$priority['value']}' WHERE `id`={$this_id}"); + 1 => $priority['lang'])); $i++; } @@ -222,9 +222,6 @@ else { hesk_token_check('POST'); require(HESK_PATH . 'inc/email_functions.inc.php'); - mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_closed', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); - foreach ($_POST['id'] as $this_id) { if (is_array($this_id)) { continue; @@ -241,6 +238,10 @@ else { $closedStatus = hesk_dbFetchAssoc($closedStatusRS); hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='" . $closedStatus['ID'] . "', `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " WHERE `id`='" . intval($this_id) . "'"); + + mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_closed', hesk_date(), + array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $i++; // Notify customer of closed ticket? diff --git a/admin/lock.php b/admin/lock.php index 71591724..ec1836db 100644 --- a/admin/lock.php +++ b/admin/lock.php @@ -45,18 +45,19 @@ if (hesk_dbNumRows($result) != 1) { } $ticket = hesk_dbFetchAssoc($result); +$audit_unlocked = null; +$audit_locked = null; + /* New locked status */ if (empty($_GET['locked'])) { $status = 0; $tmp = $hesklang['tunlock']; - mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unlocked', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $audit_unlocked = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); $closedby_sql = ' , `closedat`=NULL, `closedby`=NULL '; } else { $status = 1; $tmp = $hesklang['tlock']; - mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_locked', hesk_date(), - array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); + $audit_locked = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); $closedby_sql = ' , `closedat`=NOW(), `closedby`=' . intval($_SESSION['id']) . ' '; // Notify customer of closed ticket? @@ -87,5 +88,15 @@ $statusId = $statusRow['ID']; hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`= {$statusId},`locked`='{$status}' $closedby_sql WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); +if ($audit_unlocked) { + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unlocked', hesk_date(), + $audit_unlocked); +} + +if ($audit_locked) { + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_locked', hesk_date(), + $audit_locked); +} + /* Back to ticket page and show a success message */ hesk_process_messages($tmp, 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . rand(10000, 99999), 'SUCCESS'); \ No newline at end of file diff --git a/admin/move_category.php b/admin/move_category.php index 965bbab5..35971e02 100755 --- a/admin/move_category.php +++ b/admin/move_category.php @@ -70,11 +70,6 @@ if (hesk_dbNumRows($res) != 1) { } $ticket = hesk_dbFetchAssoc($res); -/* Log that ticket is being moved */ -mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_moved_category', hesk_date(), array( - 0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', - 1 => $row['name'] -)); /* Is the ticket assigned to someone? If yes, check that the user has access to category or change to unassigned */ $need_to_reassign = 0; @@ -95,14 +90,12 @@ if ($ticket['owner']) { } /* Reassign automatically if possible */ +$autoassign_owner = null; if ($need_to_reassign || !$ticket['owner']) { $need_to_reassign = 1; $autoassign_owner = hesk_autoAssignTicket($category); if ($autoassign_owner) { $ticket['owner'] = $autoassign_owner['id']; - mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(), array( - 0 => $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')' - )); } else { $ticket['owner'] = 0; } @@ -110,6 +103,18 @@ if ($need_to_reassign || !$ticket['owner']) { hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `category`='" . intval($category) . "', `owner`='" . intval($ticket['owner']) . "' WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); +/* Log that ticket is being moved */ +mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_moved_category', hesk_date(), array( + 0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $row['name'] +)); + +if ($autoassign_owner) { + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(), array( + 0 => $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')' + )); +} + $ticket['category'] = $category; /* --> Prepare message */ diff --git a/admin/priority.php b/admin/priority.php index b2fe75e5..ac86750f 100644 --- a/admin/priority.php +++ b/admin/priority.php @@ -57,12 +57,13 @@ $plain_options = array( $ticketRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid` = '" . hesk_dbEscape($trackingID) . "'"); $ticket = hesk_dbFetchAssoc($ticketRs); +hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `priority`='{$priority}' WHERE `trackid`='".hesk_dbEscape($trackingID)."'"); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_priority', hesk_date(), array( - 0 => $_SESSION['name'].' ('.$_SESSION['user'].')', - 1 => $plain_options[$priority] + 0 => $_SESSION['name'].' ('.$_SESSION['user'].')', + 1 => $plain_options[$priority] )); -hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `priority`='{$priority}' WHERE `trackid`='".hesk_dbEscape($trackingID)."'"); if (hesk_dbAffectedRows() != 1) { hesk_process_messages($hesklang['inpr'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'NOTICE'); From 0670d74c1eb28c9711785ceba5fd14f5c2fc0fb0 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sun, 24 Sep 2017 22:07:49 -0400 Subject: [PATCH 15/19] Pretty much wrapped up with the new ticket history --- admin/admin_reply_ticket.php | 7 ++++-- admin/admin_ticket.php | 38 +++++++++++++++++++++++++++++-- admin/assign_owner.php | 2 +- admin/change_status.php | 18 ++++++++------- admin/index.php | 36 +++++++++++++++-------------- css/mods-for-hesk-new.css | 6 ++--- internal-api/dao/calendar_dao.php | 13 +++++++++++ language/en/text.php | 4 ++++ 8 files changed, 91 insertions(+), 33 deletions(-) diff --git a/admin/admin_reply_ticket.php b/admin/admin_reply_ticket.php index 3ade28b2..29a0d5c8 100644 --- a/admin/admin_reply_ticket.php +++ b/admin/admin_reply_ticket.php @@ -189,9 +189,9 @@ if ($hesk_settings['attachments']['use'] && !empty($attachments)) { // Add reply $html = $modsForHesk_settings['rich_text_for_tickets']; if ($submit_as_customer) { - hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`,`html`) VALUES ('" . intval($replyto) . "','" . hesk_dbEscape(addslashes($ticket['name'])) . "','" . hesk_dbEscape($message . "

    {$hesklang['creb']} {$_SESSION['name']}") . "',NOW(),'" . hesk_dbEscape($myattachments) . "', '" . $html . "')"); + hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`,`html`) VALUES ('" . intval($replyto) . "','" . hesk_dbEscape(addslashes($ticket['name'])) . "','" . hesk_dbEscape($message . "

    {$hesklang['creb']} {$_SESSION['name']}") . "','" . hesk_dbEscape(hesk_date()) . "','" . hesk_dbEscape($myattachments) . "', '" . $html . "')"); } else { - hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`,`staffid`,`html`) VALUES ('" . intval($replyto) . "','" . hesk_dbEscape(addslashes($_SESSION['name'])) . "','" . hesk_dbEscape($message) . "',NOW(),'" . hesk_dbEscape($myattachments) . "','" . intval($_SESSION['id']) . "', '" . $html . "')"); + hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`,`staffid`,`html`) VALUES ('" . intval($replyto) . "','" . hesk_dbEscape(addslashes($_SESSION['name'])) . "','" . hesk_dbEscape($message) . "','" . hesk_dbEscape(hesk_date()) . "','" . hesk_dbEscape($myattachments) . "','" . intval($_SESSION['id']) . "', '" . $html . "')"); } /* Track ticket status changes for history */ @@ -252,6 +252,9 @@ if ($ticket['locked']) { if ($newStatus['IsClosed'] && hesk_checkPermission('can_resolve', 0)) { $audit_closed = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + $audit_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => mfh_getDisplayTextForStatusId($new_status) + ); $sql_status = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " "; // Lock the ticket if customers are not allowed to reopen tickets diff --git a/admin/admin_ticket.php b/admin/admin_ticket.php index a587f42f..d17ee27b 100644 --- a/admin/admin_ticket.php +++ b/admin/admin_ticket.php @@ -509,13 +509,26 @@ if (($can_reply || $can_edit) && isset($_POST['childTrackingId'])) { } hesk_dbQuery('UPDATE `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` SET `parent` = ' . intval($ticket['id']) . ' WHERE `trackid` = \'' . hesk_dbEscape(hesk_POST('childTrackingId')) . '\''); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_linked_ticket', hesk_date(), + array( + 0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => hesk_POST('childTrackingId') + )); hesk_process_messages(sprintf($hesklang['link_added'], $_POST['childTrackingId']), 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS'); } /* Delete child action */ if (($can_reply || $can_edit) && isset($_GET['deleteChild'])) { //-- Delete the relationship + $innerTrackingRs = hesk_dbQuery("SELECT `trackid` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `id` = " . hesk_dbEscape($_GET['deleteChild'])); + $innerTrackingId = hesk_dbFetchAssoc($innerTrackingRs); + hesk_dbQuery('UPDATE `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` SET `parent` = NULL WHERE `ID` = ' . hesk_dbEscape($_GET['deleteChild'])); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unlinked_ticket', hesk_date(), + array( + 0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $innerTrackingId['trackid'] + )); hesk_process_messages($hesklang['ticket_no_longer_linked'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS'); } elseif (($can_reply || $can_edit) && isset($_GET['deleteParent'])) { @@ -1830,6 +1843,12 @@ function hesk_printTicketReplies() $b_date = strtotime($b['date']); } + if ($a_date === $b_date && $a['SORT_TYPE'] != $b['SORT_TYPE']) { + if ($a['SORT_TYPE'] != $b['SORT_TYPE']) { + return $a['SORT_TYPE'] == 'REPLY' ? -1 : 1; + } + } + return $a_date - $b_date; }); @@ -1938,7 +1957,7 @@ function mfh_print_audit_record($record) { $font_icon = 'fa-user-plus'; break; case 'audit_unassigned': - $font_icon = 'fa-user-minus'; + $font_icon = 'fa-user-times'; break; case 'audit_autoassigned': $font_icon = 'fa-bolt'; @@ -1991,7 +2010,22 @@ function mfh_print_audit_record($record) { $font_icon = 'fa-code-fork'; break; case 'audit_time_worked': - $font_icon = 'fa-clock'; + $font_icon = 'fa fa-clock-o'; + break; + case 'audit_due_date_removed': + $font_icon = 'fa fa-calendar-minus-o'; + break; + case 'audit_due_date_changed': + $font_icon = 'fa fa-calendar'; + + //-- Format the date + $record['replacement_values'][1] = date('Y-m-d', strtotime($record['replacement_values'][1])); + break; + case 'audit_linked_ticket': + $font_icon = 'fa fa-link'; + break; + case 'audit_unlinked_ticket': + $font_icon = 'fa fa-chain-broken'; break; default: $font_icon = 'fa-question-circle'; diff --git a/admin/assign_owner.php b/admin/assign_owner.php index 9afc5df7..e875b2a5 100755 --- a/admin/assign_owner.php +++ b/admin/assign_owner.php @@ -53,7 +53,7 @@ $owner = intval(hesk_REQUEST('owner')); /* If ID is -1 the ticket will be unassigned */ if ($owner == -1) { $res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0 WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); - mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unassigned', date(), + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unassigned', hesk_date(), array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')')); hesk_process_messages($hesklang['tunasi2'], $_SERVER['PHP_SELF'], 'SUCCESS'); diff --git a/admin/change_status.php b/admin/change_status.php index 9a7bfb74..cc3f1fa7 100644 --- a/admin/change_status.php +++ b/admin/change_status.php @@ -72,6 +72,8 @@ if ($statusRow['IsClosed']) // Closed $action = $hesklang['ticket_been'] . ' ' . $hesklang['close']; $audit_closed = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); + $audit_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => $status_options[$status]); if ($hesk_settings['custopen'] != 1) { @@ -120,22 +122,22 @@ if ($statusRow['IsClosed']) // Closed hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='{$status}', `locked`='{$locked}' $closedby_sql WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'"); -if ($audit_closed != null) { +if ($audit_status !== null) { + mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_status', hesk_date(), + $audit_status); +} + +if ($audit_closed !== null) { mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_closed', hesk_date(), $audit_closed); } -if ($audit_locked != null) { +if ($audit_locked !== null) { mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_automatically_locked', hesk_date(), array()); } -if ($audit_status != null) { - mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_status', hesk_date(), - $audit_status); -} - -if ($audit_opened != null) { +if ($audit_opened !== null) { mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_opened', hesk_date(), $audit_opened); } diff --git a/admin/index.php b/admin/index.php index b822ed29..ba7c4b00 100644 --- a/admin/index.php +++ b/admin/index.php @@ -209,23 +209,25 @@ function do_login() $closedStatus = hesk_dbFetchAssoc($closedStatusRs); // Are we allowed to close tickets in this status? if ($closedStatus['Closable'] == 'yes' || $closedStatus['Closable'] == 'sonly') { - // Notify customer of closed ticket? - if ($hesk_settings['notify_closed']) { - // Get list of tickets - $result = hesk_dbQuery("SELECT * FROM `" . $hesk_settings['db_pfix'] . "tickets` WHERE `status` = " . $closedStatus['ID'] . " AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); - if (hesk_dbNumRows($result) > 0) { - global $ticket; - - // Load required functions? - if (!function_exists('hesk_notifyCustomer')) { - require(HESK_PATH . 'inc/email_functions.inc.php'); - } - while ($ticket = hesk_dbFetchAssoc($result)) { - $ticket['dt'] = hesk_date($ticket['dt'], true); - $ticket['lastchange'] = hesk_date($ticket['lastchange'], true); - $ticket = hesk_ticketToPlain($ticket, 1, 0); - mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_automatically_closed', hesk_date(), array()); + $result = hesk_dbQuery("SELECT * FROM `" . $hesk_settings['db_pfix'] . "tickets` WHERE `status` = " . $closedStatus['ID'] . " AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); + if (hesk_dbNumRows($result) > 0) { + global $ticket; + + // Load required functions? + if (!function_exists('hesk_notifyCustomer')) { + require(HESK_PATH . 'inc/email_functions.inc.php'); + } + + while ($ticket = hesk_dbFetchAssoc($result)) { + $ticket['dt'] = hesk_date($ticket['dt'], true); + $ticket['lastchange'] = hesk_date($ticket['lastchange'], true); + $ticket = hesk_ticketToPlain($ticket, 1, 0); + mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_automatically_closed', hesk_date(), array()); + + // Notify customer of closed ticket? + if ($hesk_settings['notify_closed']) { + // Get list of tickets hesk_notifyCustomer($modsForHesk_settings, 'ticket_closed'); } } @@ -234,7 +236,7 @@ function do_login() // Update ticket statuses and history in database if we're allowed to do so $defaultCloseRs = hesk_dbQuery('SELECT `ID` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `IsAutocloseOption` = 1'); $defaultCloseStatus = hesk_dbFetchAssoc($defaultCloseRs); - hesk_dbQuery("UPDATE `" . $hesk_settings['db_pfix'] . "tickets` SET `status`=" . intval($defaultCloseStatus['ID']) . ", `closedat`=NOW(), `closedby`='-1' WHERE `status` = '" . $closedStatus['ID'] . "' AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); + hesk_dbQuery("UPDATE `" . $hesk_settings['db_pfix'] . "tickets` SET `status`=" . intval($defaultCloseStatus['ID']) . ", `closedat`=NOW(), `closedby`='-1' WHERE `status` = " . $closedStatus['ID'] . " AND `lastchange` <= '" . hesk_dbEscape($dt) . "' "); } } diff --git a/css/mods-for-hesk-new.css b/css/mods-for-hesk-new.css index 56ddeb91..d1dec79a 100644 --- a/css/mods-for-hesk-new.css +++ b/css/mods-for-hesk-new.css @@ -352,7 +352,7 @@ div.ticket-info { outline: 0; } -.timeline-header.audit-record { - font-size: 12px !important; - +.timeline > li > .timeline-item > .timeline-header.audit-record { + font-size: 12px; + border-bottom: none; } \ No newline at end of file diff --git a/internal-api/dao/calendar_dao.php b/internal-api/dao/calendar_dao.php index 9c87e458..a3f15d98 100644 --- a/internal-api/dao/calendar_dao.php +++ b/internal-api/dao/calendar_dao.php @@ -194,12 +194,25 @@ function delete_event($id, $hesk_settings) { } function update_ticket_due_date($ticket, $hesk_settings) { + $ticket_id_rs = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid` = '" . hesk_dbEscape($ticket['trackid']) . "'"); + $ticket_id = hesk_dbFetchAssoc($ticket_id_rs); + $due_date = 'NULL'; + $language_key = 'audit_due_date_removed'; + $audit_array = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'); if ($ticket['due_date'] != NULL) { + $audit_array = array( + 0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', + 1 => date('Y-m-d H:i:s', strtotime($ticket['due_date'])) + ); $due_date = "'" . date('Y-m-d H:i:s', strtotime($ticket['due_date'])) . "'"; + $language_key = 'audit_due_date_changed'; } $sql = "UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `due_date` = {$due_date}, `overdue_email_sent` = '0' WHERE `trackid` = '" . hesk_dbEscape($ticket['trackid']) . "'"; + mfh_insert_audit_trail_record($ticket_id['id'], 'TICKET', $language_key, hesk_date(), + $audit_array); + hesk_dbQuery($sql); } \ No newline at end of file diff --git a/language/en/text.php b/language/en/text.php index a5dc2321..d543ccd3 100644 --- a/language/en/text.php +++ b/language/en/text.php @@ -2210,6 +2210,10 @@ $hesklang['audit_merged']='%s merged ticket %s with this ticket'; // %s = date, $hesklang['audit_time_worked']='%s updated time worked to %s'; // %s = date, new time worked, user making change $hesklang['audit_submitted_by']='%s submitted ticket'; $hesklang['audit_submitted_via_pop']='Ticket submitted via POP3 fetching'; // thist16 +$hesklang['audit_due_date_removed'] = '%s removed due date'; +$hesklang['audit_due_date_changed'] = '%s changed due date to %s'; +$hesklang['audit_linked_ticket'] = '%s linked ticket %s to this ticket'; +$hesklang['audit_unlinked_ticket'] = '%s unlinked ticket %s'; // DO NOT CHANGE BELOW if (!defined('IN_SCRIPT')) die('PHP syntax OK!'); From c6f4e4ce3ea7e392a1ec28febe01eaae5a6c2694 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Mon, 25 Sep 2017 08:13:57 -0400 Subject: [PATCH 16/19] New audit trail records are returned in the API response --- api/BusinessLogic/Tickets/AuditTrail.php | 24 ++++++ .../Tickets/AuditTrailEntityType.php | 8 ++ api/BusinessLogic/Tickets/Ticket.php | 8 +- api/DataAccess/Tickets/TicketGateway.php | 39 +++++++++- api/composer.lock | 74 +++++++++---------- 5 files changed, 114 insertions(+), 39 deletions(-) create mode 100644 api/BusinessLogic/Tickets/AuditTrail.php create mode 100644 api/BusinessLogic/Tickets/AuditTrailEntityType.php diff --git a/api/BusinessLogic/Tickets/AuditTrail.php b/api/BusinessLogic/Tickets/AuditTrail.php new file mode 100644 index 00000000..46993521 --- /dev/null +++ b/api/BusinessLogic/Tickets/AuditTrail.php @@ -0,0 +1,24 @@ +id = intval($row['id']); $ticket->trackingId = $row['trackid']; @@ -143,6 +143,7 @@ class Ticket extends \BaseClass { $replies[$reply->id] = $reply; } $ticket->replies = $replies; + $ticket->auditTrail = $auditRecords; return $ticket; } @@ -309,6 +310,11 @@ class Ticket extends \BaseClass { */ public $auditTrailHtml; + /** + * @var AuditTrail + */ + public $auditTrail; + /** * @var string[] */ diff --git a/api/DataAccess/Tickets/TicketGateway.php b/api/DataAccess/Tickets/TicketGateway.php index a14d623e..72f471a3 100644 --- a/api/DataAccess/Tickets/TicketGateway.php +++ b/api/DataAccess/Tickets/TicketGateway.php @@ -5,6 +5,8 @@ namespace DataAccess\Tickets; use BusinessLogic\Attachments\AttachmentType; use BusinessLogic\Tickets\Attachment; +use BusinessLogic\Tickets\AuditTrail; +use BusinessLogic\Tickets\AuditTrailEntityType; use BusinessLogic\Tickets\Ticket; use BusinessLogic\Tickets\TicketGatewayGeneratedFields; use DataAccess\CommonDao; @@ -29,7 +31,42 @@ class TicketGateway extends CommonDao { $repliesRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "replies` WHERE `replyto` = " . intval($id) . " ORDER BY `id` ASC"); - $ticket = Ticket::fromDatabaseRow($row, $linkedTicketsRs, $repliesRs, $heskSettings); + $auditTrailRs = hesk_dbQuery("SELECT `audit`.`id`, `audit`.`language_key`, `audit`.`date`, + `values`.`replacement_index`, `values`.`replacement_value` + FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "audit_trail` AS `audit` + LEFT JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "audit_trail_to_replacement_values` AS `values` + ON `audit`.`id` = `values`.`audit_trail_id` + WHERE `entity_type` = 'TICKET' AND `entity_id` = " . intval($id) . " + ORDER BY `audit`.`date` ASC"); + + $auditRecords = array(); + + /* @var $currentAuditRecord AuditTrail|null */ + $currentAuditRecord = null; + while ($auditRow = hesk_dbFetchAssoc($auditTrailRs)) { + if ($currentAuditRecord == null || $currentAuditRecord->id != $auditRow['id']) { + if ($currentAuditRecord != null) { + $auditRecords[] = $currentAuditRecord; + } + $currentAuditRecord = new AuditTrail(); + $currentAuditRecord->id = $auditRow['id']; + $currentAuditRecord->entityId = $id; + $currentAuditRecord->entityType = AuditTrailEntityType::TICKET; + $currentAuditRecord->languageKey = $auditRow['language_key']; + $currentAuditRecord->date = $auditRow['date']; + $currentAuditRecord->replacementValues = array(); + } + + if ($auditRow['replacement_index'] != null) { + $currentAuditRecord->replacementValues[intval($auditRow['replacement_index'])] = $auditRow['replacement_value']; + } + } + + if ($currentAuditRecord != null) { + $auditRecords[] = $currentAuditRecord; + } + + $ticket = Ticket::fromDatabaseRow($row, $linkedTicketsRs, $repliesRs, $auditRecords, $heskSettings); $this->close(); diff --git a/api/composer.lock b/api/composer.lock index 130a7c7a..f8503360 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -155,7 +155,7 @@ "docblock", "parser" ], - "time": "2017-07-22T11:08:38+00:00" + "time": "2017-07-22 11:08:38" }, { "name": "doctrine/cache", @@ -231,7 +231,7 @@ "cache", "caching" ], - "time": "2017-08-25T06:51:37+00:00" + "time": "2017-08-25 06:51:37" }, { "name": "doctrine/lexer", @@ -285,7 +285,7 @@ "lexer", "parser" ], - "time": "2017-07-24T09:37:08+00:00" + "time": "2017-07-24 09:37:08" }, { "name": "guzzlehttp/guzzle", @@ -401,7 +401,7 @@ "keywords": [ "promise" ], - "time": "2017-05-20T23:14:18+00:00" + "time": "2017-05-20 23:14:18" }, { "name": "guzzlehttp/psr7", @@ -466,7 +466,7 @@ "uri", "url" ], - "time": "2017-07-17T09:11:21+00:00" + "time": "2017-07-17 09:11:21" }, { "name": "mailgun/mailgun-php", @@ -765,7 +765,7 @@ "http", "httplug" ], - "time": "2017-08-05T15:50:10+00:00" + "time": "2017-08-05 15:50:10" }, { "name": "php-http/curl-client", @@ -883,7 +883,7 @@ "message", "psr7" ], - "time": "2017-09-13T14:06:45+00:00" + "time": "2017-09-13 14:06:45" }, { "name": "php-http/guzzle6-adapter", @@ -943,7 +943,7 @@ "Guzzle", "http" ], - "time": "2017-05-29T15:06:15+00:00" + "time": "2017-05-29 15:06:15" }, { "name": "php-http/httplug", @@ -999,7 +999,7 @@ "client", "http" ], - "time": "2017-08-18T18:51:51+00:00" + "time": "2017-08-18 18:51:51" }, { "name": "php-http/message", @@ -1071,7 +1071,7 @@ "message", "psr-7" ], - "time": "2017-07-05T06:40:53+00:00" + "time": "2017-07-05 06:40:53" }, { "name": "php-http/message-factory", @@ -1121,7 +1121,7 @@ "stream", "uri" ], - "time": "2016-02-03T08:16:31+00:00" + "time": "2016-02-03 08:16:31" }, { "name": "php-http/multipart-stream-builder", @@ -1178,7 +1178,7 @@ "multipart stream", "stream" ], - "time": "2017-05-21T18:01:57+00:00" + "time": "2017-05-21 18:01:57" }, { "name": "php-http/promise", @@ -1228,7 +1228,7 @@ "keywords": [ "promise" ], - "time": "2016-01-28T07:54:12+00:00" + "time": "2016-01-28 07:54:12" }, { "name": "phpmailer/phpmailer", @@ -1354,7 +1354,7 @@ "container-interop", "psr" ], - "time": "2017-06-28T15:35:32+00:00" + "time": "2017-06-28 15:35:32" }, { "name": "psr/http-message", @@ -1404,7 +1404,7 @@ "request", "response" ], - "time": "2016-08-06T14:39:51+00:00" + "time": "2016-08-06 14:39:51" }, { "name": "symfony/options-resolver", @@ -1458,7 +1458,7 @@ "configuration", "options" ], - "time": "2017-08-03T09:34:20+00:00" + "time": "2017-08-03 09:34:20" }, { "name": "webmozart/assert", @@ -1508,7 +1508,7 @@ "check", "validate" ], - "time": "2016-11-23T20:04:41+00:00" + "time": "2016-11-23 20:04:41" }, { "name": "zendframework/zend-code", @@ -1614,7 +1614,7 @@ "events", "zf2" ], - "time": "2017-07-11T19:19:12+00:00" + "time": "2017-07-11 19:19:12" } ], "packages-dev": [ @@ -1710,7 +1710,7 @@ "object", "object graph" ], - "time": "2017-04-12T18:52:22+00:00" + "time": "2017-04-12 18:52:22" }, { "name": "phar-io/manifest", @@ -1765,7 +1765,7 @@ } ], "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2017-04-07T07:07:10+00:00" + "time": "2017-04-07 07:07:10" }, { "name": "phar-io/version", @@ -2021,7 +2021,7 @@ "spy", "stub" ], - "time": "2017-09-04T11:05:03+00:00" + "time": "2017-09-04 11:05:03" }, { "name": "phpunit/php-code-coverage", @@ -2085,7 +2085,7 @@ "testing", "xunit" ], - "time": "2017-08-25T06:32:04+00:00" + "time": "2017-08-25 06:32:04" }, { "name": "phpunit/php-file-iterator", @@ -2132,7 +2132,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03T07:40:28+00:00" + "time": "2016-10-03 07:40:28" }, { "name": "phpunit/php-text-template", @@ -2222,7 +2222,7 @@ "keywords": [ "timer" ], - "time": "2017-03-07T15:42:04+00:00" + "time": "2017-03-07 15:42:04" }, { "name": "phpunit/php-token-stream", @@ -2271,7 +2271,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-08-20T05:47:52+00:00" + "time": "2017-08-20 05:47:52" }, { "name": "phpunit/phpunit", @@ -2414,7 +2414,7 @@ "mock", "xunit" ], - "time": "2017-08-03T14:08:16+00:00" + "time": "2017-08-03 14:08:16" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -2459,7 +2459,7 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T10:23:55+00:00" + "time": "2017-03-04 10:23:55" }, { "name": "sebastian/comparator", @@ -2523,7 +2523,7 @@ "compare", "equality" ], - "time": "2017-08-20T14:03:32+00:00" + "time": "2017-08-20 14:03:32" }, { "name": "sebastian/diff", @@ -2575,7 +2575,7 @@ "keywords": [ "diff" ], - "time": "2017-08-03T08:09:46+00:00" + "time": "2017-08-03 08:09:46" }, { "name": "sebastian/environment", @@ -2625,7 +2625,7 @@ "environment", "hhvm" ], - "time": "2017-07-01T08:51:00+00:00" + "time": "2017-07-01 08:51:00" }, { "name": "sebastian/exporter", @@ -2692,7 +2692,7 @@ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "time": "2017-04-03 13:19:02" }, { "name": "sebastian/global-state", @@ -2743,7 +2743,7 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "time": "2017-04-27 15:39:26" }, { "name": "sebastian/object-enumerator", @@ -2790,7 +2790,7 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" + "time": "2017-08-03 12:35:26" }, { "name": "sebastian/object-reflector", @@ -2835,7 +2835,7 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" + "time": "2017-03-29 09:07:27" }, { "name": "sebastian/recursion-context", @@ -2888,7 +2888,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-07T15:09:59+00:00" + "time": "2017-03-07 15:09:59" }, { "name": "sebastian/resource-operations", @@ -2930,7 +2930,7 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2016-10-03T07:43:09+00:00" + "time": "2016-10-03 07:43:09" }, { "name": "sebastian/version", @@ -2973,7 +2973,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "time": "2016-10-03 07:35:21" }, { "name": "theseer/tokenizer", From 7e6a5b2ba56168d2a035d20642bc2d0119f57381 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Mon, 25 Sep 2017 21:50:11 -0400 Subject: [PATCH 17/19] Working on audit for API, trying to fix email issues --- api/BusinessLogic/DateTimeHelpers.php | 19 +++++++++++++ .../Emails/EmailTemplateParser.php | 2 +- api/BusinessLogic/Tickets/Ticket.php | 2 +- api/BusinessLogic/Tickets/TicketCreator.php | 14 ++++++++-- .../AuditTrail/AuditTrailGateway.php | 28 +++++++++++++++++++ api/DataAccess/Tickets/TicketGateway.php | 4 ++- 6 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 api/BusinessLogic/DateTimeHelpers.php create mode 100644 api/DataAccess/AuditTrail/AuditTrailGateway.php diff --git a/api/BusinessLogic/DateTimeHelpers.php b/api/BusinessLogic/DateTimeHelpers.php new file mode 100644 index 00000000..6cea5cb2 --- /dev/null +++ b/api/BusinessLogic/DateTimeHelpers.php @@ -0,0 +1,19 @@ +email), $msg); + $msg = str_replace('%%EMAIL%%', implode(';', $ticket->email), $msg); $msg = str_replace('%%CREATED%%', $ticket->dateCreated, $msg); $msg = str_replace('%%UPDATED%%', $ticket->lastChanged, $msg); $msg = str_replace('%%ID%%', $ticket->id, $msg); diff --git a/api/BusinessLogic/Tickets/Ticket.php b/api/BusinessLogic/Tickets/Ticket.php index 415620f8..5e0c44ff 100644 --- a/api/BusinessLogic/Tickets/Ticket.php +++ b/api/BusinessLogic/Tickets/Ticket.php @@ -164,7 +164,7 @@ class Ticket extends \BaseClass { public $name; /** - * @var array|null + * @var string[]|null */ public $email; diff --git a/api/BusinessLogic/Tickets/TicketCreator.php b/api/BusinessLogic/Tickets/TicketCreator.php index 5956de9b..ee1affcf 100644 --- a/api/BusinessLogic/Tickets/TicketCreator.php +++ b/api/BusinessLogic/Tickets/TicketCreator.php @@ -2,11 +2,13 @@ namespace BusinessLogic\Tickets; +use BusinessLogic\DateTimeHelpers; use BusinessLogic\Emails\Addressees; use BusinessLogic\Emails\EmailSenderHelper; use BusinessLogic\Emails\EmailTemplateRetriever; use BusinessLogic\Exceptions\ValidationException; use BusinessLogic\Statuses\DefaultStatusForAction; +use DataAccess\AuditTrail\AuditTrailGateway; use DataAccess\Security\UserGateway; use DataAccess\Settings\ModsForHeskSettingsGateway; use DataAccess\Statuses\StatusGateway; @@ -56,6 +58,9 @@ class TicketCreator extends \BaseClass { /* @var $modsForHeskSettingsGateway ModsForHeskSettingsGateway */ private $modsForHeskSettingsGateway; + /* @var $auditTrailGateway AuditTrailGateway */ + private $auditTrailGateway; + function __construct(NewTicketValidator $newTicketValidator, TrackingIdGenerator $trackingIdGenerator, Autoassigner $autoassigner, @@ -64,7 +69,8 @@ class TicketCreator extends \BaseClass { VerifiedEmailChecker $verifiedEmailChecker, EmailSenderHelper $emailSenderHelper, UserGateway $userGateway, - ModsForHeskSettingsGateway $modsForHeskSettingsGateway) { + ModsForHeskSettingsGateway $modsForHeskSettingsGateway, + AuditTrailGateway $auditTrailGateway) { $this->newTicketValidator = $newTicketValidator; $this->trackingIdGenerator = $trackingIdGenerator; $this->autoassigner = $autoassigner; @@ -74,6 +80,7 @@ class TicketCreator extends \BaseClass { $this->emailSenderHelper = $emailSenderHelper; $this->userGateway = $userGateway; $this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway; + $this->auditTrailGateway = $auditTrailGateway; } /** @@ -113,7 +120,7 @@ class TicketCreator extends \BaseClass { // Transform one-to-one properties $ticket->name = $ticketRequest->name; - $ticket->email = $ticketRequest->email; + $ticket->email = $this->getAddressees($ticketRequest->email); $ticket->priorityId = $ticketRequest->priority; $ticket->categoryId = $ticketRequest->category; $ticket->subject = $ticketRequest->subject; @@ -147,6 +154,9 @@ class TicketCreator extends \BaseClass { $ticket->timeWorked = '00:00:00'; $ticket->lastReplier = 0; + $this->auditTrailGateway->insertAuditTrailRecord($ticket->id, AuditTrailEntityType::TICKET, + 'audit_created', DateTimeHelpers::heskDate($heskSettings), array(), $heskSettings); + $addressees = new Addressees(); $addressees->to = $this->getAddressees($ticket->email); diff --git a/api/DataAccess/AuditTrail/AuditTrailGateway.php b/api/DataAccess/AuditTrail/AuditTrailGateway.php new file mode 100644 index 00000000..0c174706 --- /dev/null +++ b/api/DataAccess/AuditTrail/AuditTrailGateway.php @@ -0,0 +1,28 @@ +init(); + + hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "audit_trail` (`entity_id`, `entity_type`, + `language_key`, `date`) VALUES (" . intval($entityId) . ", '" . hesk_dbEscape($entityType) . "', + '" . hesk_dbEscape($languageKey) . "', '" . hesk_dbEscape($date) . "')"); + + $auditId = hesk_dbInsertID(); + + foreach ($replacementValues as $replacementIndex => $replacementValue) { + hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "audit_trail_to_replacement_values` + (`audit_trail_id`, `replacement_index`, `replacement_value`) VALUES (" . intval($auditId) . ", + " . intval($replacementIndex) . ", '" . hesk_dbEscape($replacementValue) . "')"); + } + + $this->close(); + + return $auditId; + } +} \ No newline at end of file diff --git a/api/DataAccess/Tickets/TicketGateway.php b/api/DataAccess/Tickets/TicketGateway.php index 72f471a3..5d8437bb 100644 --- a/api/DataAccess/Tickets/TicketGateway.php +++ b/api/DataAccess/Tickets/TicketGateway.php @@ -207,6 +207,8 @@ class TicketGateway extends CommonDao { $ipAddress = $ticket->ipAddress !== null && $ticket->ipAddress !== '' ? $ticket->ipAddress : ''; + $emailAddresses = implode(';', $ticket->email); + $tableName = $isEmailVerified ? 'tickets' : 'stage_tickets'; $sql = "INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . $tableName ."` @@ -242,7 +244,7 @@ class TicketGateway extends CommonDao { ( '" . hesk_dbEscape($ticket->trackingId) . "', '" . hesk_dbEscape($ticket->name) . "', - '" . hesk_dbEscape($ticket->email) . "', + '" . hesk_dbEscape($emailAddresses) . "', '" . intval($ticket->categoryId) . "', '" . intval($ticket->priorityId) . "', '" . hesk_dbEscape($ticket->subject) . "', From 60decb3cfa66c6bbaa458475315067f721626b69 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Tue, 26 Sep 2017 13:08:17 -0400 Subject: [PATCH 18/19] Fixed ticket creation stuff --- api/BusinessLogic/Security/UserContext.php | 15 +++++++++ api/BusinessLogic/Tickets/TicketCreator.php | 6 ++-- api/DataAccess/Tickets/TicketGateway.php | 37 +++++++++++++++++++-- api/index.php | 7 ++-- 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/api/BusinessLogic/Security/UserContext.php b/api/BusinessLogic/Security/UserContext.php index ee1522a9..70a907ac 100644 --- a/api/BusinessLogic/Security/UserContext.php +++ b/api/BusinessLogic/Security/UserContext.php @@ -55,6 +55,21 @@ class UserContext extends \BaseClass { /* @var $active bool */ public $active; + static function buildAnonymousUser() { + $userContext = new UserContext(); + $userContext->id = -1; + $userContext->username = "API - ANONYMOUS USER"; // Usernames can't have spaces, so no one will take this username + $userContext->admin = false; + $userContext->name = "ANONYMOUS USER"; + $userContext->email = "anonymous-user@example.com"; + $userContext->categories = array(); + $userContext->permissions = array(); + $userContext->autoAssign = false; + $userContext->active = true; + + return $userContext; + } + /** * Builds a user context based on the current session. **The session must be active!** * @param $dataRow array the $_SESSION superglobal or the hesk_users result set diff --git a/api/BusinessLogic/Tickets/TicketCreator.php b/api/BusinessLogic/Tickets/TicketCreator.php index ee1affcf..4175ce0e 100644 --- a/api/BusinessLogic/Tickets/TicketCreator.php +++ b/api/BusinessLogic/Tickets/TicketCreator.php @@ -155,10 +155,12 @@ class TicketCreator extends \BaseClass { $ticket->lastReplier = 0; $this->auditTrailGateway->insertAuditTrailRecord($ticket->id, AuditTrailEntityType::TICKET, - 'audit_created', DateTimeHelpers::heskDate($heskSettings), array(), $heskSettings); + 'audit_created', DateTimeHelpers::heskDate($heskSettings), array( + 0 => $ticket->name + ), $heskSettings); $addressees = new Addressees(); - $addressees->to = $this->getAddressees($ticket->email); + $addressees->to = $ticket->email; if ($ticketRequest->sendEmailToCustomer && $emailVerified) { $this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_TICKET, $ticketRequest->language, $addressees, $ticket, $heskSettings, $modsForHeskSettings); diff --git a/api/DataAccess/Tickets/TicketGateway.php b/api/DataAccess/Tickets/TicketGateway.php index 5d8437bb..4c72a9f2 100644 --- a/api/DataAccess/Tickets/TicketGateway.php +++ b/api/DataAccess/Tickets/TicketGateway.php @@ -129,7 +129,7 @@ class TicketGateway extends CommonDao { function getTicketByTrackingId($trackingId, $heskSettings) { $this->init(); - $rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "tickets` WHERE `trackid` = " . intval($trackingId)); + $rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "tickets` WHERE `trackid` = '" . hesk_dbEscape($trackingId) . "'"); if (hesk_dbNumRows($rs) === 0) { return null; } @@ -138,7 +138,40 @@ class TicketGateway extends CommonDao { $linkedTicketsRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "tickets` WHERE `parent` = " . intval($trackingId)); $repliesRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "replies` WHERE `replyto` = " . intval($row['id']) . " ORDER BY `id` ASC"); - $ticket = Ticket::fromDatabaseRow($row, $linkedTicketsRs, $repliesRs, $heskSettings); + $audiTrailRs = hesk_dbQuery("SELECT `audit`.`id`, `audit`.`language_key`, `audit`.`date`, + `values`.`replacement_index`, `values`.`replacement_value` + FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "audit_trail` AS `audit` + LEFT JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "audit_trail_to_replacement_values` AS `values` + ON `audit`.`id` = `values`.`audit_trail_id` + WHERE `entity_type` = 'TICKET' AND `entity_id` = " . intval($row['id'])); + $auditRecords = array(); + + /* @var $currentAuditRecord AuditTrail */ + $currentAuditRecord = null; + while ($auditRow = hesk_dbFetchAssoc($audiTrailRs)) { + if ($currentAuditRecord == null || $currentAuditRecord->id != $auditRow['id']) { + if ($currentAuditRecord != null) { + $auditRecords[] = $currentAuditRecord; + } + $currentAuditRecord = new AuditTrail(); + $currentAuditRecord->id = $auditRow['id']; + $currentAuditRecord->entityId = $row['id']; + $currentAuditRecord->entityType = AuditTrailEntityType::TICKET; + $currentAuditRecord->languageKey = $auditRow['language_key']; + $currentAuditRecord->date = $auditRow['date']; + $currentAuditRecord->replacementValues = array(); + } + + if ($auditRow['replacement_index'] != null) { + $currentAuditRecord->replacementValues[intval($auditRow['replacement_index'])] = $auditRow['replacement_value']; + } + } + + if ($currentAuditRecord != null) { + $auditRecords[] = $currentAuditRecord; + } + + $ticket = Ticket::fromDatabaseRow($row, $linkedTicketsRs, $repliesRs, $auditRecords, $heskSettings); $this->close(); diff --git a/api/index.php b/api/index.php index 393455a4..4766701c 100644 --- a/api/index.php +++ b/api/index.php @@ -43,7 +43,10 @@ function internalOrAuthHandler() { } function publicHandler() { - //-- No-op + global $userContext; + + //-- Create an "anonymous" UserContext + $userContext = \BusinessLogic\Security\UserContext::buildAnonymousUser(); } function assertApiIsEnabled() { @@ -188,7 +191,7 @@ Link::all(array( '/v1/categories/{i}' => action(\Controllers\Categories\CategoryController::clazz(), array(RequestMethod::GET, RequestMethod::PUT, RequestMethod::DELETE), SecurityHandler::INTERNAL_OR_AUTH_TOKEN), '/v1-internal/categories/{i}/sort/{s}' => action(\Controllers\Categories\CategoryController::clazz() . '::sort', array(RequestMethod::POST), SecurityHandler::INTERNAL), // Tickets - '/v1/tickets' => action(\Controllers\Tickets\CustomerTicketController::clazz(), RequestMethod::all()), + '/v1/tickets' => action(\Controllers\Tickets\CustomerTicketController::clazz(), RequestMethod::all(), SecurityHandler::OPEN), // Tickets - Staff '/v1/staff/tickets/{i}' => action(\Controllers\Tickets\StaffTicketController::clazz(), RequestMethod::all()), // Attachments From 3485a5b7dbeec7c0051b93a579ae4e5cfb61d279 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Tue, 26 Sep 2017 21:19:17 -0400 Subject: [PATCH 19/19] Fix tests --- .../CreateTicketForCustomerTest.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/api/Tests/BusinessLogic/Tickets/TicketCreatorTests/CreateTicketForCustomerTest.php b/api/Tests/BusinessLogic/Tickets/TicketCreatorTests/CreateTicketForCustomerTest.php index c2577ab0..69d817d6 100644 --- a/api/Tests/BusinessLogic/Tickets/TicketCreatorTests/CreateTicketForCustomerTest.php +++ b/api/Tests/BusinessLogic/Tickets/TicketCreatorTests/CreateTicketForCustomerTest.php @@ -18,6 +18,7 @@ use BusinessLogic\Tickets\TrackingIdGenerator; use BusinessLogic\Tickets\VerifiedEmailChecker; use BusinessLogic\ValidationModel; use Core\Constants\Priority; +use DataAccess\AuditTrail\AuditTrailGateway; use DataAccess\Security\UserGateway; use DataAccess\Settings\ModsForHeskSettingsGateway; use DataAccess\Statuses\StatusGateway; @@ -97,6 +98,9 @@ class CreateTicketTest extends TestCase { /* @var $modsForHeskSettings array */ private $modsForHeskSettings; + /* @var $auditTrailGateway \PHPUnit_Framework_MockObject_MockObject|AuditTrailGateway */ + private $auditTrailGateway; + protected function setUp() { $this->ticketGateway = $this->createMock(TicketGateway::clazz()); $this->newTicketValidator = $this->createMock(NewTicketValidator::clazz()); @@ -107,10 +111,11 @@ class CreateTicketTest extends TestCase { $this->emailSenderHelper = $this->createMock(EmailSenderHelper::clazz()); $this->userGateway = $this->createMock(UserGateway::clazz()); $this->modsForHeskSettingsGateway = $this->createMock(ModsForHeskSettingsGateway::clazz()); + $this->auditTrailGateway = $this->createMock(AuditTrailGateway::clazz()); $this->ticketCreator = new TicketCreator($this->newTicketValidator, $this->trackingIdGenerator, $this->autoassigner, $this->statusGateway, $this->ticketGateway, $this->verifiedEmailChecker, - $this->emailSenderHelper, $this->userGateway, $this->modsForHeskSettingsGateway); + $this->emailSenderHelper, $this->userGateway, $this->modsForHeskSettingsGateway, $this->auditTrailGateway); $this->ticketRequest = new CreateTicketByCustomerModel(); $this->ticketRequest->name = 'Name'; @@ -126,7 +131,8 @@ class CreateTicketTest extends TestCase { 'require_subject' => 1, 'require_message' => 1, 'custom_fields' => array(), - 'autoassign' => 0 + 'autoassign' => 0, + 'timeformat' => 'Y-m-d', ); $this->modsForHeskSettings = array( 'customer_email_verification_required' => false @@ -222,7 +228,7 @@ class CreateTicketTest extends TestCase { //-- Assert self::assertThat($ticket->ticket->name, self::equalTo($this->ticketRequest->name)); - self::assertThat($ticket->ticket->email, self::equalTo($this->ticketRequest->email)); + self::assertThat($ticket->ticket->email[0], self::equalTo($this->ticketRequest->email)); self::assertThat($ticket->ticket->priorityId, self::equalTo($this->ticketRequest->priority)); self::assertThat($ticket->ticket->categoryId, self::equalTo($this->ticketRequest->category)); self::assertThat($ticket->ticket->subject, self::equalTo($this->ticketRequest->subject));