Bootswatch, Summernote, and Captcheck mods for Mods for HESK (mods-for-hesk.com). In use at support.netsyms.com.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2158 lines
110 KiB

  1. <?php
  2. /**
  3. *
  4. * This file is part of HESK - PHP Help Desk Software.
  5. *
  6. * (c) Copyright Klemen Stirn. All rights reserved.
  7. * https://www.hesk.com
  8. *
  9. * For the full copyright and license agreement information visit
  10. * https://www.hesk.com/eula.php
  11. *
  12. */
  13. define('IN_SCRIPT', 1);
  14. define('HESK_PATH', '../');
  15. define('WYSIWYG', 1);
  16. define('VALIDATOR', 1);
  17. define('EXTRA_JS', '<script src="'.HESK_PATH.'internal-api/js/admin-ticket.js"></script>');
  18. /* Get all the required files and functions */
  19. require(HESK_PATH . 'hesk_settings.inc.php');
  20. require(HESK_PATH . 'inc/common.inc.php');
  21. require(HESK_PATH . 'inc/admin_functions.inc.php');
  22. require(HESK_PATH . 'inc/status_functions.inc.php');
  23. require(HESK_PATH . 'inc/view_attachment_functions.inc.php');
  24. require(HESK_PATH . 'inc/mail_functions.inc.php');
  25. hesk_load_database_functions();
  26. hesk_session_start();
  27. hesk_dbConnect();
  28. hesk_isLoggedIn();
  29. /* Check permissions for this feature */
  30. hesk_checkPermission('can_view_tickets');
  31. $modsForHesk_settings = mfh_getSettings();
  32. $can_del_notes = hesk_checkPermission('can_del_notes', 0);
  33. $can_reply = hesk_checkPermission('can_reply_tickets', 0);
  34. $can_delete = hesk_checkPermission('can_del_tickets', 0);
  35. $can_edit = hesk_checkPermission('can_edit_tickets', 0);
  36. $can_archive = hesk_checkPermission('can_add_archive', 0);
  37. $can_assign_self = hesk_checkPermission('can_assign_self', 0);
  38. $can_view_unassigned = hesk_checkPermission('can_view_unassigned', 0);
  39. $can_change_cat = hesk_checkPermission('can_change_cat', 0);
  40. $can_change_own_cat = hesk_checkPermission('can_change_own_cat',0);
  41. $can_ban_emails = hesk_checkPermission('can_ban_emails', 0);
  42. $can_unban_emails = hesk_checkPermission('can_unban_emails', 0);
  43. $can_ban_ips = hesk_checkPermission('can_ban_ips', 0);
  44. $can_unban_ips = hesk_checkPermission('can_unban_ips', 0);
  45. $can_resolve = hesk_checkPermission('can_resolve', 0);
  46. // Get ticket ID
  47. $trackingID = hesk_cleanID() or print_form();
  48. // Load custom fields
  49. require_once(HESK_PATH . 'inc/custom_fields.inc.php');
  50. // Load statuses
  51. //require_once(HESK_PATH . 'inc/statuses.inc.php');
  52. $_SERVER['PHP_SELF'] = 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999);
  53. /* We will need timer function */
  54. define('TIMER', 1);
  55. /* Get ticket info */
  56. $res = hesk_dbQuery("SELECT `t1`.* , `t2`.name AS `repliername` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` AS `t1` LEFT JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` AS `t2` ON `t1`.`replierid` = `t2`.`id` WHERE `trackid`='" . hesk_dbEscape($trackingID) . "' LIMIT 1");
  57. /* Ticket found? */
  58. if (hesk_dbNumRows($res) != 1) {
  59. /* Ticket not found, perhaps it was merged with another ticket? */
  60. $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `merged` LIKE '%#" . hesk_dbEscape($trackingID) . "#%' LIMIT 1");
  61. if (hesk_dbNumRows($res) == 1) {
  62. /* OK, found in a merged ticket. Get info */
  63. $ticket = hesk_dbFetchAssoc($res);
  64. hesk_process_messages(sprintf($hesklang['tme'], $trackingID, $ticket['trackid']), 'NOREDIRECT', 'NOTICE');
  65. $trackingID = $ticket['trackid'];
  66. } else {
  67. /* Nothing found, error out */
  68. hesk_process_messages($hesklang['ticket_not_found'], 'NOREDIRECT');
  69. print_form();
  70. }
  71. } else {
  72. /* We have a match, get ticket info */
  73. $ticket = hesk_dbFetchAssoc($res);
  74. }
  75. /* Permission to view this ticket? */
  76. if ($ticket['owner'] && $ticket['owner'] != $_SESSION['id'] && !hesk_checkPermission('can_view_ass_others', 0)) {
  77. hesk_error($hesklang['ycvtao']);
  78. }
  79. if (!$ticket['owner'] && !$can_view_unassigned) {
  80. hesk_error($hesklang['ycovtay']);
  81. }
  82. /* Set last replier name */
  83. if ($ticket['lastreplier']) {
  84. if (empty($ticket['repliername'])) {
  85. $ticket['repliername'] = $hesklang['staff'];
  86. }
  87. } else {
  88. $ticket['repliername'] = $ticket['name'];
  89. }
  90. /* Get category name and ID */
  91. $result = hesk_dbQuery("SELECT `id`, `name`, `manager` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE `id`='" . intval($ticket['category']) . "' LIMIT 1");
  92. /* If this category has been deleted use the default category with ID 1 */
  93. if (hesk_dbNumRows($result) != 1) {
  94. $result = hesk_dbQuery("SELECT `id`, `name`, `manager` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE `id`='1' LIMIT 1");
  95. }
  96. $category = hesk_dbFetchAssoc($result);
  97. $managerRS = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'users` WHERE `id` = ' . intval($_SESSION['id']));
  98. $managerRow = hesk_dbFetchAssoc($managerRS);
  99. $isManager = $managerRow['id'] == $category['manager'];
  100. if ($isManager) {
  101. $can_del_notes =
  102. $can_reply =
  103. $can_delete =
  104. $can_edit =
  105. $can_archive =
  106. $can_assign_self =
  107. $can_view_unassigned =
  108. $can_change_own_cat =
  109. $can_change_cat =
  110. $can_ban_emails =
  111. $can_unban_emails =
  112. $can_ban_ips =
  113. $can_unban_ips =
  114. $can_resolve = true;
  115. }
  116. /* Is this user allowed to view tickets inside this category? */
  117. hesk_okCategory($category['id']);
  118. /* Delete post action */
  119. if (isset($_GET['delete_post']) && $can_delete && hesk_token_check()) {
  120. $n = intval(hesk_GET('delete_post'));
  121. if ($n) {
  122. /* Get last reply ID, we'll need it later */
  123. $res = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` WHERE `replyto`='" . intval($ticket['id']) . "' ORDER BY `id` DESC LIMIT 1");
  124. $last_reply_id = hesk_dbResult($res, 0, 0);
  125. // Was this post submitted by staff and does it have any attachments?
  126. $res = hesk_dbQuery("SELECT `dt`, `staffid`, `attachments` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` WHERE `id`='" . intval($n) . "' AND `replyto`='" . intval($ticket['id']) . "' LIMIT 1");
  127. $reply = hesk_dbFetchAssoc($res);
  128. // If the reply was by a staff member update the appropriate columns
  129. if ($reply['staffid']) {
  130. // Is this the only staff reply? Delete "firstreply" and "firstreplyby" columns
  131. if ($ticket['staffreplies'] <= 1) {
  132. $staffreplies_sql = ' , `firstreply`=NULL, `firstreplyby`=NULL, `staffreplies`=0 ';
  133. } // Are we deleting the first staff reply? Update "firstreply" and "firstreplyby" columns
  134. elseif ($reply['dt'] == $ticket['firstreply'] && $reply['staffid'] == $ticket['firstreplyby']) {
  135. // Get the new first reply info
  136. $res = hesk_dbQuery("SELECT `dt`, `staffid` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` WHERE `replyto`='" . intval($ticket['id']) . "' AND `id`!='" . intval($n) . "' AND `staffid`!=0 ORDER BY `id` ASC LIMIT 1");
  137. // Did we find the new first reply?
  138. if (hesk_dbNumRows($res)) {
  139. $firstreply = hesk_dbFetchAssoc($res);
  140. $staffreplies_sql = " , `firstreply`='" . hesk_dbEscape($firstreply['dt']) . "', `firstreplyby`='" . hesk_dbEscape($firstreply['staffid']) . "', `staffreplies`=`staffreplies`-1 ";
  141. } // The count must have been wrong, update it
  142. else {
  143. $staffreplies_sql = ' , `firstreply`=NULL, `firstreplyby`=NULL, `staffreplies`=0 ';
  144. }
  145. } // OK, this is not the first and not the only staff reply, just reduce number
  146. else {
  147. $staffreplies_sql = ' , `staffreplies`=`staffreplies`-1 ';
  148. }
  149. } else {
  150. $staffreplies_sql = '';
  151. }
  152. /* Delete any attachments to this post */
  153. if (strlen($reply['attachments'])) {
  154. $hesk_settings['server_path'] = dirname(dirname(__FILE__));
  155. /* List of attachments */
  156. $att = explode(',', substr($reply['attachments'], 0, -1));
  157. foreach ($att as $myatt) {
  158. list($att_id, $att_name) = explode('#', $myatt);
  159. /* Delete attachment files */
  160. $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "' LIMIT 1");
  161. if (hesk_dbNumRows($res) && $file = hesk_dbFetchAssoc($res)) {
  162. hesk_unlink($hesk_settings['server_path'] . '/' . $hesk_settings['attach_dir'] . '/' . $file['saved_name']);
  163. }
  164. /* Delete attachments info from the database */
  165. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "'");
  166. }
  167. }
  168. /* Delete this reply */
  169. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` WHERE `id`='" . intval($n) . "' AND `replyto`='" . intval($ticket['id']) . "'");
  170. /* Reply wasn't deleted */
  171. if (hesk_dbAffectedRows() != 1) {
  172. hesk_process_messages($hesklang['repl1'], $_SERVER['PHP_SELF']);
  173. } else {
  174. $closed_sql = '';
  175. $changeStatusRs = hesk_dbQuery('SELECT `id`, `LockedTicketStatus`, `IsCustomerReplyStatus`, `IsDefaultStaffReplyStatus`, `IsNewTicketStatus`
  176. FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses`
  177. WHERE `LockedTicketStatus` = 1
  178. OR `IsCustomerReplyStatus` = 1
  179. OR `IsDefaultStaffReplyStatus` = 1
  180. OR `IsNewTicketStatus` = 1');
  181. $lockedTicketStatus = '';
  182. $customerReplyStatus = '';
  183. $defaultStaffReplyStatus = '';
  184. $newTicketStatus = '';
  185. while ($row = hesk_dbFetchAssoc($changeStatusRs)) {
  186. if ($row['LockedTicketStatus']) {
  187. $lockedTicketStatus = $row['id'];
  188. } elseif ($row['IsCustomerReplyStatus']) {
  189. $customerReplyStatus = $row['id'];
  190. } elseif ($row['IsDefaultStaffReplyStatus']) {
  191. $defaultStaffReplyStatus = $row['id'];
  192. } elseif ($row['IsNewTicketStatus']) {
  193. $newTicketStatus = $row['id'];
  194. }
  195. }
  196. /* Reply deleted. Need to update status and last replier? */
  197. $res = hesk_dbQuery("SELECT `dt`, `staffid` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` WHERE `replyto`='" . intval($ticket['id']) . "' ORDER BY `id` DESC LIMIT 1");
  198. if (hesk_dbNumRows($res)) {
  199. $replier_id = hesk_dbResult($res, 0, 1);
  200. $last_replier = $replier_id ? 1 : 0;
  201. /* Change status? */
  202. $status_sql = '';
  203. if ($last_reply_id == $n) {
  204. $status = $ticket['locked'] ? $lockedTicketStatus : ($last_replier ? $defaultStaffReplyStatus : $customerReplyStatus);
  205. $status_sql = " , `status`='" . intval($status) . "' ";
  206. // Update closedat and closedby columns as required
  207. if ($status == $lockedTicketStatus) {
  208. $closed_sql = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " ";
  209. }
  210. }
  211. hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `lastchange`=NOW(), `lastreplier`='{$last_replier}', `replierid`='" . intval($replier_id) . "', `replies`=`replies`-1 $status_sql $closed_sql $staffreplies_sql WHERE `id`='" . intval($ticket['id']) . "'");
  212. } else {
  213. // Update status, closedat and closedby columns as required
  214. if ($ticket['locked']) {
  215. $status = $lockedTicketStatus;
  216. $closed_sql = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " ";
  217. } else {
  218. $status = $newTicketStatus;
  219. $closed_sql = " , `closedat`=NULL, `closedby`=NULL ";
  220. }
  221. hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `lastchange`=NOW(), `lastreplier`='0', `status`='$status', `replies`=0 $staffreplies_sql WHERE `id`='" . intval($ticket['id']) . "'");
  222. }
  223. hesk_process_messages($hesklang['repl'], $_SERVER['PHP_SELF'], 'SUCCESS');
  224. }
  225. } else {
  226. hesk_process_messages($hesklang['repl0'], $_SERVER['PHP_SELF']);
  227. }
  228. }
  229. /* Delete notes action */
  230. if (isset($_GET['delnote']) && hesk_token_check()) {
  231. $n = intval(hesk_GET('delnote'));
  232. if ($n) {
  233. // Get note info
  234. $res = hesk_dbQuery("SELECT `who`, `attachments` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` WHERE `id`={$n}");
  235. if (hesk_dbNumRows($res)) {
  236. $note = hesk_dbFetchAssoc($res);
  237. // Permission to delete note?
  238. if ($can_del_notes || $note['who'] == $_SESSION['id']) {
  239. // Delete note
  240. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` WHERE `id`='" . intval($n) . "'");
  241. // Delete attachments
  242. if (strlen($note['attachments'])) {
  243. $hesk_settings['server_path'] = dirname(dirname(__FILE__));
  244. $attachments = array();
  245. $att = explode(',', substr($note['attachments'], 0, -1));
  246. foreach ($att as $myatt) {
  247. list($att_id, $att_name) = explode('#', $myatt);
  248. $attachments[] = intval($att_id);
  249. }
  250. if (count($attachments)) {
  251. $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id` IN (" . implode(',', $attachments) . ") ");
  252. while ($file = hesk_dbFetchAssoc($res)) {
  253. hesk_unlink($hesk_settings['server_path'] . '/' . $hesk_settings['attach_dir'] . '/' . $file['saved_name']);
  254. }
  255. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id` IN (" . implode(',', $attachments) . ") ");
  256. }
  257. }
  258. }
  259. }
  260. }
  261. header('Location: admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  262. exit();
  263. }
  264. /* Add a note action */
  265. if (isset($_POST['notemsg']) && hesk_token_check('POST')) {
  266. // Error buffer
  267. $hesk_error_buffer = array();
  268. // Get message
  269. $msg = hesk_input(hesk_POST('notemsg'));
  270. // Get attachments
  271. if ($hesk_settings['attachments']['use']) {
  272. require(HESK_PATH . 'inc/posting_functions.inc.php');
  273. require(HESK_PATH . 'inc/htmLawed.php');
  274. require(HESK_PATH . 'inc/attachments.inc.php');
  275. $attachments = array();
  276. $use_legacy_attachments = hesk_POST('use-legacy-attachments', 0);
  277. if ($use_legacy_attachments) {
  278. for ($i = 1; $i <= $hesk_settings['attachments']['max_number']; $i++) {
  279. $att = hesk_uploadFile($i);
  280. if ($att !== false && !empty($att)) {
  281. $attachments[$i] = $att;
  282. }
  283. }
  284. } else {
  285. // The user used the new drag-and-drop system.
  286. $temp_attachment_ids = hesk_POST_array('attachment-ids');
  287. foreach ($temp_attachment_ids as $temp_attachment_id) {
  288. // Simply get the temp info and move it to the attachments table
  289. $temp_attachment = mfh_getTemporaryAttachment($temp_attachment_id);
  290. $attachments[] = $temp_attachment;
  291. mfh_deleteTemporaryAttachment($temp_attachment_id);
  292. }
  293. }
  294. }
  295. $myattachments = '';
  296. // We need message and/or attachments to accept note
  297. if (count($attachments) || strlen($msg) || count($hesk_error_buffer)) {
  298. // Any errors?
  299. if (count($hesk_error_buffer) != 0) {
  300. $_SESSION['note_message'] = hesk_POST('notemsg');
  301. // Remove any successfully uploaded attachments
  302. if ($hesk_settings['attachments']['use']) {
  303. hesk_removeAttachments($attachments);
  304. }
  305. $tmp = '';
  306. foreach ($hesk_error_buffer as $error) {
  307. $tmp .= "<li>$error</li>\n";
  308. }
  309. $hesk_error_buffer = $tmp;
  310. $hesk_error_buffer = $hesklang['pcer'] . '<br /><br /><ul>' . $hesk_error_buffer . '</ul>';
  311. hesk_process_messages($hesk_error_buffer, 'admin_ticket.php?track=' . $ticket['trackid'] . '&Refresh=' . rand(10000, 99999));
  312. }
  313. // Process attachments
  314. if ($hesk_settings['attachments']['use'] && !empty($attachments)) {
  315. foreach ($attachments as $myatt) {
  316. hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` (`ticket_id`,`saved_name`,`real_name`,`size`,`type`) VALUES ('" . hesk_dbEscape($trackingID) . "','" . hesk_dbEscape($myatt['saved_name']) . "','" . hesk_dbEscape($myatt['real_name']) . "','" . intval($myatt['size']) . "', '1')");
  317. $myattachments .= hesk_dbInsertID() . '#' . $myatt['real_name'] . '#' . $myatt['saved_name'] . ',';
  318. }
  319. }
  320. // Add note to database
  321. $msg = nl2br(hesk_makeURL($msg));
  322. hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` (`ticket`,`who`,`dt`,`message`,`attachments`) VALUES ('" . intval($ticket['id']) . "','" . intval($_SESSION['id']) . "',NOW(),'" . hesk_dbEscape($msg) . "','" . hesk_dbEscape($myattachments) . "')");
  323. /* Notify assigned staff that a note has been added if needed */
  324. $users = hesk_dbQuery("SELECT `email`, `notify_note` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` WHERE (`id`='" . intval($ticket['owner']) . "' OR (`isadmin` = '1' AND `notify_note_unassigned` = '1')) AND `id` <> '" . intval($_SESSION['id']) . "'");
  325. if (hesk_dbNumRows($users) > 0) {
  326. // 1. Generate the array with ticket info that can be used in emails
  327. $info = array(
  328. 'email' => $ticket['email'],
  329. 'category' => $ticket['category'],
  330. 'priority' => $ticket['priority'],
  331. 'owner' => $ticket['owner'],
  332. 'trackid' => $ticket['trackid'],
  333. 'status' => $ticket['status'],
  334. 'name' => $_SESSION['name'],
  335. 'lastreplier' => $ticket['lastreplier'],
  336. 'subject' => $ticket['subject'],
  337. 'message' => stripslashes($msg),
  338. 'dt' => hesk_date($ticket['dt'], true),
  339. 'lastchange' => hesk_date($ticket['lastchange'], true),
  340. 'attachments' => $myattachments,
  341. 'id' => $ticket['id'],
  342. );
  343. // 2. Add custom fields to the array
  344. foreach ($hesk_settings['custom_fields'] as $k => $v) {
  345. $info[$k] = $v['use'] ? $ticket[$k] : '';
  346. }
  347. // 3. Make sure all values are properly formatted for email
  348. $ticket = hesk_ticketToPlain($info, 1, 0);
  349. /* Get email functions */
  350. require(HESK_PATH . 'inc/email_functions.inc.php');
  351. /* Format email subject and message for staff */
  352. $subject = hesk_getEmailSubject('new_note', $ticket);
  353. $message = hesk_getEmailMessage('new_note', $ticket, $modsForHesk_settings, 1);
  354. $htmlMessage = hesk_getHtmlMessage('new_note', $ticket, $modsForHesk_settings, 1);
  355. $hasMessage = hesk_doesTemplateHaveTag('new_note', '%%MESSAGE%%', $modsForHesk_settings);
  356. /* Send email to staff */
  357. while ($user = hesk_dbFetchAssoc($users)) {
  358. hesk_mail($user['email'], $subject, $message, $htmlMessage, $modsForHesk_settings, array(), array(), $hasMessage);
  359. }
  360. }
  361. }
  362. header('Location: admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  363. exit();
  364. }
  365. /* Update time worked */
  366. if ($hesk_settings['time_worked'] && ($can_reply || $can_edit) && isset($_POST['h']) && isset($_POST['m']) && isset($_POST['s']) && hesk_token_check('POST')) {
  367. $h = intval(hesk_POST('h'));
  368. $m = intval(hesk_POST('m'));
  369. $s = intval(hesk_POST('s'));
  370. /* Get time worked in proper format */
  371. $time_worked = hesk_getTime($h . ':' . $m . ':' . $s);
  372. /* Update database */
  373. $revision = sprintf($hesklang['thist14'], hesk_date(), $time_worked, $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
  374. 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) . "'");
  375. /* Show ticket */
  376. hesk_process_messages($hesklang['twu'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  377. }
  378. /* Add child action */
  379. if (($can_reply || $can_edit) && isset($_POST['childTrackingId'])) {
  380. //-- Make sure this isn't the same ticket or one of its merged tickets.
  381. $mergedTickets = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `trackid` =
  382. \'' . hesk_dbEscape($trackingID) . '\' AND `merged` LIKE \'%#' . hesk_dbEscape($_POST['childTrackingId']) . '#%\'');
  383. if ($_POST['childTrackingId'] == $trackingID || $mergedTickets->num_rows > 0) {
  384. hesk_process_messages($hesklang['cannot_link_ticket_to_itself'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  385. }
  386. //-- Does the child exist?
  387. $existRs = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `trackid` = \'' . hesk_dbEscape($_POST['childTrackingId']) . '\'');
  388. if ($existRs->num_rows == 0) {
  389. //-- Maybe it was merged?
  390. $existRs = hesk_dbQuery('SELECT `trackid` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `merged` LIKE \'#' . hesk_dbEscape($_POST['childTrackingId']) . '#\'');
  391. if ($existRs->num_rows > 0) {
  392. //-- Yes, it was merged. Set the child to the "new" ticket; not the merged one.
  393. $exist = hesk_dbFetchAssoc($existRs);
  394. $_POST['childTrackingId'] = $exist['trackid'];
  395. } else {
  396. hesk_process_messages(sprintf($hesklang['linked_ticket_does_not_exist'], $_POST['childTrackingId']), 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  397. }
  398. }
  399. //-- Check if the ticket is already a child.
  400. $childRs = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `parent` = ' . $ticket['id'] . ' AND `trackid` = \'' . $_POST['childTrackingId'] . '\'');
  401. if ($childRs->num_rows > 0) {
  402. hesk_process_messages(sprintf($hesklang['is_already_linked'], $_POST['childTrackingId']), 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'NOTICE');
  403. }
  404. hesk_dbQuery('UPDATE `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` SET `parent` = ' . $ticket['id'] . ' WHERE `trackid` = \'' . $_POST['childTrackingId'] . '\'');
  405. hesk_process_messages(sprintf($hesklang['link_added'], $_POST['childTrackingId']), 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  406. }
  407. /* Delete child action */
  408. if (($can_reply || $can_edit) && isset($_GET['deleteChild'])) {
  409. //-- Delete the relationship
  410. hesk_dbQuery('UPDATE `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` SET `parent` = NULL WHERE `ID` = ' . hesk_dbEscape($_GET['deleteChild']));
  411. hesk_process_messages($hesklang['ticket_no_longer_linked'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  412. } elseif (($can_reply || $can_edit) && isset($_GET['deleteParent'])) {
  413. //-- Delete the relationship
  414. hesk_dbQuery('UPDATE `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` SET `parent` = NULL WHERE `ID` = ' . hesk_dbEscape($ticket['id']));
  415. hesk_process_messages($hesklang['ticket_no_longer_linked'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  416. }
  417. /* Delete attachment action */
  418. if (isset($_GET['delatt']) && hesk_token_check()) {
  419. if (!$can_delete || !$can_edit) {
  420. hesk_process_messages($hesklang['no_permission'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  421. }
  422. $att_id = intval(hesk_GET('delatt')) or hesk_error($hesklang['inv_att_id']);
  423. $reply = intval(hesk_GET('reply', 0));
  424. if ($reply < 1) {
  425. $reply = 0;
  426. }
  427. $note = intval(hesk_GET('note', 0));
  428. if ($note < 1) {
  429. $note = 0;
  430. }
  431. /* Get attachment info */
  432. $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "' LIMIT 1");
  433. if (hesk_dbNumRows($res) != 1) {
  434. hesk_process_messages($hesklang['id_not_valid'] . ' (att_id)', 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  435. }
  436. $att = hesk_dbFetchAssoc($res);
  437. /* Is ticket ID valid for this attachment? */
  438. if ($att['ticket_id'] != $trackingID) {
  439. hesk_process_messages($hesklang['trackID_not_found'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  440. }
  441. /* Delete file from server */
  442. hesk_unlink(HESK_PATH . $hesk_settings['attach_dir'] . '/' . $att['saved_name']);
  443. /* Delete attachment from database */
  444. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "'");
  445. /* Update ticket or reply in the database */
  446. $revision = sprintf($hesklang['thist12'], hesk_date(), $att['real_name'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
  447. if ($reply) {
  448. 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) . "'");
  449. hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `id`='" . intval($ticket['id']) . "'");
  450. } elseif ($note) {
  451. hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` SET `attachments`=REPLACE(`attachments`,'" . hesk_dbEscape($att_id . '#' . $att['real_name'] . '#' . $att['saved_name']) . ",','') WHERE `id`={$note} LIMIT 1");
  452. hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` SET `attachments`=REPLACE(`attachments`,'" . hesk_dbEscape($att_id . '#' . $att['real_name']) . ",','') WHERE `id`={$note}");
  453. } else {
  454. 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']) . "'");
  455. 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']) . "'");
  456. }
  457. hesk_process_messages($hesklang['kb_att_rem'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  458. }
  459. //-- Update location action
  460. if (isset($_POST['latitude']) && isset($_POST['longitude'])) {
  461. hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `latitude` = '" . hesk_dbEscape($_POST['latitude']) . "',
  462. `longitude` = '" . hesk_dbEscape($_POST['longitude']) . "' WHERE `ID` = " . intval($ticket['id']));
  463. //redirect
  464. hesk_process_messages($hesklang['ticket_location_updated'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  465. }
  466. /* Print header */
  467. require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
  468. /* List of categories */
  469. $orderBy = $modsForHesk_settings['category_order_column'];
  470. if ($can_change_cat) {
  471. $result = hesk_dbQuery("SELECT `id`,`name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."categories` WHERE `usage` <> 2 ORDER BY `cat_order` ASC");
  472. } else {
  473. $result = hesk_dbQuery("SELECT `id`,`name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."categories` WHERE `usage` <> 2 AND ".hesk_myCategories('id')." ORDER BY `cat_order` ASC");
  474. }
  475. $categories_options = '';
  476. while ($row = hesk_dbFetchAssoc($result)) {
  477. $selected = '';
  478. if ($row['id'] == $ticket['category']) {
  479. $selected = 'selected';
  480. }
  481. $categories_options .= '<option value="' . $row['id'] . '" ' . $selected . '>' . $row['name'] . '</option>';
  482. }
  483. /* List of users */
  484. $admins = array();
  485. $result = hesk_dbQuery("SELECT `id`,`name`,`isadmin`,`categories`,`heskprivileges` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` WHERE `active` = '1' ORDER BY `name` ASC");
  486. while ($row = hesk_dbFetchAssoc($result)) {
  487. /* Is this an administrator? */
  488. if ($row['isadmin']) {
  489. $admins[$row['id']] = $row['name'];
  490. continue;
  491. }
  492. /* Not admin, is user allowed to view tickets? */
  493. if (strpos($row['heskprivileges'], 'can_view_tickets') !== false) {
  494. /* Is user allowed to access this category? */
  495. $cat = substr($row['categories'], 0);
  496. $row['categories'] = explode(',', $cat);
  497. if (in_array($ticket['category'], $row['categories'])) {
  498. $admins[$row['id']] = $row['name'];
  499. continue;
  500. }
  501. }
  502. }
  503. /* Get replies */
  504. if ($ticket['replies']) {
  505. $reply = '';
  506. $result = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` WHERE `replyto`='" . intval($ticket['id']) . "' ORDER BY `id` " . ($hesk_settings['new_top'] ? 'DESC' : 'ASC'));
  507. } else {
  508. $reply = false;
  509. }
  510. // Demo mode
  511. if (defined('HESK_DEMO')) {
  512. $ticket['email'] = 'hidden@demo.com';
  513. $ticket['ip'] = '127.0.0.1';
  514. }
  515. // If an email address is tied to this ticket, check if there are any others
  516. $recentTickets = NULL;
  517. if ($ticket['email'] != '') {
  518. $recentTicketsSql = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets`
  519. WHERE `email` = '" . hesk_dbEscape($ticket['email']) . "' AND `trackid` <> '" . hesk_dbEscape($trackingID) . "' ORDER BY `lastchange` DESC LIMIT 5");
  520. while ($recentRow = hesk_dbFetchAssoc($recentTicketsSql)) {
  521. if ($recentTickets === NULL) {
  522. $recentTickets = array();
  523. }
  524. array_push($recentTickets, $recentRow);
  525. }
  526. if ($recentTickets !== NULL) {
  527. $recentTicketsWithStatuses = array();
  528. foreach ($recentTickets as $recentTicket) {
  529. $newRecentTicket = $recentTicket;
  530. $thisTicketStatusRS = hesk_dbQuery("SELECT `ID`, `TextColor` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` WHERE `ID` = " . intval($recentTicket['status']));
  531. $theStatusRow = hesk_dbFetchAssoc($thisTicketStatusRS);
  532. $newRecentTicket['statusText'] = mfh_getDisplayTextForStatusId($theStatusRow['ID']);
  533. $newRecentTicket['statusColor'] = $theStatusRow['TextColor'];
  534. array_push($recentTicketsWithStatuses, $newRecentTicket);
  535. }
  536. $recentTickets = $recentTicketsWithStatuses;
  537. }
  538. }
  539. // TODO Here we go!
  540. /* Print admin navigation */
  541. require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
  542. ?>
  543. <section class="content">
  544. <?php
  545. /* This will handle error, success and notice messages */
  546. hesk_handle_messages();
  547. // Prepare special custom fields
  548. foreach ($hesk_settings['custom_fields'] as $k=>$v) {
  549. if ($v['use'] && hesk_is_custom_field_in_category($k, $ticket['category']) ) {
  550. switch ($v['type']) {
  551. case 'date':
  552. $ticket[$k] = hesk_custom_date_display_format($ticket[$k], $v['value']['date_format']);
  553. break;
  554. }
  555. }
  556. }
  557. ?>
  558. <h1><?php echo $hesklang['ticket_details']; ?></h1>
  559. <h2>
  560. <?php
  561. $tmp = '';
  562. if ($hesk_settings['sequential']) {
  563. $tmp = ' (' . $hesklang['seqid'] . ': ' . $ticket['id'] . ')';
  564. }
  565. echo $trackingID . $tmp; ?>
  566. </h2>
  567. <div class="box">
  568. <div class="box-header">
  569. <h1 class="box-title">
  570. <i class="fa fa-user"></i>
  571. <?php
  572. echo $ticket['name'];
  573. if ($ticket['archive']) {
  574. echo ' <span class="label label-primary"><i class="fa fa-tag"></i> ' . $hesklang['archived'] . '</span>';
  575. }
  576. if ($ticket['locked']) {
  577. echo ' <span class="label label-primary"><i class="fa fa-lock"></i> ' . $hesklang['loc'] . '</span>';
  578. }
  579. ?>
  580. </h1>
  581. <div class="pull-right">
  582. <?php echo hesk_getAdminButtons($category['id']); ?>
  583. </div>
  584. </div>
  585. <div class="box-body">
  586. <div class="callout callout-info">
  587. <div class="row">
  588. <div class="col-md-3">
  589. <strong><?php echo $hesklang['created_colon']; ?></strong>
  590. <?php echo hesk_date($ticket['dt'], true); ?>
  591. </div>
  592. <div class="col-md-3">
  593. <strong><?php echo $hesklang['updated_colon']; ?></strong>
  594. <?php echo hesk_date($ticket['lastchange'], true); ?>
  595. </div>
  596. <?php if ($ticket['language'] !== NULL): ?>
  597. <div class="col-md-3">
  598. <strong><?php echo $hesklang['language_colon']; ?></strong>
  599. <?php echo $ticket['language']; ?>
  600. </div>
  601. <div class="col-md-3">
  602. <strong><?php echo $hesklang['last_replier_colon']; ?></strong>
  603. <?php echo $ticket['repliername']; ?>
  604. </div>
  605. <?php endif; ?>
  606. </div>
  607. </div>
  608. <div class="row">
  609. <div class="col-md-6">
  610. <table class="table table-striped">
  611. <tbody>
  612. <?php if ($ticket['email'] !== ''): ?>
  613. <tr>
  614. <td><b><?php echo $hesklang['email']; ?></b></td>
  615. <td>
  616. <a href="mailto:<?php echo $ticket['email']; ?>"><?php echo $ticket['email']; ?></a>
  617. <?php
  618. if ($can_ban_emails && !empty($ticket['email'])) {
  619. if ($email_id = hesk_isBannedEmail($ticket['email'])) {
  620. if ($can_unban_emails) {
  621. echo '<a href="banned_emails.php?a=unban&amp;track=' . $trackingID . '&amp;id=' . intval($email_id) . '&amp;token=' . hesk_token_echo(0) . '">
  622. <i class="fa fa-ban icon-link red gray-on-hover" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['eisban'] . ' ' . $hesklang['click_unban'] . '"></i>
  623. </a> ';
  624. } else {
  625. echo '<i class="fa fa-ban icon-link red" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['eisban'] . '"></i>';
  626. }
  627. } else {
  628. echo '<a href="banned_emails.php?a=ban&amp;track=' . $trackingID . '&amp;email=' . urlencode($ticket['email']) . '&amp;token=' . hesk_token_echo(0) . '">
  629. <i class="fa fa-ban icon-link gray red-on-hover" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['savebanemail'] . '"></i>
  630. </a> ';
  631. }
  632. }
  633. ?>
  634. </td>
  635. </tr>
  636. <?php endif; if ($hesk_settings['time_worked']): ?>
  637. <tr>
  638. <td><strong><?php echo $hesklang['ip']; ?></strong></td>
  639. <td>
  640. <?php
  641. // Format IP for lookup
  642. if ($ticket['ip'] == 'Unknown' || $ticket['ip'] == $hesklang['unknown']) {
  643. echo $hesklang['unknown'];
  644. } else {
  645. echo '<a href="../ip_whois.php?ip=' . urlencode($ticket['ip']) . '">' . $ticket['ip'] . '</a>';
  646. if ($can_ban_ips) {
  647. if ($ip_id = hesk_isBannedIP($ticket['ip'])) {
  648. if ($can_unban_ips) {
  649. echo '<a href="banned_ips.php?a=unban&amp;track=' . $trackingID . '&amp;id=' . intval($ip_id) . '&amp;token=' . hesk_token_echo(0) . '">
  650. <i class="fa fa-ban red icon-link gray-on-hover" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['ipisban'] . ' ' . $hesklang['click_unban'] . '"></i>
  651. </a> ';
  652. } else {
  653. echo '<i class="fa fa-ban icon-link red" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['ipisban'] . '"></i>';
  654. }
  655. } else {
  656. echo '<a href="banned_ips.php?a=ban&amp;track=' . $trackingID . '&amp;ip=' . urlencode($ticket['ip']) . '&amp;token=' . hesk_token_echo(0) . '">
  657. <i class="fa fa-ban gray icon-link red-on-hover" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['savebanip'] . '"></i>
  658. </a> ';
  659. }
  660. }
  661. }
  662. ?>
  663. </td>
  664. </tr>
  665. <tr>
  666. <td><b><?php echo $hesklang['ts']; ?></b></td>
  667. <td>
  668. <span class="click-to-edit" onclick="Javascript:hesk_toggleLayerDisplay('modifytime')"
  669. data-toggle="tooltip" title="<?php echo $hesklang['click_to_edit']; ?>">
  670. <?php echo $ticket['time_worked']; ?>
  671. </span>
  672. <?php
  673. if ($can_reply || $can_edit)
  674. {
  675. ?><?php $t = hesk_getHHMMSS($ticket['time_worked']); ?>
  676. <div id="modifytime" style="display:none">
  677. <form data-toggle="validator" class="form-horizontal" method="post" action="admin_ticket.php" style="margin:0px; padding:0px;">
  678. <div class="form-group">
  679. <label for="h" class="col-sm-4 control-label"><?php echo $hesklang['hh']; ?></label>
  680. <div class="col-sm-8">
  681. <input type="text" name="h" value="<?php echo $t[0]; ?>" size="3"
  682. data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
  683. placeholder="<?php echo htmlspecialchars($hesklang['hh']); ?>"
  684. class="form-control input-sm" required>
  685. </div>
  686. <div class="col-sm-12 text-right">
  687. <div class="help-block with-errors"></div>
  688. </div>
  689. </div>
  690. <div class="form-group input-group-sm">
  691. <label for="m" class="col-sm-4 control-label"><?php echo $hesklang['mm']; ?></label>
  692. <div class="col-sm-8">
  693. <input type="text" name="m" value="<?php echo $t[1]; ?>" size="3"
  694. data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
  695. placeholder="<?php echo htmlspecialchars($hesklang['mm']); ?>"
  696. class="form-control input-sm" required>
  697. </div>
  698. <div class="col-sm-12 text-right">
  699. <div class="help-block with-errors"></div>
  700. </div>
  701. </div>
  702. <div class="form-group input-group-sm">
  703. <label for="s" class="col-sm-4 control-label"><?php echo $hesklang['ss']; ?></label>
  704. <div class="col-sm-8">
  705. <input type="text" name="s" value="<?php echo $t[2]; ?>" size="3"
  706. data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
  707. placeholder="<?php echo htmlspecialchars($hesklang['ss']); ?>"
  708. class="form-control input-sm" required>
  709. </div>
  710. <div class="col-sm-12 text-right">
  711. <div class="help-block with-errors"></div>
  712. </div>
  713. </div>
  714. <div class="text-right">
  715. <div class="btn-group btn-group-sm text-right">
  716. <input class="btn btn-primary" type="submit" value="<?php echo $hesklang['save']; ?>" />
  717. <a class="btn btn-default" href="Javascript:void(0)" onclick="Javascript:hesk_toggleLayerDisplay('modifytime')"><?php echo $hesklang['cancel']; ?></a>
  718. </div>
  719. </div>
  720. <input type="hidden" name="track" value="<?php echo $trackingID; ?>" />
  721. <input type="hidden" name="token" value="<?php hesk_token_echo(); ?>" />
  722. </form>
  723. </div>
  724. <?php
  725. }
  726. ?>
  727. </td>
  728. </tr>
  729. <?php endif; ?>
  730. <tr>
  731. <td><strong><?php echo $hesklang['linked_tickets']; ?></strong></td>
  732. <td>
  733. <?php
  734. if ($ticket['parent'] != null) {
  735. //-- Get the tracking ID of the parent
  736. $parentRs = hesk_dbQuery('SELECT `trackid` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets`
  737. WHERE `ID` = ' . hesk_dbEscape($ticket['parent']));
  738. $parent = hesk_dbFetchAssoc($parentRs);
  739. echo '<a href="admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999) . '&deleteParent=true">
  740. <i class="fa fa-times-circle" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete_relationship'] . '"></i></a>';
  741. echo '&nbsp;<a href="admin_ticket.php?track=' . $parent['trackid'] . '&Refresh=' . mt_rand(10000, 99999) . '">' . $parent['trackid'] . '</a>';
  742. }
  743. //-- Check if any tickets have a parent set to this tracking ID
  744. $hasRows = false;
  745. $childrenRS = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets`
  746. WHERE `parent` = ' . hesk_dbEscape($ticket['id']));
  747. while ($row = hesk_dbFetchAssoc($childrenRS)) {
  748. $hasRows = true;
  749. echo '<a href="admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999) . '&deleteChild=' . $row['id'] . '">
  750. <i class="fa fa-times-circle font-icon red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['unlink'] . '"></i></a>';
  751. echo '&nbsp;<a href="admin_ticket.php?track=' . $row['trackid'] . '&Refresh=' . mt_rand(10000, 99999) . '">' . $row['trackid'] . '</a>';
  752. echo '<br>';
  753. }
  754. if (!$hasRows && $ticket['parent'] == null) {
  755. echo $hesklang['none'];
  756. }
  757. if ($can_reply || $can_edit) {
  758. ?>
  759. <div id="addChildText">
  760. <?php echo '<a href="javascript:void(0)" onclick="toggleChildrenForm(true)"><i class="fa fa-plus-circle"></i> ' . $hesklang['add_ticket'] . '</a>'; ?>
  761. </div>
  762. <div id="childrenForm" style="display: none">
  763. <form action="admin_ticket.php" method="post" data-toggle="validator">
  764. <div class="form-group">
  765. <label for="childTrackingId" class="control-label">
  766. <?php echo $hesklang['trackID']; ?>
  767. </label>
  768. <input type="text" name="childTrackingId" class="form-control input-sm"
  769. placeholder="<?php echo htmlspecialchars($hesklang['trackID']); ?>"
  770. data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
  771. required>
  772. <div class="help-block with-errors"></div>
  773. </div>
  774. <div class="btn-group">
  775. <input type="submit" class="btn btn-primary btn-sm"
  776. value="<?php echo $hesklang['save']; ?>">
  777. <a class="btn btn-default btn-sm" href="javascript:void(0)"
  778. onclick="toggleChildrenForm(false)">
  779. <?php echo $hesklang['cancel']; ?>
  780. </a>
  781. </div>
  782. <input type="hidden" name="track" value="<?php echo $trackingID; ?>"/>
  783. <input type="hidden" name="token" value="<?php hesk_token_echo(); ?>"/>
  784. </form>
  785. </div>
  786. <?php } ?>
  787. </td>
  788. </tr>
  789. </tbody>
  790. </table>
  791. </div>
  792. <div class="col-md-6">
  793. <table class="table table-striped">
  794. <tbody>
  795. <tr>
  796. <td><strong><?php echo $hesklang['due_date']; ?></strong></td>
  797. <td>
  798. <div id="readonly-due-date">
  799. <span id="due-date" data-toggle="tooltip" title="<?php echo $hesklang['click_to_edit']; ?>">
  800. <?php
  801. $due_date = $hesklang['none'];
  802. if ($ticket['due_date'] != null) {
  803. $due_date = hesk_date($ticket['due_date'], false, true, false);
  804. $due_date = date('Y-m-d', $due_date);
  805. }
  806. echo $due_date;
  807. ?></span>
  808. </div>
  809. <div id="editable-due-date" style="display: none">
  810. <div class="form-group">
  811. <input title="due-date" type="text" class="form-control datepicker" name="due-date" value="<?php echo $due_date == $hesklang['none'] ? '' : $due_date; ?>">
  812. <p class="help-block"><?php echo $hesklang['clear_for_no_due_date']; ?></p>
  813. </div>
  814. <div class="btn-group">
  815. <button id="submit" class="btn btn-primary"><?php echo $hesklang['save']; ?></button>
  816. <button id="cancel" class="btn btn-default"><?php echo $hesklang['cancel']; ?></button>
  817. </div>
  818. </div>
  819. </td>
  820. </tr>
  821. <tr>
  822. <td><strong><?php echo $hesklang['replies']; ?></strong></td>
  823. <td><?php echo $ticket['replies']; ?></td>
  824. </tr>
  825. <tr>
  826. <td><strong><?php echo $hesklang['recent_tickets']; ?></strong></td>
  827. <td>
  828. <?php if ($recentTickets === NULL): ?>
  829. <p style="margin: 0"><?php echo $hesklang['none']; ?></p>
  830. <?php
  831. else:
  832. foreach ($recentTickets as $recentTicket):
  833. ?>
  834. <p style="margin: 0">
  835. <i class="fa fa-circle" data-toggle="tooltip" data-placement="top"
  836. style="color: <?php echo $recentTicket['statusColor']; ?>"
  837. title="<?php echo sprintf($hesklang['current_status_colon'], $recentTicket['statusText']); ?>"></i>
  838. <?php echo '<a href="admin_ticket.php?track=' . $recentTicket['trackid'] . '&amp;Refresh=' . mt_rand(10000, 99999) . '">' . $recentTicket['trackid'] . '</a>'; ?>
  839. </p>
  840. <?php
  841. endforeach;
  842. endif;
  843. ?>
  844. </td>
  845. </tr>
  846. </tbody>
  847. </table>
  848. </div>
  849. </div>
  850. </div>
  851. </div>
  852. <div class="table-bordered status-row">
  853. <div class="row no-margins med-low-priority">
  854. <?php
  855. $priorityLanguages = array(
  856. 0 => $hesklang['critical'],
  857. 1 => $hesklang['high'],
  858. 2 => $hesklang['medium'],
  859. 3 => $hesklang['low']
  860. );
  861. $options = array();
  862. for ($i = 0; $i < 4; $i++) {
  863. $selected = $ticket['priority'] == $i ? 'selected' : '';
  864. array_push($options, '<option value="' . $i . '" ' . $selected . '>' . $priorityLanguages[$i] . '</option>');
  865. }
  866. echo '<div class="ticket-cell-admin col-md-3 col-sm-12 ';
  867. if ($ticket['priority'] == 0) {
  868. echo 'critical-priority">';
  869. } elseif ($ticket['priority'] == 1) {
  870. echo 'high-priority">';
  871. } else {
  872. echo 'med-low-priority">';
  873. }
  874. echo '<p class="ticket-property-title">' . $hesklang['priority'] . '</p>';
  875. echo '<form style="margin-bottom:0;" id="changePriorityForm" action="priority.php" method="post">
  876. <span style="white-space:nowrap;">
  877. <select class="form-control" name="priority" onchange="document.getElementById(\'changePriorityForm\').submit();">';
  878. echo implode('', $options);
  879. echo '
  880. </select>
  881. <input type="submit" style="display: none" value="' . $hesklang['go'] . '" /><input type="hidden" name="track" value="' . $trackingID . '" />
  882. <input type="hidden" name="token" value="' . hesk_token_echo(0) . '" />';
  883. if ($isManager) {
  884. echo '<input type="hidden" name="isManager" value="1">';
  885. }
  886. echo '</span>
  887. </form>
  888. </div>';
  889. echo '<div class="col-md-3 col-sm-12 ticket-cell-admin"><p class="ticket-property-title">' . $hesklang['status'] . '</p>';
  890. $status_options = array();
  891. $results = mfh_getAllStatuses();
  892. foreach ($results as $row) {
  893. $selected = $ticket['status'] == $row['ID'] ? 'selected' : '';
  894. $status_options[$row['ID']] = '<option value="' . $row['ID'] . '" ' . $selected . '>' . mfh_getDisplayTextForStatusId($row['ID']) . '</option>';
  895. }
  896. echo '
  897. <form role="form" id="changeStatusForm" style="margin-bottom:0;" action="change_status.php" method="post">
  898. <span style="white-space:nowrap;">
  899. <select class="form-control" onchange="document.getElementById(\'changeStatusForm\').submit();" name="s">
  900. ' . implode('', $status_options) . '
  901. </select>
  902. <input type="submit" style="display:none;" value="' . $hesklang['go'] . '" class="btn btn-default" /><input type="hidden" name="track" value="' . $trackingID . '" />
  903. <input type="hidden" name="token" value="' . hesk_token_echo(0) . '" />';
  904. if ($isManager) {
  905. echo '<input type="hidden" name="isManager" value="1">';
  906. }
  907. echo '</span>
  908. </form>
  909. </div>';
  910. echo '<div class="col-md-3 col-sm-12 ticket-cell-admin"><p class="ticket-property-title">' . $hesklang['owner'] . '</p>';
  911. if (hesk_checkPermission('can_assign_others', 0) || $isManager) {
  912. echo '
  913. <form style="margin-bottom:0;" id="changeOwnerForm" action="assign_owner.php" method="post">
  914. <span style="white-space:nowrap;">
  915. <select class="form-control" name="owner" onchange="document.getElementById(\'changeOwnerForm\').submit();">';
  916. $selectedForUnassign = 'selected';
  917. foreach ($admins as $k => $v) {
  918. $selected = '';
  919. if ($k == $ticket['owner']) {
  920. $selectedForUnassign = '';
  921. $selected = 'selected';
  922. }
  923. echo '<option value="' . $k . '" ' . $selected . '>' . $v . '</option>';
  924. }
  925. echo '<option value="-1" ' . $selectedForUnassign . '> &gt; ' . $hesklang['unas'] . ' &lt; </option>';
  926. echo '</select>
  927. <input type="submit" style="display: none" value="' . $hesklang['go'] . '">
  928. <input type="hidden" name="track" value="' . $trackingID . '">
  929. <input type="hidden" name="token" value="' . hesk_token_echo(0) . '">
  930. </span>';
  931. if ( ! $ticket['owner'])
  932. {
  933. echo '<input type="hidden" name="unassigned" value="1">';
  934. }
  935. echo '</form></div>';
  936. } else {
  937. echo '<p class="ticket-property-text">';
  938. echo isset($admins[$ticket['owner']]) ? $admins[$ticket['owner']] :
  939. ($can_assign_self ? $hesklang['unas'] . ' [<a href="assign_owner.php?track=' . $trackingID . '&amp;owner=' . $_SESSION['id'] . '&amp;token=' . hesk_token_echo(0) . '&amp;unassigned=1">' . $hesklang['asss'] . '</a>]' : $hesklang['unas']);
  940. echo '</p>';
  941. }
  942. echo '<div class="col-md-3 col-sm-12 ticket-cell-admin"><p class="ticket-property-title">' . $hesklang['category'] . '</p>';
  943. if (strlen($categories_options) && ($can_change_cat || $can_change_own_cat)) {
  944. echo '
  945. <form style="margin-bottom:0;" id="changeCategory" action="move_category.php" method="post">
  946. <span style="white-space:nowrap;">
  947. <select name="category" class="form-control" onchange="document.getElementById(\'changeCategory\').submit();">
  948. ' . $categories_options . '
  949. </select>
  950. <input type="submit" style="display: none" value="' . $hesklang['go'] . '">
  951. <input type="hidden" name="track" value="' . $trackingID . '">
  952. <input type="hidden" name="token" value="' . hesk_token_echo(0) . '">
  953. </span>
  954. </form>';
  955. } else {
  956. echo '<p class="ticket-property-text">' . $category['name'] . '</p>';
  957. }
  958. echo '</div>';
  959. ?>
  960. </div>
  961. </div>
  962. <div class="box box-warning">
  963. <div class="box-header with-border">
  964. <h1 class="box-title">
  965. <?php echo $hesklang['notes']; ?>
  966. </h1>
  967. <div class="box-tools pull-right">
  968. <button type="button" class="btn btn-box-tool" data-widget="collapse">
  969. <i class="fa fa-minus"></i>
  970. </button>
  971. </div>
  972. </div>
  973. <div class="box-body">
  974. <?php
  975. $res = hesk_dbQuery("SELECT t1.*, t2.`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` AS t1 LEFT JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` AS t2 ON t1.`who` = t2.`id` WHERE `ticket`='" . intval($ticket['id']) . "' ORDER BY t1.`id` " . ($hesk_settings['new_top'] ? 'DESC' : 'ASC'));
  976. if (hesk_dbNumRows($res) > 0):
  977. $first = true;
  978. while ($note = hesk_dbFetchAssoc($res)):
  979. if (!$first) {
  980. echo '<hr>';
  981. } else {
  982. $first = false;
  983. }
  984. ?>
  985. <div class="row">
  986. <div class="col-md-8">
  987. <p><i><?php echo $hesklang['noteby']; ?>
  988. <b><?php echo($note['name'] ? $note['name'] : $hesklang['e_udel']); ?></b></i>
  989. - <?php echo hesk_date($note['dt'], true); ?></p>
  990. <?php
  991. // Message
  992. echo $note['message'];
  993. // Attachments
  994. if ($hesk_settings['attachments']['use'] && strlen($note['attachments'])) {
  995. echo strlen($note['message']) ? '<br><br>' : '';
  996. $att = explode(',', substr($note['attachments'], 0, -1));
  997. $num = count($att);
  998. foreach ($att as $myatt) {
  999. list($att_id, $att_name) = explode('#', $myatt);
  1000. // Can edit and delete note (attachments)?
  1001. if ($can_del_notes || $note['who'] == $_SESSION['id']) {
  1002. // If this is the last attachment and no message, show "delete ticket" link
  1003. if ($num == 1 && strlen($note['message']) == 0) {
  1004. echo '<a href="admin_ticket.php?delnote=' . $note['id'] . '&amp;track=' . $trackingID . '&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '" onclick="return hesk_confirmExecute(\'' . hesk_makeJsString($hesklang['pda']) . '\');">
  1005. <i class="fa fa-times" style="font-size:16px;color:red;" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['dela'] . '"></i>
  1006. </a> ';
  1007. } // Show "delete attachment" link
  1008. else {
  1009. echo '<a href="admin_ticket.php?delatt=' . $att_id . '&amp;note=' . $note['id'] . '&amp;track=' . $trackingID . '&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '" onclick="return hesk_confirmExecute(\'' . hesk_makeJsString($hesklang['pda']) . '\');">
  1010. <i class="fa fa-times" style="font-size:16px;color:red;" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['dela'] . '"></i>
  1011. </a> ';
  1012. }
  1013. }
  1014. echo '
  1015. <a href="../download_attachment.php?att_id=' . $att_id . '&amp;track=' . $trackingID . '">
  1016. <i class="fa fa-paperclip" style="font-size:16px;" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['dnl'] . ' ' . $att_name . '"></i>
  1017. </a>
  1018. <a href="../download_attachment.php?att_id=' . $att_id . '&amp;track=' . $trackingID . '">' . $att_name . '</a><br />
  1019. ';
  1020. }
  1021. }
  1022. ?>
  1023. </div>
  1024. <div class="col-md-4 text-right">
  1025. <?php if ($can_del_notes || $note['who'] == $_SESSION['id']) { ?>
  1026. <a href="edit_note.php?track=<?php echo $trackingID; ?>&amp;Refresh=<?php echo mt_rand(10000, 99999); ?>&amp;note=<?php echo $note['id']; ?>&amp;token=<?php hesk_token_echo(); ?>">
  1027. <i class="fa fa-pencil icon-link orange" data-toggle="tooltip" title="<?php echo $hesklang['ednote']; ?>"></i>
  1028. </a>&nbsp;
  1029. <a href="admin_ticket.php?track=<?php echo $trackingID; ?>&amp;Refresh=<?php echo mt_rand(10000, 99999); ?>&amp;delnote=<?php echo $note['id']; ?>&amp;token=<?php hesk_token_echo(); ?>">
  1030. <i class="fa fa-times icon-link red" data-toggle="tooltip" title="<?php echo $hesklang['delnote']; ?>"></i>
  1031. </a>
  1032. <?php } ?>
  1033. </div>
  1034. </div>
  1035. <?php
  1036. endwhile;
  1037. else:
  1038. ?>
  1039. <?php echo $hesklang['no_notes_for_this_ticket']; ?>
  1040. <?php endif; ?>
  1041. </div>
  1042. <?php if ($can_reply): ?>
  1043. <div class="box-footer">
  1044. <button class="btn btn-default pull-right" data-toggle="modal" data-target="#noteform">
  1045. <i class="fa fa-plus-circle"></i> <?php echo $hesklang['addnote']; ?>
  1046. </button>
  1047. </div>
  1048. <?php endif; ?>
  1049. </div>
  1050. <div class="modal fade" tabindex="-1" role="dialog" id="noteform">
  1051. <div class="modal-dialog" role="document">
  1052. <div class="modal-content">
  1053. <div class="modal-header">
  1054. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  1055. <h4 class="modal-title"><?php echo $hesklang['addnote']; ?></h4>
  1056. </div>
  1057. <form class="form-horizontal" data-toggle="validator" method="post" action="admin_ticket.php" style="margin:0px; padding:0px;"
  1058. enctype="multipart/form-data">
  1059. <div class="modal-body">
  1060. <div class="form-group">
  1061. <label for="note-message" class="control-label col-sm-2"><?php echo $hesklang['message']; ?></label>
  1062. <div class="col-sm-10">
  1063. <textarea id="note-message" style="min-height: 150px" data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']) ?>" class="form-control" name="notemsg" rows="6"
  1064. cols="60" required><?php echo isset($_SESSION['note_message']) ? stripslashes(hesk_input($_SESSION['note_message'])) : ''; ?></textarea>
  1065. <div class="help-block with-errors"></div>
  1066. </div>
  1067. </div>
  1068. <div class="form-group">
  1069. <label for="note-attachments" class="control-label col-sm-2">
  1070. <?php echo $hesklang['attachments']; ?>
  1071. </label>
  1072. <div class="col-sm-10">
  1073. <?php build_dropzone_markup(true, 'notesFiledrop'); ?>
  1074. </div>
  1075. </div>
  1076. <?php display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/ticket/upload-attachment.php', 'notesFiledrop'); ?>
  1077. </div>
  1078. <div class="modal-footer">
  1079. <i><?php echo $hesklang['nhid']; ?></i>&nbsp;
  1080. <div class="btn-group">
  1081. <button type="button" class="btn btn-danger" data-dismiss="modal">Cancel</button>
  1082. <input type="submit" class="btn btn-success" value="<?php echo $hesklang['s']; ?>">
  1083. </div>
  1084. <input type="hidden" name="track" value="<?php echo $trackingID; ?>">
  1085. <input type="hidden" name="token" value="<?php hesk_token_echo(); ?>">
  1086. </div>
  1087. </form>
  1088. </div>
  1089. </div>
  1090. </div>
  1091. <?php
  1092. /* Reply form on top? */
  1093. if ($can_reply && $hesk_settings['reply_top'] == 1) {
  1094. hesk_printReplyForm();
  1095. }
  1096. /* Do we need or have any canned responses? */
  1097. $can_options = hesk_printCanned();
  1098. hesk_printTicketReplies();
  1099. echo '<br>';
  1100. /* Reply form on bottom? */
  1101. if ($can_reply && !$hesk_settings['reply_top']) {
  1102. hesk_printReplyForm();
  1103. }
  1104. /* Display ticket history */
  1105. if (strlen($ticket['history'])) {
  1106. ?>
  1107. <div class="box">
  1108. <div class="box-header with-border">
  1109. <h1 class="box-title">
  1110. <?php echo $hesklang['thist']; ?>
  1111. </h1>
  1112. <div class="box-tools pull-right">
  1113. <button type="button" class="btn btn-box-tool" data-widget="collapse">
  1114. <i class="fa fa-minus"></i>
  1115. </button>
  1116. </div>
  1117. </div>
  1118. <div class="box-body">
  1119. <?php echo $ticket['history']; ?>
  1120. </div>
  1121. </div>
  1122. <?php }
  1123. ?>
  1124. </section>
  1125. <div style="display: none">
  1126. <p id="lang_ticket_due_date_updated"><?php echo $hesklang['ticket_due_date_updated']; ?></p>
  1127. <p id="lang_none"><?php echo $hesklang['none']; ?></p>
  1128. <p id="lang_error_updating_ticket_due_date"><?php echo $hesklang['error_updating_ticket_due_date']; ?></p>
  1129. </div>
  1130. <?php
  1131. /* Clear unneeded session variables */
  1132. hesk_cleanSessionVars('ticket_message');
  1133. hesk_cleanSessionVars('time_worked');
  1134. hesk_cleanSessionVars('note_message');
  1135. require_once(HESK_PATH . 'inc/footer.inc.php');
  1136. /*** START FUNCTIONS ***/
  1137. function hesk_getAdminButtons($category_id)
  1138. {
  1139. global $hesk_settings, $hesklang, $modsForHesk_settings, $ticket, $reply, $trackingID, $can_edit, $can_archive, $can_delete, $can_resolve, $isManager;
  1140. $options = '';
  1141. /* Edit post */
  1142. if ($can_edit) {
  1143. $tmp = $reply ? '&amp;reply=' . $reply['id'] : '';
  1144. $mgr = $isManager ? '&amp;isManager=true' : '';
  1145. $options .= '<a class="btn btn-default" href="edit_post.php?track=' . $trackingID . $tmp . $mgr . '"><i class="fa fa-pencil orange"></i> ' . $hesklang['edit'] . '</a> ';
  1146. }
  1147. /* Print ticket button */
  1148. $options .= '<a class="btn btn-default" href="../print.php?track=' . $trackingID . '"><i class="fa fa-print"></i> ' . $hesklang['printer_friendly'] . '</a> ';
  1149. /* Delete ticket */
  1150. if ($can_delete) {
  1151. if ($reply) {
  1152. $url = 'admin_ticket.php';
  1153. $tmp = 'delete_post=' . $reply['id'];
  1154. $txt = $hesklang['delt'];
  1155. } else {
  1156. $url = 'delete_tickets.php';
  1157. $tmp = 'delete_ticket=1';
  1158. $txt = $hesklang['dele'];
  1159. }
  1160. $options .= '<a class="btn btn-default" href="' . $url . '?track=' . $trackingID . '&amp;' . $tmp . '&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '" onclick="return hesk_confirmExecute(\'' . hesk_makeJsString($txt) . '?\');"><i class="fa fa-times red"></i> ' . $txt . '</a> ';
  1161. }
  1162. $dropdown = '
  1163. <div class="btn-group">
  1164. <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
  1165. <i class="fa fa-ellipsis-h"></i> ' . hesk_htmlspecialchars($hesklang['more']) . ' <span class="caret"></span>
  1166. </button>
  1167. <ul class="dropdown-menu pull-right">';
  1168. // Location and UA
  1169. $has_location_or_user_agent = false;
  1170. if ($modsForHesk_settings['display_user_agent_information']
  1171. && $ticket['user_agent'] !== NULL
  1172. && $ticket['screen_resolution_height'] !== NULL
  1173. && $ticket['screen_resolution_height'] != 0
  1174. && $ticket['screen_resolution_width'] !== NULL
  1175. && $ticket['screen_resolution_width'] != 0
  1176. ) {
  1177. $has_location_or_user_agent = true;
  1178. $dropdown .=
  1179. '<li><a href="javascript:;" data-toggle="modal" data-target="#user-agent-modal"><i class="fa fa-desktop fa-fw"></i> ' . $hesklang['device_information'] . '</a></li>';
  1180. buildUserAgentModal($ticket['user_agent'], $ticket['screen_resolution_width'], $ticket['screen_resolution_height']);
  1181. } else if ($modsForHesk_settings['display_user_agent_information']) {
  1182. $has_location_or_user_agent = true;
  1183. $dropdown .=
  1184. '<li><span href="javascript:;" class="linkless-dropdown gray"><i class="fa fa-desktop fa-fw"></i> ' . $hesklang['no_device_information'] . '</span></li>';
  1185. }
  1186. ?>
  1187. <?php
  1188. if ($modsForHesk_settings['request_location']) {
  1189. $hasLocation = true;
  1190. $has_location_or_user_agent = true;
  1191. if (strpos($ticket['latitude'], 'E') === false) {
  1192. $locationText = $hesklang['click_for_map'];
  1193. $iconColor = '';
  1194. } else {
  1195. $hasLocation = false;
  1196. $locationText = $hesklang['location_unavailable'];
  1197. $iconColor = 'class="grey"';
  1198. }
  1199. $dropdown .= '<li><a href="javascript:;" data-toggle="modal" data-target=".map-modal" ' . $iconColor . '><i class="fa fa-map-marker fa-fw"></i> ' . $locationText . ' </a></li>';
  1200. ?>
  1201. <div id="map-modal" class="modal fade map-modal" tabindex="-1" role="dialog"
  1202. aria-labelledby="myLargeModalLabel" aria-hidden="true">
  1203. <div class="modal-dialog modal-lg">
  1204. <div class="modal-content">
  1205. <div class="modal-header">
  1206. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  1207. <span aria-hidden="true">&times;</span>
  1208. </button>
  1209. <h4><?php echo $hesklang['users_location']; ?></h4>
  1210. </div>
  1211. <div class="modal-body">
  1212. <?php if ($hasLocation): ?>
  1213. <div id="map" style="height: 500px"></div><br>
  1214. <address id="friendly-location" style="font-size: 13px"></address>
  1215. <p id="save-for-address"
  1216. style="font-size: 13px;display:none"><?php echo $hesklang['save_to_see_updated_address']; ?></p>
  1217. <script>
  1218. getFriendlyLocation(<?php echo $ticket['latitude']; ?>,
  1219. <?php echo $ticket['longitude']; ?>);
  1220. </script>
  1221. <div class="row">
  1222. <form action="admin_ticket.php" method="post" role="form">
  1223. <input type="hidden" name="track"
  1224. value="<?php echo $trackingID; ?>">
  1225. <input type="hidden" name="token"
  1226. value="<?php hesk_token_echo(); ?>">
  1227. <input type="hidden" name="latitude" id="latitude"
  1228. value="<?php echo $ticket['latitude']; ?>">
  1229. <input type="hidden" name="longitude" id="longitude"
  1230. value="<?php echo $ticket['longitude']; ?>">
  1231. <div class="col-sm-12">
  1232. <div class="btn-group" style="display:none" id="save-group">
  1233. <input type="submit" class="btn btn-success"
  1234. value="<?php echo $hesklang['save_location']; ?>">
  1235. <button class="btn btn-default" data-dismiss="modal"
  1236. onclick="closeAndReset(<?php echo $ticket['latitude']; ?>, <?php echo $ticket['longitude']; ?>)">
  1237. <?php echo $hesklang['close_modal_without_saving']; ?>
  1238. </button>
  1239. </div>
  1240. <div class="btn-group">
  1241. <button id="close-button" class="btn btn-default"
  1242. data-dismiss="modal"><?php echo $hesklang['close_modal']; ?></button>
  1243. </div>
  1244. </div>
  1245. </form>
  1246. </div>
  1247. <?php
  1248. else:
  1249. $errorCode = explode('-', $ticket['latitude']);
  1250. $key = 'location_unavailable_' . $errorCode[1];
  1251. echo '<h5>' . $hesklang[$key] . '</h5>';
  1252. endif;
  1253. ?>
  1254. </div>
  1255. </div>
  1256. </div>
  1257. </div>
  1258. <?php
  1259. // Only output JavaScript if we have coordinates
  1260. if (strpos($ticket['latitude'], 'E') === false):
  1261. ?>
  1262. <script>
  1263. var latitude = '';
  1264. latitude = <?php echo $ticket['latitude'] != '' ? $ticket['latitude'] : -1; ?>;
  1265. var longitude = '';
  1266. longitude = <?php echo $ticket['longitude'] != '' ? $ticket['longitude'] : -1; ?>;
  1267. initializeMapForStaff(latitude, longitude, "<?php echo $hesklang['users_location']; ?>");
  1268. </script>
  1269. <?php
  1270. endif;
  1271. }
  1272. // If there is device info enabled or location, separate them from the rest of the items in the dropdown.
  1273. if ($has_location_or_user_agent) {
  1274. $dropdown .= '<li role="separator" class="divider"></li>';
  1275. }
  1276. /* Close/Reopen ticket link */
  1277. $random = rand(10000, 99999);
  1278. $statusSql = 'SELECT `ID`, `IsStaffClosedOption`, `IsStaffReopenedStatus` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `IsStaffClosedOption` = 1 OR `IsStaffReopenedStatus` = 1';
  1279. $statusRs = hesk_dbQuery($statusSql);
  1280. $staffClosedOptionStatus = array();
  1281. $staffReopenedStatus = array();
  1282. while ($statusRow = hesk_dbFetchAssoc($statusRs)) {
  1283. if ($statusRow['IsStaffReopenedStatus'] == 1) {
  1284. $staffReopenedStatus['ID'] = $statusRow['ID'];
  1285. } else {
  1286. $staffClosedOptionStatus['ID'] = $statusRow['ID'];
  1287. }
  1288. }
  1289. $isTicketClosedSql = 'SELECT `IsClosed`, `Closable` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `ID` = ' . $ticket['status'];
  1290. $isTicketClosedRs = hesk_dbQuery($isTicketClosedSql);
  1291. $isTicketClosedRow = hesk_dbFetchAssoc($isTicketClosedRs);
  1292. $isTicketClosed = $isTicketClosedRow['IsClosed'];
  1293. $isClosable = $isTicketClosedRow['Closable'] == 'yes' || $isTicketClosedRow['Closable'] == 'sonly';
  1294. $mgr = $isManager ? '&amp;isManager=1' : '';
  1295. if ($isTicketClosed == 0 && $isClosable && $can_resolve) // Ticket is still open
  1296. {
  1297. $dropdown .= '<li><a href="change_status.php?track=' . $trackingID . $mgr . '&amp;s=' . $staffClosedOptionStatus['ID'] . '&amp;Refresh=' . $random . '&amp;token=' . hesk_token_echo(0) . '">
  1298. <i class="fa fa-check-circle fa-fw"></i> ' . $hesklang['close_action'] . '</a></li>';
  1299. } elseif ($isTicketClosed == 1) {
  1300. $dropdown .= '<li><a href="change_status.php?track=' . $trackingID . $mgr . '&amp;s=' . $staffReopenedStatus['ID'] . '&amp;Refresh=' . $random . '&amp;token=' . hesk_token_echo(0) . '">
  1301. <i class="fa fa-check-circle fa-fw"></i> ' . $hesklang['open_action'] . '</a></li>';
  1302. }
  1303. /* Lock ticket button */
  1304. if ($can_resolve) {
  1305. $template = '<li><a href="lock.php?track=' . $trackingID . '&amp;locked=%s&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-%s fa-fw"></i> %s</a></li>';
  1306. $dropdown .= $ticket['locked']
  1307. ? sprintf($template, 0, 'unlock', $hesklang['tul'])
  1308. : sprintf($template, 1, 'lock', $hesklang['tlo']);
  1309. }
  1310. /* Tag ticket button */
  1311. if ($can_archive) {
  1312. $template = '<li><a href="archive.php?track=' . $trackingID . '&amp;archived=%s&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-tag fa-fw"></i> %s</a></li>';
  1313. $dropdown .= $ticket['archive']
  1314. ? sprintf($template, 0, $hesklang['remove_archive'])
  1315. : sprintf($template, 1, $hesklang['add_archive']);
  1316. }
  1317. /* Import to knowledgebase button */
  1318. if ($hesk_settings['kb_enable'] && hesk_checkPermission('can_man_kb', 0)) {
  1319. $dropdown .= '<li><a href="manage_knowledgebase.php?a=import_article&amp;track=' . $trackingID . '"><i class="fa fa-lightbulb-o fa-fw"></i> ' . $hesklang['import_kb'] . '</a></li>';
  1320. }
  1321. /* Create ticket for same contact button */
  1322. $strippedName = strip_tags($ticket['name']);
  1323. $strippedEmail = strip_tags($ticket['email']);
  1324. $linkText = 'new_ticket.php?name=' . $strippedName . '&email=' . $strippedEmail . '&catid=' . $category_id . '&priority=' . $ticket['priority'];
  1325. foreach ($hesk_settings['custom_fields'] as $k => $v) {
  1326. if ($v['use'] == 1) {
  1327. if ($v['type'] == 'checkbox') {
  1328. $value = str_replace('<br />', '-CHECKBOX-', $ticket[$k]);
  1329. } else {
  1330. $value = $ticket[$k];
  1331. }
  1332. $strippedCustomField = strip_tags($value);
  1333. $linkText .= '&c_' . $k . '=' . $strippedCustomField;
  1334. }
  1335. }
  1336. $dropdown .= '<li><a href="' . $linkText . '"><i class="fa fa-plus fa-fw"></i> ' . $hesklang['create_based_on_contact'] . '</a></li>';
  1337. $dropdown .= '</ul></div> ';
  1338. $options .= $dropdown;
  1339. /* Return generated HTML */
  1340. return $options;
  1341. } // END hesk_getAdminButtons()
  1342. function hesk_getAdminButtonsInTicket($reply = 0, $white = 1)
  1343. {
  1344. global $hesk_settings, $hesklang, $ticket, $reply, $trackingID, $can_edit, $can_archive, $can_delete, $isManager;
  1345. $options = $reply ? '' : '<div class="pull-right">';
  1346. /* Edit post */
  1347. if ($can_edit) {
  1348. $tmp = $reply ? '&amp;reply=' . $reply['id'] : '';
  1349. $mgr = $isManager ? '&amp;isManager=true' : '';
  1350. $options .= '<a class="btn btn-default" href="edit_post.php?track=' . $trackingID . $tmp . $mgr . '"><i class="fa fa-pencil orange"></i> ' . $hesklang['edtt'] . '</a> ';
  1351. }
  1352. /* Delete ticket */
  1353. if ($can_delete) {
  1354. if ($reply) {
  1355. $url = 'admin_ticket.php';
  1356. $tmp = 'delete_post=' . $reply['id'];
  1357. $txt = $hesklang['delt'];
  1358. } else {
  1359. $url = 'delete_tickets.php';
  1360. $tmp = 'delete_ticket=1';
  1361. $txt = $hesklang['dele'];
  1362. }
  1363. $options .= '<a class="btn btn-default" href="' . $url . '?track=' . $trackingID . '&amp;' . $tmp . '&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '" onclick="return hesk_confirmExecute(\'' . $txt . '?\');"><i class="fa fa-times red"></i> ' . $txt . '</a> ';
  1364. }
  1365. /* Return generated HTML */
  1366. $options .= $reply ? '' : '</div>';
  1367. return $options;
  1368. } // END hesk_getAdminButtonsInTicket()
  1369. function print_form()
  1370. {
  1371. global $hesk_settings, $hesklang;
  1372. global $trackingID;
  1373. /* Print header */
  1374. require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
  1375. /* Print admin navigation */
  1376. require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
  1377. /* This will handle error, success and notice messages */
  1378. hesk_handle_messages();
  1379. ?>
  1380. <div class="row">
  1381. <div class="col-sm-10 col-sm-offset-1">
  1382. <h3 align="left"><?php echo $hesklang['view_existing']; ?></a></h3>
  1383. <form data-toggle="validator" action="admin_ticket.php" method="get" class="form-horizontal">
  1384. <div class="form-group">
  1385. <label for="track" class="control-label col-sm-3"><?php echo $hesklang['ticket_trackID']; ?></label>
  1386. <div class="col-sm-9">
  1387. <input type="text" name="track" maxlength="20" size="35" value="<?php echo $trackingID; ?>"
  1388. data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
  1389. placeholder="<?php echo $hesklang['ticket_trackID']; ?>" class="form-control" required>
  1390. <div class="help-block with-errors"></div>
  1391. </div>
  1392. </div>
  1393. <div class="form-group">
  1394. <div class="col-sm-9 col-sm-offset-3">
  1395. <input type="submit" value="<?php echo $hesklang['view_ticket']; ?>" class="btn btn-default">
  1396. <input type="hidden" name="Refresh" value="<?php echo rand(10000, 99999); ?>">
  1397. </div>
  1398. </div>
  1399. </form>
  1400. </div>
  1401. </div>
  1402. <?php
  1403. require_once(HESK_PATH . 'inc/footer.inc.php');
  1404. exit();
  1405. } // End print_form()
  1406. function mfh_print_message() {
  1407. global $ticket, $hesklang, $hesk_settings, $modsForHesk_settings;
  1408. ?>
  1409. <li><i class="fa fa-comment bg-red" data-toggle="tooltip" title="<?php echo $hesklang['original_message']; ?>"></i>
  1410. <div class="timeline-item">
  1411. <span class="time"><i class="fa fa-clock-o"></i> <?php echo $ticket['dt']; ?></span>
  1412. <h3 class="timeline-header"><?php echo $ticket['name']; ?></h3>
  1413. <div class="timeline-header header-info">
  1414. <div class="row">
  1415. <div class="col-md-3 text-right">
  1416. <strong><?php echo $hesklang['m_sub']; ?></strong>
  1417. </div>
  1418. <div class="col-md-9">
  1419. <?php echo $ticket['subject']; ?>
  1420. </div>
  1421. </div>
  1422. <?php
  1423. foreach ($hesk_settings['custom_fields'] as $k => $v) {
  1424. if ($v['use'] && $v['place'] == 0 && hesk_is_custom_field_in_category($k, $ticket['category'])) {
  1425. echo '<div class="row">';
  1426. echo '<div class="col-md-3 text-right"><strong>' . $v['name'] . ':</strong></div>';
  1427. if ($v['type'] == 'email') {
  1428. echo '<div class="col-md-9"><a href="mailto:'.$ticket[$k].'">'.$ticket[$k].'</a></div>';
  1429. } else {
  1430. echo '<div class="col-md-9">' . $ticket[$k] . '</div>';
  1431. }
  1432. echo '</div>';
  1433. }
  1434. }
  1435. ?>
  1436. </div>
  1437. <div class="timeline-body">
  1438. <?php
  1439. if ($ticket['message'] != '') {
  1440. if ($ticket['html']) {
  1441. echo hesk_html_entity_decode($ticket['message']);
  1442. } else {
  1443. echo $ticket['message'];
  1444. }
  1445. }
  1446. ?>
  1447. </div>
  1448. <?php
  1449. $first = true;
  1450. foreach ($hesk_settings['custom_fields'] as $k => $v) {
  1451. if ($v['use'] && $v['place'] && hesk_is_custom_field_in_category($k, $ticket['category'])) {
  1452. if ($first) {
  1453. echo '<div class="timeline-footer">';
  1454. $first = false;
  1455. }
  1456. echo '<div class="row">';
  1457. echo '<div class="col-md-3 text-right"><strong>' . $v['name'] . ':</strong></div>';
  1458. if ($v['type'] == 'email') {
  1459. echo '<div class="col-md-9"><a href="mailto:'.$ticket[$k].'">'.$ticket[$k].'</a></div>';
  1460. } else {
  1461. echo '<div class="col-md-9">' . $ticket[$k] . '</div>';
  1462. }
  1463. echo '</div>';
  1464. }
  1465. }
  1466. if (!$first) {
  1467. echo '</div>';
  1468. }
  1469. ?>
  1470. <?php if (($hesk_settings['attachments']['use'] && strlen($ticket['attachments']))
  1471. || ($hesk_settings['kb_enable'] && $hesk_settings['kb_recommendanswers'] && strlen($ticket['articles']))): ?>
  1472. <div class="timeline-footer">
  1473. <?php
  1474. /* Attachments */
  1475. mfh_listAttachments($ticket['attachments'], 0, true);
  1476. // Show suggested KB articles
  1477. if ($hesk_settings['kb_enable'] && $hesk_settings['kb_recommendanswers'] && strlen($ticket['articles'])) {
  1478. $suggested = array();
  1479. $suggested_list = '';
  1480. // Get article info from the database
  1481. $articles = hesk_dbQuery("SELECT `id`,`subject` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "kb_articles` WHERE `id` IN (" . preg_replace('/[^0-9\,]/', '', $ticket['articles']) . ")"