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.

admin_ticket.php 109KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195
  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('MFH_PAGE_LAYOUT', 'TOP_AND_SIDE');
  18. define('EXTRA_JS', '<script src="'.HESK_PATH.'internal-api/js/admin-ticket.js"></script>');
  19. /* Get all the required files and functions */
  20. require(HESK_PATH . 'hesk_settings.inc.php');
  21. require(HESK_PATH . 'inc/common.inc.php');
  22. require(HESK_PATH . 'inc/admin_functions.inc.php');
  23. require(HESK_PATH . 'inc/status_functions.inc.php');
  24. require(HESK_PATH . 'inc/view_attachment_functions.inc.php');
  25. require(HESK_PATH . 'inc/mail_functions.inc.php');
  26. hesk_load_database_functions();
  27. hesk_session_start();
  28. hesk_dbConnect();
  29. hesk_isLoggedIn();
  30. /* Check permissions for this feature */
  31. hesk_checkPermission('can_view_tickets');
  32. $modsForHesk_settings = mfh_getSettings();
  33. $can_del_notes = hesk_checkPermission('can_del_notes', 0);
  34. $can_reply = hesk_checkPermission('can_reply_tickets', 0);
  35. $can_delete = hesk_checkPermission('can_del_tickets', 0);
  36. $can_edit = hesk_checkPermission('can_edit_tickets', 0);
  37. $can_archive = hesk_checkPermission('can_add_archive', 0);
  38. $can_assign_self = hesk_checkPermission('can_assign_self', 0);
  39. $can_view_unassigned = hesk_checkPermission('can_view_unassigned', 0);
  40. $can_change_cat = hesk_checkPermission('can_change_cat', 0);
  41. $can_change_own_cat = hesk_checkPermission('can_change_own_cat',0);
  42. $can_ban_emails = hesk_checkPermission('can_ban_emails', 0);
  43. $can_unban_emails = hesk_checkPermission('can_unban_emails', 0);
  44. $can_ban_ips = hesk_checkPermission('can_ban_ips', 0);
  45. $can_unban_ips = hesk_checkPermission('can_unban_ips', 0);
  46. $can_resolve = hesk_checkPermission('can_resolve', 0);
  47. // Get ticket ID
  48. $trackingID = hesk_cleanID() or print_form();
  49. // Load custom fields
  50. require_once(HESK_PATH . 'inc/custom_fields.inc.php');
  51. // Load statuses
  52. //require_once(HESK_PATH . 'inc/statuses.inc.php');
  53. $_SERVER['PHP_SELF'] = 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999);
  54. /* We will need timer function */
  55. define('TIMER', 1);
  56. /* Get ticket info */
  57. $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");
  58. /* Ticket found? */
  59. if (hesk_dbNumRows($res) != 1) {
  60. /* Ticket not found, perhaps it was merged with another ticket? */
  61. $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `merged` LIKE '%#" . hesk_dbEscape($trackingID) . "#%' LIMIT 1");
  62. if (hesk_dbNumRows($res) == 1) {
  63. /* OK, found in a merged ticket. Get info */
  64. $ticket = hesk_dbFetchAssoc($res);
  65. hesk_process_messages(sprintf($hesklang['tme'], $trackingID, $ticket['trackid']), 'NOREDIRECT', 'NOTICE');
  66. $trackingID = $ticket['trackid'];
  67. } else {
  68. /* Nothing found, error out */
  69. hesk_process_messages($hesklang['ticket_not_found'], 'NOREDIRECT');
  70. print_form();
  71. }
  72. } else {
  73. /* We have a match, get ticket info */
  74. $ticket = hesk_dbFetchAssoc($res);
  75. }
  76. /* Permission to view this ticket? */
  77. if ($ticket['owner'] && $ticket['owner'] != $_SESSION['id'] && !hesk_checkPermission('can_view_ass_others', 0)) {
  78. hesk_error($hesklang['ycvtao']);
  79. }
  80. if (!$ticket['owner'] && !$can_view_unassigned) {
  81. hesk_error($hesklang['ycovtay']);
  82. }
  83. /* Set last replier name */
  84. if ($ticket['lastreplier']) {
  85. if (empty($ticket['repliername'])) {
  86. $ticket['repliername'] = $hesklang['staff'];
  87. }
  88. } else {
  89. $ticket['repliername'] = $ticket['name'];
  90. }
  91. /* Get category name and ID */
  92. $result = hesk_dbQuery("SELECT `id`, `name`, `manager` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE `id`='" . intval($ticket['category']) . "' LIMIT 1");
  93. /* If this category has been deleted use the default category with ID 1 */
  94. if (hesk_dbNumRows($result) != 1) {
  95. $result = hesk_dbQuery("SELECT `id`, `name`, `manager` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE `id`='1' LIMIT 1");
  96. }
  97. $category = hesk_dbFetchAssoc($result);
  98. $managerRS = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'users` WHERE `id` = ' . intval($_SESSION['id']));
  99. $managerRow = hesk_dbFetchAssoc($managerRS);
  100. $isManager = $managerRow['id'] == $category['manager'];
  101. if ($isManager) {
  102. $can_del_notes =
  103. $can_reply =
  104. $can_delete =
  105. $can_edit =
  106. $can_archive =
  107. $can_assign_self =
  108. $can_view_unassigned =
  109. $can_change_own_cat =
  110. $can_change_cat =
  111. $can_ban_emails =
  112. $can_unban_emails =
  113. $can_ban_ips =
  114. $can_unban_ips =
  115. $can_resolve = true;
  116. }
  117. /* Is this user allowed to view tickets inside this category? */
  118. hesk_okCategory($category['id']);
  119. /* Delete post action */
  120. if (isset($_GET['delete_post']) && $can_delete && hesk_token_check()) {
  121. $n = intval(hesk_GET('delete_post'));
  122. if ($n) {
  123. /* Get last reply ID, we'll need it later */
  124. $res = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` WHERE `replyto`='" . intval($ticket['id']) . "' ORDER BY `id` DESC LIMIT 1");
  125. $last_reply_id = hesk_dbResult($res, 0, 0);
  126. // Was this post submitted by staff and does it have any attachments?
  127. $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");
  128. $reply = hesk_dbFetchAssoc($res);
  129. // If the reply was by a staff member update the appropriate columns
  130. if ($reply['staffid']) {
  131. // Is this the only staff reply? Delete "firstreply" and "firstreplyby" columns
  132. if ($ticket['staffreplies'] <= 1) {
  133. $staffreplies_sql = ' , `firstreply`=NULL, `firstreplyby`=NULL, `staffreplies`=0 ';
  134. } // Are we deleting the first staff reply? Update "firstreply" and "firstreplyby" columns
  135. elseif ($reply['dt'] == $ticket['firstreply'] && $reply['staffid'] == $ticket['firstreplyby']) {
  136. // Get the new first reply info
  137. $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");
  138. // Did we find the new first reply?
  139. if (hesk_dbNumRows($res)) {
  140. $firstreply = hesk_dbFetchAssoc($res);
  141. $staffreplies_sql = " , `firstreply`='" . hesk_dbEscape($firstreply['dt']) . "', `firstreplyby`='" . hesk_dbEscape($firstreply['staffid']) . "', `staffreplies`=`staffreplies`-1 ";
  142. } // The count must have been wrong, update it
  143. else {
  144. $staffreplies_sql = ' , `firstreply`=NULL, `firstreplyby`=NULL, `staffreplies`=0 ';
  145. }
  146. } // OK, this is not the first and not the only staff reply, just reduce number
  147. else {
  148. $staffreplies_sql = ' , `staffreplies`=`staffreplies`-1 ';
  149. }
  150. } else {
  151. $staffreplies_sql = '';
  152. }
  153. /* Delete any attachments to this post */
  154. if (strlen($reply['attachments'])) {
  155. $hesk_settings['server_path'] = dirname(dirname(__FILE__));
  156. /* List of attachments */
  157. $att = explode(',', substr($reply['attachments'], 0, -1));
  158. foreach ($att as $myatt) {
  159. list($att_id, $att_name) = explode('#', $myatt);
  160. /* Delete attachment files */
  161. $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "' LIMIT 1");
  162. if (hesk_dbNumRows($res) && $file = hesk_dbFetchAssoc($res)) {
  163. hesk_unlink($hesk_settings['server_path'] . '/' . $hesk_settings['attach_dir'] . '/' . $file['saved_name']);
  164. }
  165. /* Delete attachments info from the database */
  166. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "'");
  167. }
  168. }
  169. /* Delete this reply */
  170. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` WHERE `id`='" . intval($n) . "' AND `replyto`='" . intval($ticket['id']) . "'");
  171. /* Reply wasn't deleted */
  172. if (hesk_dbAffectedRows() != 1) {
  173. hesk_process_messages($hesklang['repl1'], $_SERVER['PHP_SELF']);
  174. } else {
  175. $closed_sql = '';
  176. $changeStatusRs = hesk_dbQuery('SELECT `id`, `LockedTicketStatus`, `IsCustomerReplyStatus`, `IsDefaultStaffReplyStatus`, `IsNewTicketStatus`
  177. FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses`
  178. WHERE `LockedTicketStatus` = 1
  179. OR `IsCustomerReplyStatus` = 1
  180. OR `IsDefaultStaffReplyStatus` = 1
  181. OR `IsNewTicketStatus` = 1');
  182. $lockedTicketStatus = '';
  183. $customerReplyStatus = '';
  184. $defaultStaffReplyStatus = '';
  185. $newTicketStatus = '';
  186. while ($row = hesk_dbFetchAssoc($changeStatusRs)) {
  187. if ($row['LockedTicketStatus']) {
  188. $lockedTicketStatus = $row['id'];
  189. } elseif ($row['IsCustomerReplyStatus']) {
  190. $customerReplyStatus = $row['id'];
  191. } elseif ($row['IsDefaultStaffReplyStatus']) {
  192. $defaultStaffReplyStatus = $row['id'];
  193. } elseif ($row['IsNewTicketStatus']) {
  194. $newTicketStatus = $row['id'];
  195. }
  196. }
  197. /* Reply deleted. Need to update status and last replier? */
  198. $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");
  199. if (hesk_dbNumRows($res)) {
  200. $replier_id = hesk_dbResult($res, 0, 1);
  201. $last_replier = $replier_id ? 1 : 0;
  202. /* Change status? */
  203. $status_sql = '';
  204. if ($last_reply_id == $n) {
  205. $status = $ticket['locked'] ? $lockedTicketStatus : ($last_replier ? $defaultStaffReplyStatus : $customerReplyStatus);
  206. $status_sql = " , `status`='" . intval($status) . "' ";
  207. // Update closedat and closedby columns as required
  208. if ($status == $lockedTicketStatus) {
  209. $closed_sql = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " ";
  210. }
  211. }
  212. 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']) . "'");
  213. } else {
  214. // Update status, closedat and closedby columns as required
  215. if ($ticket['locked']) {
  216. $status = $lockedTicketStatus;
  217. $closed_sql = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " ";
  218. } else {
  219. $status = $newTicketStatus;
  220. $closed_sql = " , `closedat`=NULL, `closedby`=NULL ";
  221. }
  222. 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']) . "'");
  223. }
  224. hesk_process_messages($hesklang['repl'], $_SERVER['PHP_SELF'], 'SUCCESS');
  225. }
  226. } else {
  227. hesk_process_messages($hesklang['repl0'], $_SERVER['PHP_SELF']);
  228. }
  229. }
  230. /* Delete notes action */
  231. if (isset($_GET['delnote']) && hesk_token_check()) {
  232. $n = intval(hesk_GET('delnote'));
  233. if ($n) {
  234. // Get note info
  235. $res = hesk_dbQuery("SELECT `who`, `attachments` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` WHERE `id`={$n}");
  236. if (hesk_dbNumRows($res)) {
  237. $note = hesk_dbFetchAssoc($res);
  238. // Permission to delete note?
  239. if ($can_del_notes || $note['who'] == $_SESSION['id']) {
  240. // Delete note
  241. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` WHERE `id`='" . intval($n) . "'");
  242. // Delete attachments
  243. if (strlen($note['attachments'])) {
  244. $hesk_settings['server_path'] = dirname(dirname(__FILE__));
  245. $attachments = array();
  246. $att = explode(',', substr($note['attachments'], 0, -1));
  247. foreach ($att as $myatt) {
  248. list($att_id, $att_name) = explode('#', $myatt);
  249. $attachments[] = intval($att_id);
  250. }
  251. if (count($attachments)) {
  252. $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id` IN (" . implode(',', $attachments) . ") ");
  253. while ($file = hesk_dbFetchAssoc($res)) {
  254. hesk_unlink($hesk_settings['server_path'] . '/' . $hesk_settings['attach_dir'] . '/' . $file['saved_name']);
  255. }
  256. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id` IN (" . implode(',', $attachments) . ") ");
  257. }
  258. }
  259. }
  260. }
  261. }
  262. header('Location: admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  263. exit();
  264. }
  265. /* Add a note action */
  266. if (isset($_POST['notemsg']) && hesk_token_check('POST')) {
  267. // Error buffer
  268. $hesk_error_buffer = array();
  269. // Get message
  270. $msg = hesk_input(hesk_POST('notemsg'));
  271. // Get attachments
  272. if ($hesk_settings['attachments']['use']) {
  273. require(HESK_PATH . 'inc/posting_functions.inc.php');
  274. require(HESK_PATH . 'inc/htmLawed.php');
  275. require(HESK_PATH . 'inc/attachments.inc.php');
  276. $attachments = array();
  277. $use_legacy_attachments = hesk_POST('use-legacy-attachments', 0);
  278. if ($use_legacy_attachments) {
  279. for ($i = 1; $i <= $hesk_settings['attachments']['max_number']; $i++) {
  280. $att = hesk_uploadFile($i);
  281. if ($att !== false && !empty($att)) {
  282. $attachments[$i] = $att;
  283. }
  284. }
  285. } else {
  286. // The user used the new drag-and-drop system.
  287. $temp_attachment_ids = hesk_POST_array('attachment-ids');
  288. foreach ($temp_attachment_ids as $temp_attachment_id) {
  289. // Simply get the temp info and move it to the attachments table
  290. $temp_attachment = mfh_getTemporaryAttachment($temp_attachment_id);
  291. $attachments[] = $temp_attachment;
  292. mfh_deleteTemporaryAttachment($temp_attachment_id);
  293. }
  294. }
  295. }
  296. $myattachments = '';
  297. // We need message and/or attachments to accept note
  298. if (count($attachments) || strlen($msg) || count($hesk_error_buffer)) {
  299. // Any errors?
  300. if (count($hesk_error_buffer) != 0) {
  301. $_SESSION['note_message'] = hesk_POST('notemsg');
  302. // Remove any successfully uploaded attachments
  303. if ($hesk_settings['attachments']['use']) {
  304. hesk_removeAttachments($attachments);
  305. }
  306. $tmp = '';
  307. foreach ($hesk_error_buffer as $error) {
  308. $tmp .= "<li>$error</li>\n";
  309. }
  310. $hesk_error_buffer = $tmp;
  311. $hesk_error_buffer = $hesklang['pcer'] . '<br /><br /><ul>' . $hesk_error_buffer . '</ul>';
  312. hesk_process_messages($hesk_error_buffer, 'admin_ticket.php?track=' . $ticket['trackid'] . '&Refresh=' . rand(10000, 99999));
  313. }
  314. // Process attachments
  315. if ($hesk_settings['attachments']['use'] && !empty($attachments)) {
  316. foreach ($attachments as $myatt) {
  317. 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')");
  318. $myattachments .= hesk_dbInsertID() . '#' . $myatt['real_name'] . '#' . $myatt['saved_name'] . ',';
  319. }
  320. }
  321. // Add note to database
  322. $msg = nl2br(hesk_makeURL($msg));
  323. 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) . "')");
  324. /* Notify assigned staff that a note has been added if needed */
  325. $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']) . "'");
  326. if (hesk_dbNumRows($users) > 0) {
  327. // 1. Generate the array with ticket info that can be used in emails
  328. $info = array(
  329. 'email' => $ticket['email'],
  330. 'category' => $ticket['category'],
  331. 'priority' => $ticket['priority'],
  332. 'owner' => $ticket['owner'],
  333. 'trackid' => $ticket['trackid'],
  334. 'status' => $ticket['status'],
  335. 'name' => $_SESSION['name'],
  336. 'lastreplier' => $ticket['lastreplier'],
  337. 'subject' => $ticket['subject'],
  338. 'message' => stripslashes($msg),
  339. 'dt' => hesk_date($ticket['dt'], true),
  340. 'lastchange' => hesk_date($ticket['lastchange'], true),
  341. 'attachments' => $myattachments,
  342. 'id' => $ticket['id'],
  343. );
  344. // 2. Add custom fields to the array
  345. foreach ($hesk_settings['custom_fields'] as $k => $v) {
  346. $info[$k] = $v['use'] ? $ticket[$k] : '';
  347. }
  348. // 3. Make sure all values are properly formatted for email
  349. $ticket = hesk_ticketToPlain($info, 1, 0);
  350. /* Get email functions */
  351. require(HESK_PATH . 'inc/email_functions.inc.php');
  352. /* Format email subject and message for staff */
  353. $subject = hesk_getEmailSubject('new_note', $ticket);
  354. $message = hesk_getEmailMessage('new_note', $ticket, $modsForHesk_settings, 1);
  355. $htmlMessage = hesk_getHtmlMessage('new_note', $ticket, $modsForHesk_settings, 1);
  356. $hasMessage = hesk_doesTemplateHaveTag('new_note', '%%MESSAGE%%', $modsForHesk_settings);
  357. /* Send email to staff */
  358. while ($user = hesk_dbFetchAssoc($users)) {
  359. hesk_mail($user['email'], $subject, $message, $htmlMessage, $modsForHesk_settings, array(), array(), $hasMessage);
  360. }
  361. }
  362. }
  363. header('Location: admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  364. exit();
  365. }
  366. /* Update time worked */
  367. if ($hesk_settings['time_worked'] && ($can_reply || $can_edit) && isset($_POST['h']) && isset($_POST['m']) && isset($_POST['s']) && hesk_token_check('POST')) {
  368. $h = intval(hesk_POST('h'));
  369. $m = intval(hesk_POST('m'));
  370. $s = intval(hesk_POST('s'));
  371. /* Get time worked in proper format */
  372. $time_worked = hesk_getTime($h . ':' . $m . ':' . $s);
  373. /* Update database */
  374. $revision = sprintf($hesklang['thist14'], hesk_date(), $time_worked, $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
  375. 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) . "'");
  376. /* Show ticket */
  377. hesk_process_messages($hesklang['twu'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  378. }
  379. /* Add child action */
  380. if (($can_reply || $can_edit) && isset($_POST['childTrackingId'])) {
  381. //-- Make sure this isn't the same ticket or one of its merged tickets.
  382. $mergedTickets = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `trackid` =
  383. \'' . hesk_dbEscape($trackingID) . '\' AND `merged` LIKE \'%#' . hesk_dbEscape($_POST['childTrackingId']) . '#%\'');
  384. if ($_POST['childTrackingId'] == $trackingID || hesk_dbNumRows($mergedTickets) > 0) {
  385. hesk_process_messages($hesklang['cannot_link_ticket_to_itself'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  386. }
  387. //-- Does the child exist?
  388. $existRs = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `trackid` = \'' . hesk_dbEscape($_POST['childTrackingId']) . '\'');
  389. if (hesk_dbNumRows($existRs) == 0) {
  390. //-- Maybe it was merged?
  391. $existRs = hesk_dbQuery('SELECT `trackid` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `merged` LIKE \'#' . hesk_dbEscape($_POST['childTrackingId']) . '#\'');
  392. if (hesk_dbNumRows($existRs) > 0) {
  393. //-- Yes, it was merged. Set the child to the "new" ticket; not the merged one.
  394. $exist = hesk_dbFetchAssoc($existRs);
  395. $_POST['childTrackingId'] = $exist['trackid'];
  396. } else {
  397. hesk_process_messages(sprintf($hesklang['linked_ticket_does_not_exist'], $_POST['childTrackingId']), 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  398. }
  399. }
  400. //-- Check if the ticket is already a child.
  401. $childRs = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `parent` = ' . intval($ticket['id']) . ' AND `trackid` = \'' . hesk_dbEscape(hesk_POST(['childTrackingId'])) . '\'');
  402. if (hesk_dbNumRows($childRs) > 0) {
  403. hesk_process_messages(sprintf($hesklang['is_already_linked'], $_POST['childTrackingId']), 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'NOTICE');
  404. }
  405. hesk_dbQuery('UPDATE `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` SET `parent` = ' . intval($ticket['id']) . ' WHERE `trackid` = \'' . hesk_dbEscape(hesk_POST('childTrackingId')) . '\'');
  406. hesk_process_messages(sprintf($hesklang['link_added'], $_POST['childTrackingId']), 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  407. }
  408. /* Delete child action */
  409. if (($can_reply || $can_edit) && isset($_GET['deleteChild'])) {
  410. //-- Delete the relationship
  411. hesk_dbQuery('UPDATE `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` SET `parent` = NULL WHERE `ID` = ' . hesk_dbEscape($_GET['deleteChild']));
  412. hesk_process_messages($hesklang['ticket_no_longer_linked'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  413. } elseif (($can_reply || $can_edit) && isset($_GET['deleteParent'])) {
  414. //-- Delete the relationship
  415. hesk_dbQuery('UPDATE `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` SET `parent` = NULL WHERE `ID` = ' . hesk_dbEscape($ticket['id']));
  416. hesk_process_messages($hesklang['ticket_no_longer_linked'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  417. }
  418. /* Delete attachment action */
  419. if (isset($_GET['delatt']) && hesk_token_check()) {
  420. if (!$can_delete || !$can_edit) {
  421. hesk_process_messages($hesklang['no_permission'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  422. }
  423. $att_id = intval(hesk_GET('delatt')) or hesk_error($hesklang['inv_att_id']);
  424. $reply = intval(hesk_GET('reply', 0));
  425. if ($reply < 1) {
  426. $reply = 0;
  427. }
  428. $note = intval(hesk_GET('note', 0));
  429. if ($note < 1) {
  430. $note = 0;
  431. }
  432. /* Get attachment info */
  433. $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "' LIMIT 1");
  434. if (hesk_dbNumRows($res) != 1) {
  435. hesk_process_messages($hesklang['id_not_valid'] . ' (att_id)', 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  436. }
  437. $att = hesk_dbFetchAssoc($res);
  438. /* Is ticket ID valid for this attachment? */
  439. if ($att['ticket_id'] != $trackingID) {
  440. hesk_process_messages($hesklang['trackID_not_found'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999));
  441. }
  442. /* Delete file from server */
  443. hesk_unlink(HESK_PATH . $hesk_settings['attach_dir'] . '/' . $att['saved_name']);
  444. /* Delete attachment from database */
  445. hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "attachments` WHERE `att_id`='" . intval($att_id) . "'");
  446. /* Update ticket or reply in the database */
  447. $revision = sprintf($hesklang['thist12'], hesk_date(), $att['real_name'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
  448. if ($reply) {
  449. 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) . "'");
  450. hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `id`='" . intval($ticket['id']) . "'");
  451. } elseif ($note) {
  452. 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");
  453. hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` SET `attachments`=REPLACE(`attachments`,'" . hesk_dbEscape($att_id . '#' . $att['real_name']) . ",','') WHERE `id`={$note}");
  454. } else {
  455. 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']) . "'");
  456. 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']) . "'");
  457. }
  458. hesk_process_messages($hesklang['kb_att_rem'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  459. }
  460. //-- Update location action
  461. if (isset($_POST['latitude']) && isset($_POST['longitude'])) {
  462. hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `latitude` = '" . hesk_dbEscape($_POST['latitude']) . "',
  463. `longitude` = '" . hesk_dbEscape($_POST['longitude']) . "' WHERE `ID` = " . intval($ticket['id']));
  464. //redirect
  465. hesk_process_messages($hesklang['ticket_location_updated'], 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'SUCCESS');
  466. }
  467. /* Print header */
  468. require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
  469. /* List of categories */
  470. $orderBy = $modsForHesk_settings['category_order_column'];
  471. if ($can_change_cat) {
  472. $result = hesk_dbQuery("SELECT `id`,`name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."categories` WHERE `usage` <> 2 ORDER BY `cat_order` ASC");
  473. } else {
  474. $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");
  475. }
  476. $categories_options = '';
  477. while ($row = hesk_dbFetchAssoc($result)) {
  478. $selected = '';
  479. if ($row['id'] == $ticket['category']) {
  480. $selected = 'selected';
  481. }
  482. $categories_options .= '<option value="' . $row['id'] . '" ' . $selected . '>' . $row['name'] . '</option>';
  483. }
  484. /* List of users */
  485. $admins = array();
  486. $result = hesk_dbQuery("SELECT `id`,`name`,`isadmin`,`categories`,`heskprivileges` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` WHERE `active` = '1' ORDER BY `name` ASC");
  487. while ($row = hesk_dbFetchAssoc($result)) {
  488. /* Is this an administrator? */
  489. if ($row['isadmin']) {
  490. $admins[$row['id']] = $row['name'];
  491. continue;
  492. }
  493. /* Not admin, is user allowed to view tickets? */
  494. if (strpos($row['heskprivileges'], 'can_view_tickets') !== false) {
  495. /* Is user allowed to access this category? */
  496. $cat = substr($row['categories'], 0);
  497. $row['categories'] = explode(',', $cat);
  498. if (in_array($ticket['category'], $row['categories'])) {
  499. $admins[$row['id']] = $row['name'];
  500. continue;
  501. }
  502. }
  503. }
  504. /* Get replies */
  505. if ($ticket['replies']) {
  506. $reply = '';
  507. $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'));
  508. } else {
  509. $reply = false;
  510. }
  511. // Demo mode
  512. if (defined('HESK_DEMO')) {
  513. $ticket['email'] = 'hidden@demo.com';
  514. $ticket['ip'] = '127.0.0.1';
  515. }
  516. // If an email address is tied to this ticket, check if there are any others
  517. $recentTickets = NULL;
  518. if ($ticket['email'] != '') {
  519. $recentTicketsSql = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets`
  520. WHERE `email` = '" . hesk_dbEscape($ticket['email']) . "' AND `trackid` <> '" . hesk_dbEscape($trackingID) . "' ORDER BY `lastchange` DESC LIMIT 5");
  521. while ($recentRow = hesk_dbFetchAssoc($recentTicketsSql)) {
  522. if ($recentTickets === NULL) {
  523. $recentTickets = array();
  524. }
  525. array_push($recentTickets, $recentRow);
  526. }
  527. if ($recentTickets !== NULL) {
  528. $recentTicketsWithStatuses = array();
  529. foreach ($recentTickets as $recentTicket) {
  530. $newRecentTicket = $recentTicket;
  531. $thisTicketStatusRS = hesk_dbQuery("SELECT `ID`, `TextColor` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` WHERE `ID` = " . intval($recentTicket['status']));
  532. $theStatusRow = hesk_dbFetchAssoc($thisTicketStatusRS);
  533. $newRecentTicket['statusText'] = mfh_getDisplayTextForStatusId($theStatusRow['ID']);
  534. $newRecentTicket['statusColor'] = $theStatusRow['TextColor'];
  535. array_push($recentTicketsWithStatuses, $newRecentTicket);
  536. }
  537. $recentTickets = $recentTicketsWithStatuses;
  538. }
  539. }
  540. /* Print admin navigation */
  541. require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
  542. ?>
  543. <aside class="main-sidebar">
  544. <section class="sidebar" style="height: auto">
  545. <ul class="sidebar-menu">
  546. <li class="header text-uppercase"><?php echo $hesklang['information']; ?></li>
  547. <li>
  548. <div class="ticket-info">
  549. <span><?php echo $hesklang['trackID']; ?></span>
  550. <br>
  551. <b>
  552. <?php
  553. $tmp = '';
  554. if ($hesk_settings['sequential']) {
  555. $tmp = '<br> (' . $hesklang['seqid'] . ': ' . $ticket['id'] . ')';
  556. }
  557. echo $trackingID . $tmp; ?>
  558. </b>
  559. </div>
  560. </li>
  561. <?php if ($ticket['language'] !== NULL): ?>
  562. <li>
  563. <div class="ticket-info">
  564. <span><?php echo $hesklang['lgs']; ?></span>
  565. <br><b><?php echo $ticket['language']; ?></b>
  566. </div>
  567. </li>
  568. <?php endif; ?>
  569. <li>
  570. <div class="ticket-info">
  571. <span><?php echo $hesklang['replies']; ?></span>
  572. <br><b><?php echo $ticket['replies']; ?></b>
  573. </div>
  574. </li>
  575. <li>
  576. <div class="ticket-info">
  577. <span><?php echo $hesklang['created_on']; ?></span>
  578. <br><b><?php echo hesk_date($ticket['dt'], true); ?></b>
  579. </div>
  580. </li>
  581. <li>
  582. <div class="ticket-info">
  583. <span><?php echo $hesklang['last_update']; ?></span>
  584. <br><b><?php echo hesk_date($ticket['lastchange'], true); ?></b>
  585. </div>
  586. </li>
  587. <li>
  588. <div class="ticket-info">
  589. <span><?php echo $hesklang['due_date']; ?></span>
  590. <br>
  591. <div id="readonly-due-date">
  592. <b>
  593. <span id="due-date">
  594. <?php
  595. $due_date = $hesklang['none'];
  596. if ($ticket['due_date'] != null) {
  597. $due_date = hesk_date($ticket['due_date'], false, true, false);
  598. $due_date = date('Y-m-d', $due_date);
  599. }
  600. echo $due_date;
  601. ?>
  602. </span>
  603. </b><br>
  604. <button class="btn btn-default btn-sm" id="change-button">
  605. <?php echo $hesklang['chg']; ?>
  606. </button>
  607. </div>
  608. <div id="editable-due-date" style="display: none">
  609. <span class="form-group">
  610. <input title="due-date" type="text" class="form-control datepicker" name="due-date" value="<?php echo $due_date == $hesklang['none'] ? '' : $due_date; ?>">
  611. <?php echo $hesklang['clear_for_no_due_date']; ?>
  612. </span>
  613. <span class="btn-group">
  614. <button id="submit" class="btn btn-primary"><?php echo $hesklang['save']; ?></button>
  615. <button id="cancel" class="btn btn-default"><?php echo $hesklang['cancel']; ?></button>
  616. </span>
  617. </div>
  618. </div>
  619. </li>
  620. <li>
  621. <div class="ticket-info">
  622. <span><?php echo $hesklang['last_replier']; ?></span>
  623. <br><b><?php echo $ticket['repliername']; ?></b>
  624. </div>
  625. </li>
  626. <li>
  627. <div class="ticket-info">
  628. <span><?php echo $hesklang['ts']; ?></span>
  629. <br>
  630. <b>
  631. <span>
  632. <?php echo $ticket['time_worked']; ?>
  633. </span>
  634. </b><br>
  635. <?php if ($can_reply || $can_edit): ?>
  636. <button class="btn btn-default btn-sm" data-toggle="modal" data-target="#timeworkedform">
  637. <?php echo $hesklang['chg']; ?>
  638. </button>
  639. <?php endif; ?>
  640. </div>
  641. </li>
  642. <li>
  643. <div class="ticket-info">
  644. <span><?php echo $hesklang['linked_tickets']; ?></span>
  645. <br>
  646. <b>
  647. <?php
  648. if ($ticket['parent'] != null) {
  649. //-- Get the tracking ID of the parent
  650. $parentRs = hesk_dbQuery('SELECT `trackid` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets`
  651. WHERE `ID` = ' . intval($ticket['parent']));
  652. $parent = hesk_dbFetchAssoc($parentRs);
  653. echo '<a href="admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999) . '&deleteParent=true">
  654. <i class="fa fa-times-circle" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete_relationship'] . '"></i></a>';
  655. echo '&nbsp;<a href="admin_ticket.php?track=' . $parent['trackid'] . '&Refresh=' . mt_rand(10000, 99999) . '">' . $parent['trackid'] . '</a>';
  656. }
  657. //-- Check if any tickets have a parent set to this tracking ID
  658. $hasRows = false;
  659. $childrenRS = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets`
  660. WHERE `parent` = ' . intval($ticket['id']));
  661. while ($row = hesk_dbFetchAssoc($childrenRS)) {
  662. $hasRows = true;
  663. echo '<a href="admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999) . '&deleteChild=' . $row['id'] . '">
  664. <i class="fa fa-times-circle font-icon red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['unlink'] . '"></i></a>';
  665. echo '&nbsp;<a href="admin_ticket.php?track=' . $row['trackid'] . '&Refresh=' . mt_rand(10000, 99999) . '">' . $row['trackid'] . '</a>';
  666. echo '<br>';
  667. }
  668. if (!$hasRows && $ticket['parent'] == null) {
  669. echo $hesklang['none'];
  670. }
  671. ?>
  672. </b>
  673. <?php
  674. if ($can_reply || $can_edit) {
  675. ?>
  676. <div id="addChildText">
  677. <?php echo '<button class="btn btn-default btn-sm" onclick="toggleChildrenForm(true)"><i class="fa fa-plus-circle"></i> ' . $hesklang['add_ticket'] . '</a>'; ?>
  678. </div>
  679. <div id="childrenForm" style="display: none">
  680. <form action="admin_ticket.php" method="post" data-toggle="validator">
  681. <div class="form-group">
  682. <label for="childTrackingId" class="control-label">
  683. <?php echo $hesklang['trackID']; ?>
  684. </label>
  685. <input type="text" name="childTrackingId" class="form-control input-sm"
  686. placeholder="<?php echo htmlspecialchars($hesklang['trackID']); ?>"
  687. data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
  688. required>
  689. <div class="help-block with-errors"></div>
  690. </div>
  691. <div class="btn-group">
  692. <input type="submit" class="btn btn-primary btn-sm"
  693. value="<?php echo $hesklang['save']; ?>">
  694. <button class="btn btn-default btn-sm" onclick="toggleChildrenForm(false); return false;">
  695. <?php echo $hesklang['cancel']; ?>
  696. </button>
  697. </div>
  698. <input type="hidden" name="track" value="<?php echo $trackingID; ?>"/>
  699. <input type="hidden" name="token" value="<?php hesk_token_echo(); ?>"/>
  700. </form>
  701. </div>
  702. <?php } ?>
  703. </div>
  704. </li>
  705. <li>
  706. <div class="ticket-info">
  707. <span><?php echo $hesklang['recent_tickets']; ?></span>
  708. <br>
  709. <?php if ($recentTickets === NULL): ?>
  710. <p style="margin: 0"><b><?php echo $hesklang['none']; ?></b></p>
  711. <?php
  712. else:
  713. foreach ($recentTickets as $recentTicket):
  714. ?>
  715. <p style="margin: 0"><b>
  716. <i class="fa fa-circle" data-toggle="tooltip" data-placement="top"
  717. style="color: <?php echo $recentTicket['statusColor']; ?>"
  718. title="<?php echo sprintf($hesklang['current_status_colon'], $recentTicket['statusText']); ?>"></i>
  719. <?php echo '<a href="admin_ticket.php?track=' . $recentTicket['trackid'] . '&amp;Refresh=' . mt_rand(10000, 99999) . '">' . $recentTicket['trackid'] . '</a>'; ?>
  720. </b></p>
  721. <?php
  722. endforeach;
  723. endif;
  724. ?>
  725. </div>
  726. </li>
  727. </ul>
  728. </section>
  729. </aside>
  730. <div class="modal fade" tabindex="-1" role="dialog" id="timeworkedform">
  731. <div class="modal-dialog" role="document">
  732. <div class="modal-content">
  733. <div class="modal-header">
  734. <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  735. <h4 class="modal-title"><?php echo $hesklang['ts']; ?></h4>
  736. </div>
  737. <div class="modal-body">
  738. <?php $t = hesk_getHHMMSS($ticket['time_worked']); ?>
  739. <form data-toggle="validator" class="form-horizontal" method="post" action="admin_ticket.php" style="margin:0px; padding:0px;">
  740. <div class="form-group">
  741. <label for="h" class="col-sm-4 control-label"><?php echo $hesklang['hh']; ?></label>
  742. <div class="col-sm-8">
  743. <input type="text" name="h" value="<?php echo $t[0]; ?>" size="3"
  744. data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
  745. placeholder="<?php echo htmlspecialchars($hesklang['hh']); ?>"
  746. class="form-control input-sm" required>
  747. </div>
  748. <div class="col-sm-12 text-right">
  749. <div class="help-block with-errors"></div>
  750. </div>
  751. </div>
  752. <div class="form-group input-group-sm">
  753. <label for="m" class="col-sm-4 control-label"><?php echo $hesklang['mm']; ?></label>
  754. <div class="col-sm-8">
  755. <input type="text" name="m" value="<?php echo $t[1]; ?>" size="3"
  756. data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
  757. placeholder="<?php echo htmlspecialchars($hesklang['mm']); ?>"
  758. class="form-control input-sm" required>
  759. </div>
  760. <div class="col-sm-12 text-right">
  761. <div class="help-block with-errors"></div>
  762. </div>
  763. </div>
  764. <div class="form-group input-group-sm">
  765. <label for="s" class="col-sm-4 control-label"><?php echo $hesklang['ss']; ?></label>
  766. <div class="col-sm-8">
  767. <input type="text" name="s" value="<?php echo $t[2]; ?>" size="3"
  768. data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
  769. placeholder="<?php echo htmlspecialchars($hesklang['ss']); ?>"
  770. class="form-control input-sm" required>
  771. </div>
  772. <div class="col-sm-12 text-right">
  773. <div class="help-block with-errors"></div>
  774. </div>
  775. </div>
  776. <div class="text-right">
  777. <div class="btn-group btn-group-sm text-right">
  778. <input class="btn btn-primary" type="submit" value="<?php echo $hesklang['save']; ?>" />
  779. <a class="btn btn-default" data-dismiss="modal"><?php echo $hesklang['cancel']; ?></a>
  780. </div>
  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. </div>
  787. </div>
  788. </div>
  789. <div class="content-wrapper">
  790. <section class="content">
  791. <?php
  792. /* This will handle error, success and notice messages */
  793. hesk_handle_messages();
  794. // Prepare special custom fields
  795. foreach ($hesk_settings['custom_fields'] as $k=>$v) {
  796. if ($v['use'] && hesk_is_custom_field_in_category($k, $ticket['category']) ) {
  797. switch ($v['type']) {
  798. case 'date':
  799. $ticket[$k] = hesk_custom_date_display_format($ticket[$k], $v['value']['date_format']);
  800. break;
  801. }
  802. }
  803. }
  804. ?>
  805. <h1><?php echo $hesklang['ticket_details']; ?></h1>
  806. <div class="box">
  807. <div class="box-header">
  808. <h1 class="box-title">
  809. <?php
  810. echo $ticket['subject'];
  811. if ($ticket['archive']) {
  812. echo ' <span class="label label-primary"><i class="fa fa-tag"></i> ' . $hesklang['archived'] . '</span>';
  813. }
  814. if ($ticket['locked']) {
  815. echo ' <span class="label label-primary"><i class="fa fa-lock"></i> ' . $hesklang['loc'] . '</span>';
  816. }
  817. ?>
  818. </h1>
  819. <div class="pull-right">
  820. <?php echo hesk_getAdminButtons($category['id']);
  821. // Only output JavaScript if we have coordinates
  822. if (strpos($ticket['latitude'], 'E') === false):
  823. ?>
  824. <script>
  825. var latitude = '';
  826. latitude = <?php echo $ticket['latitude'] != '' ? $ticket['latitude'] : -1; ?>;
  827. var longitude = '';
  828. longitude = <?php echo $ticket['longitude'] != '' ? $ticket['longitude'] : -1; ?>;
  829. $('#more-modal').on('shown.bs.modal', function() {
  830. initializeMapForStaff(latitude, longitude, "<?php echo $hesklang['users_location']; ?>");
  831. });
  832. </script>
  833. <?php
  834. endif;
  835. ?>
  836. </div>
  837. </div>
  838. <div class="table-bordered status-row">
  839. <div class="row no-margins med-low-priority">
  840. <?php
  841. $priorityLanguages = array(
  842. 0 => $hesklang['critical'],
  843. 1 => $hesklang['high'],
  844. 2 => $hesklang['medium'],
  845. 3 => $hesklang['low']
  846. );
  847. $options = array();
  848. for ($i = 0; $i < 4; $i++) {
  849. $selected = $ticket['priority'] == $i ? 'selected' : '';
  850. array_push($options, '<option value="' . $i . '" ' . $selected . '>' . $priorityLanguages[$i] . '</option>');
  851. }
  852. echo '<div class="ticket-cell-admin col-md-3 col-sm-12 ';
  853. if ($ticket['priority'] == 0) {
  854. echo 'critical-priority">';
  855. } elseif ($ticket['priority'] == 1) {
  856. echo 'high-priority">';
  857. } else {
  858. echo 'med-low-priority">';
  859. }
  860. echo '<p class="ticket-property-title">' . $hesklang['priority'] . '</p>';
  861. echo '<form style="margin-bottom:0;" id="changePriorityForm" action="priority.php" method="post">
  862. <span style="white-space:nowrap;">
  863. <select class="form-control" name="priority" onchange="document.getElementById(\'changePriorityForm\').submit();">';
  864. echo implode('', $options);
  865. echo '
  866. </select>
  867. <input type="submit" style="display: none" value="' . $hesklang['go'] . '" /><input type="hidden" name="track" value="' . $trackingID . '" />
  868. <input type="hidden" name="token" value="' . hesk_token_echo(0) . '" />';
  869. if ($isManager) {
  870. echo '<input type="hidden" name="isManager" value="1">';
  871. }
  872. echo '</span>
  873. </form>
  874. </div>';
  875. echo '<div class="col-md-3 col-sm-12 ticket-cell-admin"><p class="ticket-property-title">' . $hesklang['status'] . '</p>';
  876. $status_options = array();
  877. $results = mfh_getAllStatuses();
  878. foreach ($results as $row) {
  879. $selected = $ticket['status'] == $row['ID'] ? 'selected' : '';
  880. $status_options[$row['ID']] = '<option value="' . $row['ID'] . '" ' . $selected . '>' . mfh_getDisplayTextForStatusId($row['ID']) . '</option>';
  881. }
  882. echo '
  883. <form role="form" id="changeStatusForm" style="margin-bottom:0;" action="change_status.php" method="post">
  884. <span style="white-space:nowrap;">
  885. <select class="form-control" onchange="document.getElementById(\'changeStatusForm\').submit();" name="s">
  886. ' . implode('', $status_options) . '
  887. </select>
  888. <input type="submit" style="display:none;" value="' . $hesklang['go'] . '" class="btn btn-default" /><input type="hidden" name="track" value="' . $trackingID . '" />
  889. <input type="hidden" name="token" value="' . hesk_token_echo(0) . '" />';
  890. if ($isManager) {
  891. echo '<input type="hidden" name="isManager" value="1">';
  892. }
  893. echo '</span>
  894. </form>
  895. </div>';
  896. echo '<div class="col-md-3 col-sm-12 ticket-cell-admin"><p class="ticket-property-title">' . $hesklang['owner'] . '</p>';
  897. if (hesk_checkPermission('can_assign_others', 0) || $isManager) {
  898. echo '
  899. <form style="margin-bottom:0;" id="changeOwnerForm" action="assign_owner.php" method="post">
  900. <span style="white-space:nowrap;">
  901. <select class="form-control" name="owner" onchange="document.getElementById(\'changeOwnerForm\').submit();">';
  902. $selectedForUnassign = 'selected';
  903. foreach ($admins as $k => $v) {
  904. $selected = '';
  905. if ($k == $ticket['owner']) {
  906. $selectedForUnassign = '';
  907. $selected = 'selected';
  908. }
  909. echo '<option value="' . $k . '" ' . $selected . '>' . $v . '</option>';
  910. }
  911. echo '<option value="-1" ' . $selectedForUnassign . '> &gt; ' . $hesklang['unas'] . ' &lt; </option>';
  912. echo '</select>
  913. <input type="submit" style="display: none" value="' . $hesklang['go'] . '">
  914. <input type="hidden" name="track" value="' . $trackingID . '">
  915. <input type="hidden" name="token" value="' . hesk_token_echo(0) . '">
  916. </span>';
  917. if ( ! $ticket['owner'])
  918. {
  919. echo '<input type="hidden" name="unassigned" value="1">';
  920. }
  921. echo '</form>';
  922. } else {
  923. echo '<p class="ticket-property-text">';
  924. echo isset($admins[$ticket['owner']]) ? $admins[$ticket['owner']] :
  925. ($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']);
  926. echo '</p>';
  927. }
  928. echo '</div>';
  929. echo '<div class="col-md-3 col-sm-12 ticket-cell-admin"><p class="ticket-property-title">' . $hesklang['category'] . '</p>';
  930. if (strlen($categories_options) && ($can_change_cat || $can_change_own_cat)) {
  931. echo '
  932. <form style="margin-bottom:0;" id="changeCategory" action="move_category.php" method="post">
  933. <span style="white-space:nowrap;">
  934. <select name="category" class="form-control" onchange="document.getElementById(\'changeCategory\').submit();">
  935. ' . $categories_options . '
  936. </select>
  937. <input type="submit" style="display: none" value="' . $hesklang['go'] . '">
  938. <input type="hidden" name="track" value="' . $trackingID . '">
  939. <input type="hidden" name="token" value="' . hesk_token_echo(0) . '">
  940. </span>
  941. </form>';
  942. } else {
  943. echo '<p class="ticket-property-text">' . $category['name'] . '</p>';
  944. }
  945. echo '</div>';
  946. ?>
  947. </div>
  948. </div>
  949. </div>
  950. <div class="box box-warning">
  951. <div class="box-header with-border">
  952. <h1 class="box-title">
  953. <?php echo $hesklang['notes']; ?>
  954. </h1>
  955. <div class="box-tools pull-right">
  956. <button type="button" class="btn btn-box-tool" data-widget="collapse">
  957. <i class="fa fa-minus"></i>
  958. </button>
  959. </div>
  960. </div>
  961. <div class="box-body">
  962. <?php
  963. $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'));
  964. if (hesk_dbNumRows($res) > 0):
  965. $first = true;
  966. while ($note = hesk_dbFetchAssoc($res)):
  967. if (!$first) {
  968. echo '<hr>';
  969. } else {
  970. $first = false;
  971. }
  972. ?>
  973. <div class="row">
  974. <div class="col-md-8">
  975. <p><i><?php echo $hesklang['noteby']; ?>
  976. <b><?php echo($note['name'] ? $note['name'] : $hesklang['e_udel']); ?></b></i>
  977. - <?php echo hesk_date($note['dt'], true); ?></p>
  978. <?php
  979. // Message
  980. echo $note['message'];
  981. // Attachments
  982. if ($hesk_settings['attachments']['use'] && strlen($note['attachments'])) {
  983. echo strlen($note['message']) ? '<br><br>' : '';
  984. $att = explode(',', substr($note['attachments'], 0, -1));
  985. $num = count($att);
  986. foreach ($att as $myatt) {
  987. list($att_id, $att_name) = explode('#', $myatt);
  988. // Can edit and delete note (attachments)?
  989. if ($can_del_notes || $note['who'] == $_SESSION['id']) {
  990. // If this is the last attachment and no message, show "delete ticket" link
  991. if ($num == 1 && strlen($note['message']) == 0) {
  992. 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']) . '\');">
  993. <i class="fa fa-times" style="font-size:16px;color:red;" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['dela'] . '"></i>
  994. </a> ';
  995. } // Show "delete attachment" link
  996. else {
  997. 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']) . '\');">
  998. <i class="fa fa-times" style="font-size:16px;color:red;" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['dela'] . '"></i>
  999. </a> ';
  1000. }
  1001. }
  1002. echo '
  1003. <a href="../download_attachment.php?att_id=' . $att_id . '&amp;track=' . $trackingID . '">
  1004. <i class="fa fa-paperclip" style="font-size:16px;" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['dnl'] . ' ' . $att_name . '"></i>
  1005. </a>
  1006. <a href="../download_attachment.php?att_id=' . $att_id . '&amp;track=' . $trackingID . '">' . $att_name . '</a><br />
  1007. ';
  1008. }
  1009. }
  1010. ?>
  1011. </div>
  1012. <div class="col-md-4 text-right">
  1013. <?php if ($can_del_notes || $note['who'] == $_SESSION['id']) { ?>
  1014. <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(); ?>">
  1015. <i class="fa fa-pencil icon-link orange" data-toggle="tooltip" title="<?php echo $hesklang['ednote']; ?>"></i>
  1016. </a>&nbsp;
  1017. <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(); ?>">
  1018. <i class="fa fa-times icon-link red" data-toggle="tooltip" title="<?php echo $hesklang['delnote']; ?>"></i>
  1019. </a>
  1020. <?php } ?>
  1021. </div>
  1022. </div>
  1023. <?php
  1024. endwhile;
  1025. else:
  1026. ?>
  1027. <?php echo $hesklang['no_notes_for_this_ticket']; ?>
  1028. <?php endif; ?>
  1029. <div id="noteform" style="display: none">
  1030. <h3><?php echo $hesklang['addnote']; ?></h3>
  1031. <form class="form-horizontal" data-toggle="validator" method="post" action="admin_ticket.php" style="margin:0px; padding:0px;"
  1032. enctype="multipart/form-data">
  1033. <div class="form-group">
  1034. <label for="note-message" class="control-label col-sm-2"><?php echo $hesklang['message']; ?></label>
  1035. <div class="col-sm-10">
  1036. <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"
  1037. cols="60" required><?php echo isset($_SESSION['note_message']) ? stripslashes(hesk_input($_SESSION['note_message'])) : ''; ?></textarea>
  1038. <div class="help-block with-errors"></div>
  1039. </div>
  1040. </div>
  1041. <div class="form-group">
  1042. <label for="note-attachments" class="control-label col-sm-2">
  1043. <?php echo $hesklang['attachments']; ?>
  1044. </label>
  1045. <div class="col-sm-10">
  1046. <?php build_dropzone_markup(true, 'notesFiledrop'); ?>
  1047. </div>
  1048. </div>
  1049. <?php display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/ticket/upload-attachment.php', 'notesFiledrop'); ?>
  1050. <div class="text-right">
  1051. <i><?php echo $hesklang['nhid']; ?></i>&nbsp;
  1052. <div class="btn-group">
  1053. <button type="button" class="btn btn-danger" data-show="note-footer" data-hide="noteform"><?php echo $hesklang['cancel']; ?></button>
  1054. <input type="submit" class="btn btn-success" value="<?php echo $hesklang['s']; ?>">
  1055. </div>
  1056. <input type="hidden" name="track" value="<?php echo $trackingID; ?>">
  1057. <input type="hidden" name="token" value="<?php hesk_token_echo(); ?>">
  1058. </div>
  1059. </form>
  1060. </div>
  1061. </div>
  1062. <?php if ($can_reply): ?>
  1063. <div class="box-footer" id="note-footer">
  1064. <button class="btn btn-default pull-right" data-show="noteform" data-hide="note-footer">
  1065. <i class="fa fa-plus-circle"></i> <?php echo $hesklang['addnote']; ?>
  1066. </button>
  1067. </div>
  1068. <?php endif; ?>
  1069. </div>
  1070. <?php
  1071. /* Do we need or have any canned responses? */
  1072. $can_options = hesk_printCanned();
  1073. /* Reply form on top? */
  1074. if ($can_reply && $hesk_settings['reply_top'] == 1) {
  1075. hesk_printReplyForm();
  1076. }
  1077. hesk_printTicketReplies();
  1078. echo '<br>';
  1079. /* Reply form on bottom? */
  1080. if ($can_reply && !$hesk_settings['reply_top']) {
  1081. hesk_printReplyForm();
  1082. }
  1083. /* Display ticket history */
  1084. if (strlen($ticket['history'])) {
  1085. ?>
  1086. <div class="box">
  1087. <div class="box-header with-border">
  1088. <h1 class="box-title">
  1089. <?php echo $hesklang['thist']; ?>
  1090. </h1>
  1091. <div class="box-tools pull-right">
  1092. <button type="button" class="btn btn-box-tool" data-widget="collapse">
  1093. <i class="fa fa-minus"></i>
  1094. </button>
  1095. </div>
  1096. </div>
  1097. <div class="box-body">
  1098. <ul>
  1099. <?php echo $ticket['history']; ?>
  1100. </ul>
  1101. </div>
  1102. </div>
  1103. <?php }
  1104. ?>
  1105. </section>
  1106. </div>
  1107. <div style="display: none">
  1108. <p id="lang_ticket_due_date_updated"><?php echo $hesklang['ticket_due_date_updated']; ?></p>
  1109. <p id="lang_none"><?php echo $hesklang['none']; ?></p>
  1110. <p id="lang_error_updating_ticket_due_date"><?php echo $hesklang['error_updating_ticket_due_date']; ?></p>
  1111. </div>
  1112. <?php
  1113. /* Clear unneeded session variables */
  1114. hesk_cleanSessionVars('ticket_message');
  1115. hesk_cleanSessionVars('time_worked');
  1116. hesk_cleanSessionVars('note_message');
  1117. require_once(HESK_PATH . 'inc/footer.inc.php');
  1118. /*** START FUNCTIONS ***/
  1119. function hesk_getAdminButtons($category_id)
  1120. {
  1121. global $hesk_settings, $hesklang, $modsForHesk_settings, $ticket, $reply, $trackingID, $can_edit, $can_archive, $can_delete, $can_resolve, $isManager;
  1122. $options = '';
  1123. /* Edit post */
  1124. if ($can_edit) {
  1125. $tmp = $reply ? '&amp;reply=' . $reply['id'] : '';
  1126. $mgr = $isManager ? '&amp;isManager=true' : '';
  1127. $options .= '<a class="btn btn-default" href="edit_post.php?track=' . $trackingID . $tmp . $mgr . '"><i class="fa fa-pencil orange"></i> ' . $hesklang['edit'] . '</a> ';
  1128. }
  1129. /* Print ticket button */
  1130. $options .= '<a class="btn btn-default" href="../print.php?track=' . $trackingID . '"><i class="fa fa-print"></i> ' . $hesklang['printer_friendly'] . '</a> ';
  1131. /* Copy ticket button */
  1132. $strippedName = strip_tags($ticket['name']);
  1133. $strippedEmail = strip_tags($ticket['email']);
  1134. $linkText = 'new_ticket.php?name=' . $strippedName . '&email=' . $strippedEmail . '&catid=' . $category_id . '&priority=' . $ticket['priority'];
  1135. foreach ($hesk_settings['custom_fields'] as $k => $v) {
  1136. if ($v['use'] == 1) {
  1137. if ($v['type'] == 'checkbox') {
  1138. $value = str_replace('<br />', '-CHECKBOX-', $ticket[$k]);
  1139. } else {
  1140. $value = $ticket[$k];
  1141. }
  1142. $strippedCustomField = strip_tags($value);
  1143. $linkText .= '&c_' . $k . '=' . $strippedCustomField;
  1144. }
  1145. }
  1146. $options .= '<a class="btn btn-default" href="' . $linkText . '"><i class="fa fa-copy fa-fw"></i> ' . $hesklang['copy_ticket'] . '</a> ';
  1147. /* Close/Reopen ticket link */
  1148. $random = rand(10000, 99999);
  1149. $statusSql = 'SELECT `ID`, `IsStaffClosedOption`, `IsStaffReopenedStatus` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `IsStaffClosedOption` = 1 OR `IsStaffReopenedStatus` = 1';
  1150. $statusRs = hesk_dbQuery($statusSql);
  1151. $staffClosedOptionStatus = array();
  1152. $staffReopenedStatus = array();
  1153. while ($statusRow = hesk_dbFetchAssoc($statusRs)) {
  1154. if ($statusRow['IsStaffReopenedStatus'] == 1) {
  1155. $staffReopenedStatus['ID'] = $statusRow['ID'];
  1156. } else {
  1157. $staffClosedOptionStatus['ID'] = $statusRow['ID'];
  1158. }
  1159. }
  1160. $isTicketClosedSql = 'SELECT `IsClosed`, `Closable` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `ID` = ' . intval($ticket['status']);
  1161. $isTicketClosedRs = hesk_dbQuery($isTicketClosedSql);
  1162. $isTicketClosedRow = hesk_dbFetchAssoc($isTicketClosedRs);
  1163. $isTicketClosed = $isTicketClosedRow['IsClosed'];
  1164. $isClosable = $isTicketClosedRow['Closable'] == 'yes' || $isTicketClosedRow['Closable'] == 'sonly';
  1165. $mgr = $isManager ? '&amp;isManager=1' : '';
  1166. if ($isTicketClosed == 0 && $isClosable && $can_resolve) // Ticket is still open
  1167. {
  1168. $options .= '<a class="btn btn-default" href="change_status.php?track=' . $trackingID . $mgr . '&amp;s=' . $staffClosedOptionStatus['ID'] . '&amp;Refresh=' . $random . '&amp;token=' . hesk_token_echo(0) . '">
  1169. <i class="fa fa-check-circle green"></i> ' . $hesklang['close_action'] . '</a> ';
  1170. } elseif ($isTicketClosed == 1) {
  1171. $options .= '<a class="btn btn-default" href="change_status.php?track=' . $trackingID . $mgr . '&amp;s=' . $staffReopenedStatus['ID'] . '&amp;Refresh=' . $random . '&amp;token=' . hesk_token_echo(0) . '">
  1172. <i class="fa fa-folder-open-o green"></i> ' . $hesklang['open_action'] . '</a> ';
  1173. }
  1174. $dropdown = '
  1175. <button type="button" class="btn btn-default" data-toggle="modal" data-target="#more-modal">
  1176. <i class="fa fa-ellipsis-h"></i> ' . hesk_htmlspecialchars($hesklang['more']) . '
  1177. </button>
  1178. <div class="modal fade" id="more-modal" role="dialog">
  1179. <div class="modal-dialog modal-lg">
  1180. <div class="modal-content">
  1181. <div class="modal-header">
  1182. <div class="modal-title">
  1183. <button type="button" class="close cancel-callback" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
  1184. <h4>' . hesk_htmlspecialchars($hesklang['more']) . '</h4>
  1185. </div>
  1186. </div>
  1187. <div class="modal-body">
  1188. ';
  1189. // Location and UA
  1190. if ($modsForHesk_settings['display_user_agent_information']
  1191. && $ticket['user_agent'] !== NULL
  1192. && $ticket['screen_resolution_height'] !== NULL
  1193. && $ticket['screen_resolution_height'] != 0
  1194. && $ticket['screen_resolution_width'] !== NULL
  1195. && $ticket['screen_resolution_width'] != 0
  1196. ) {
  1197. $dropdown .=
  1198. '<div class="panel panel-default">
  1199. <div class="panel-heading">
  1200. <h4 style="text-transform: capitalize"><i class="fa fa-desktop fa-fw"></i> '.$hesklang['device_information'].'</h4>
  1201. </div>
  1202. '.buildUserAgentBody($ticket['user_agent'], $ticket['screen_resolution_width'], $ticket['screen_resolution_height']).'
  1203. </div>';
  1204. } else if ($modsForHesk_settings['display_user_agent_information']) {
  1205. $dropdown .=
  1206. '<div class="panel panel-default">
  1207. <div class="panel-heading">
  1208. <h4 style="text-transform: capitalize"><i class="fa fa-desktop fa-fw"></i> '.$hesklang['device_information'].'</h4>
  1209. </div>
  1210. <div class="panel-body">
  1211. <div class="row">
  1212. <div class="col-xs-12">
  1213. '.$hesklang['no_device_information'].'
  1214. </div>
  1215. </div>
  1216. </div>
  1217. </div>';
  1218. }
  1219. ?>
  1220. <?php
  1221. if ($modsForHesk_settings['request_location']) {
  1222. $hasLocation = true;
  1223. if (strpos($ticket['latitude'], 'E') === false) {
  1224. $locationText = $hesklang['click_for_map'];
  1225. } else {
  1226. $hasLocation = false;
  1227. $locationText = $hesklang['users_location'];
  1228. }
  1229. $dropdown .= '<div class="panel panel-default">
  1230. <div class="panel-heading">
  1231. <h4><i class="fa fa-map-marker fa-fw"></i> ' . $locationText . '</h4>
  1232. </div>';
  1233. if ($hasLocation):
  1234. $dropdown .= '<div id="map" style="height: 500px"></div><br><div class="panel-body">
  1235. <address id="friendly-location" style="font-size: 13px"></address>
  1236. <p id="save-for-address"
  1237. style="font-size: 13px;display:none">' . $hesklang['save_to_see_updated_address'] . '</p>
  1238. <script>
  1239. getFriendlyLocation(' . $ticket['latitude'] . ',
  1240. ' . $ticket['longitude'] . ');
  1241. </script>
  1242. <div class="row">
  1243. <form action="admin_ticket.php" method="post" role="form">
  1244. <input type="hidden" name="track"
  1245. value="'. $trackingID . '">
  1246. <input type="hidden" name="token"
  1247. value="'. hesk_token_echo(0) . '">
  1248. <input type="hidden" name="latitude" id="latitude"
  1249. value="'. $ticket['latitude'] . '">
  1250. <input type="hidden" name="longitude" id="longitude"
  1251. value="'. $ticket['longitude'] . '">
  1252. <div class="col-sm-12">
  1253. <div class="btn-group" style="display: none" id="save-group">
  1254. <input type="submit" class="btn btn-success"
  1255. value="'. $hesklang['save_location'] . '">
  1256. <button type="button" class="btn btn-default" onclick="closeAndReset('. $ticket['latitude'] . ', '. $ticket['longitude'] . ')">' . $hesklang['reset'] . '</button>
  1257. </div>
  1258. </div>
  1259. </form>
  1260. </div>';
  1261. else:
  1262. $dropdown .= '<div class="panel-body">';
  1263. $errorCode = explode('-', $ticket['latitude']);
  1264. $key = 'location_unavailable_' . $errorCode[1];
  1265. $dropdown .= '<h5>' . $hesklang[$key] . '</h5>';
  1266. endif;
  1267. $dropdown .= '</div></div>';
  1268. }
  1269. $dropdown .= '<div class="row">';
  1270. /* Lock ticket button */
  1271. if ($can_resolve) {
  1272. $template =
  1273. '<div class="col-md-6 col-sm-12"><a class="button-link" href="lock.php?track=' . $trackingID . '&amp;locked=%s&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '">
  1274. <div class="panel panel-default">
  1275. <div class="panel-body">
  1276. <h4>
  1277. <i class="fa fa-%s fa-fw"></i> %s
  1278. </h4>
  1279. </div>
  1280. </div>
  1281. </a></div>';
  1282. $dropdown .= $ticket['locked']
  1283. ? sprintf($template, 0, 'unlock', $hesklang['tul'])
  1284. : sprintf($template, 1, 'lock', $hesklang['tlo']);
  1285. }
  1286. /* Tag ticket button */
  1287. if ($can_archive) {
  1288. $template =
  1289. '<div class="col-md-6 col-sm-12"><a class="button-link" href="archive.php?track=' . $trackingID . '&amp;archived=%s&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '">
  1290. <div class="panel panel-default">
  1291. <div class="panel-body">
  1292. <h4>
  1293. <i class="fa fa-tag fa-fw"></i> %s
  1294. </h4>
  1295. </div>
  1296. </div>
  1297. </a></div>';
  1298. $dropdown .= $ticket['archive']
  1299. ? sprintf($template, 0, $hesklang['remove_archive'])
  1300. : sprintf($template, 1, $hesklang['add_archive']);
  1301. }
  1302. /* Import to knowledgebase button */
  1303. if ($hesk_settings['kb_enable'] && hesk_checkPermission('can_man_kb', 0)) {
  1304. $dropdown .=
  1305. '<div class="col-md-6 col-sm-12"><a href="manage_knowledgebase.php?a=import_article&amp;track=' . $trackingID . '" class="button-link">
  1306. <div class="panel panel-default">
  1307. <div class="panel-body">
  1308. <h4>
  1309. <i class="fa fa-lightbulb-o fa-fw"></i> ' . $hesklang['import_kb'] . '
  1310. </h4>
  1311. </div>
  1312. </div>
  1313. </a></div>';
  1314. }
  1315. /* Delete ticket */
  1316. if ($can_delete) {
  1317. if ($reply) {
  1318. $url = 'admin_ticket.php';
  1319. $tmp = 'delete_post=' . $reply['id'];
  1320. $txt = $hesklang['delt'];
  1321. } else {
  1322. $url = 'delete_tickets.php';
  1323. $tmp = 'delete_ticket=1';
  1324. $txt = $hesklang['dele'];
  1325. }
  1326. $dropdown .=
  1327. '<div class="col-md-6 col-sm-12"><a class="button-link" 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) . '?\');">
  1328. <div class="panel panel-default">
  1329. <div class="panel-body danger">
  1330. <h4>
  1331. <i class="fa fa-fw fa-times"></i> ' . $txt . '
  1332. </h4>
  1333. </div>
  1334. </div>
  1335. </a></div>';
  1336. }
  1337. $dropdown .= '</div></div></div></div></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, $can_ban_emails, $can_ban_ips, $trackingID, $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 hesk_date($ticket['dt'], true); ?></span>
  1412. <h3 class="timeline-header">
  1413. <i class="fa fa-fw fa-user" data-toggle="tooltip" title="<?php echo $hesklang['customer']; ?>"></i>
  1414. <?php echo $ticket['name']; ?>
  1415. <?php if ($ticket['email'] !== ''): ?>
  1416. <br>
  1417. <i class="fa fa-fw fa-envelope" data-toggle="tooltip" title="<?php echo $hesklang['email']; ?>"></i>
  1418. <a href="mailto:<?php echo $ticket['email']; ?>"><?php echo $ticket['email']; ?></a>
  1419. <?php
  1420. if ($can_ban_emails && !empty($ticket['email'])) {
  1421. if ($email_id = hesk_isBannedEmail($ticket['email'])) {
  1422. if ($can_unban_emails) {
  1423. echo '<a href="banned_emails.php?a=unban&amp;track=' . $trackingID . '&amp;id=' . intval($email_id) . '&amp;token=' . hesk_token_echo(0) . '">
  1424. <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>
  1425. </a> ';
  1426. } else {
  1427. echo '<i class="fa fa-ban icon-link red" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['eisban'] . '"></i>';
  1428. }
  1429. } else {
  1430. echo '<a href="banned_emails.php?a=ban&amp;track=' . $trackingID . '&amp;email=' . urlencode($ticket['email']) . '&amp;token=' . hesk_token_echo(0) . '">
  1431. <i class="fa fa-ban icon-link gray red-on-hover" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['savebanemail'] . '"></i>
  1432. </a> ';
  1433. }
  1434. }
  1435. endif; ?>
  1436. <br> <i class="fa fa-fw fa-globe" data-toggle="tooltip" title="<?php echo $hesklang['ip']; ?>"></i>
  1437. <?php
  1438. // Format IP for lookup
  1439. if ($ticket['ip'] == '' || $ticket['ip'] == 'Unknown' || $ticket['ip'] == $hesklang['unknown']) {
  1440. echo $hesklang['unknown'];
  1441. } else {
  1442. echo '<a href="../ip_whois.php?ip=' . urlencode($ticket['ip']) . '">' . $ticket['ip'] . '</a>';
  1443. if ($can_ban_ips) {
  1444. if ($ip_id = hesk_isBannedIP($ticket['ip'])) {
  1445. if ($can_unban_ips) {
  1446. echo '<a href="banned_ips.php?a=unban&amp;track=' . $trackingID . '&amp;id=' . intval($ip_id) . '&amp;token=' . hesk_token_echo(0) . '">
  1447. <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>
  1448. </a> ';
  1449. } else {
  1450. echo '<i class="fa fa-ban icon-link red" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['ipisban'] . '"></i>';
  1451. }
  1452. } else {
  1453. echo '<a href="banned_ips.php?a=ban&amp;track=' . $trackingID . '&amp;ip=' . urlencode($ticket['ip']) . '&amp;token=' . hesk_token_echo(0) . '">
  1454. <i class="fa fa-ban gray icon-link red-on-hover" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['savebanip'] . '"></i>
  1455. </a> ';
  1456. }
  1457. }
  1458. }
  1459. ?>
  1460. </h3>
  1461. <div class="timeline-header header-info">
  1462. <?php
  1463. foreach ($hesk_settings['custom_fields'] as $k => $v) {
  1464. if ($v['use'] && $v['place'] == 0 && hesk_is_custom_field_in_category($k, $ticket['category'])) {
  1465. echo '<div class="row">';
  1466. echo '<div class="col-md-3 text-right"><strong>' . $v['name'] . ':</strong></div>';
  1467. if ($v['type'] == 'email') {
  1468. echo '<div class="col-md-9"><a href="mailto:'.$ticket[$k].'">'.$ticket[$k].'</a></div>';
  1469. } else {
  1470. echo '<div class="col-md-9">' . $ticket[$k] . '</div>';
  1471. }
  1472. echo '</div>';
  1473. }
  1474. }
  1475. ?>
  1476. </div>
  1477. <div class="timeline-body">
  1478. <div class="row">
  1479. <div class="col-md-3 text-right">
  1480. <strong><?php echo $hesklang['message_colon']; ?></strong>
  1481. </div>
  1482. <div class="col-md-9">
  1483. <?php
  1484. if ($ticket['message'] != '') {
  1485. if ($ticket['html']) {
  1486. echo hesk_html_entity_decode($ticket['message']);
  1487. } else {
  1488. echo $ticket['message'];
  1489. }
  1490. }
  1491. ?>
  1492. </div>
  1493. </div>
  1494. </div>
  1495. <?php
  1496. $first = true;
  1497. foreach ($hesk_settings['custom_fields'] as $k => $v) {
  1498. if ($v['use'] && $v['place'] && hesk_is_custom_field_in_category($k, $ticket['category'])) {
  1499. if ($first) {
  1500. echo '<div class="timeline-footer">';
  1501. $first = false;
  1502. }
  1503. echo '<div class="row">';
  1504. echo '<div class="col-md-3 text-right"><strong>' . $v['name'] . ':</strong></div>';
  1505. if ($v['type'] == 'email') {
  1506. echo '<div class="col-md-9"><a href="mailto:'.$ticket[$k].'">'.$ticket[$k].'</a></div>';
  1507. } else {
  1508. echo '<div class="col-md-9">' . $ticket[$k] . '</div>';
  1509. }
  1510. echo '</div>';
  1511. }
  1512. }
  1513. if (!$first) {
  1514. echo '</div>';
  1515. }
  1516. ?>
  1517. <?php if (($hesk_settings['attachments']['use'] && strlen($ticket['attachments']))
  1518. || ($hesk_settings['kb_enable'] && $hesk_settings['kb_recommendanswers'] && strlen($ticket['articles']))): ?>
  1519. <div class="timeline-footer">
  1520. <?php
  1521. /* Attachments */
  1522. mfh_listAttachments($ticket['attachments'], 0, true);
  1523. // Show suggested KB articles
  1524. if ($hesk_settings['kb_enable'] && $hesk_settings['kb_recommendanswers'] && strlen($ticket['articles'])) {
  1525. $suggested = array();
  1526. $suggested_list = '';
  1527. // Get article info from the database
  1528. $articles = hesk_dbQuery("SELECT `id`,`subject` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "kb_articles` WHERE `id` IN (" . preg_replace('/[^0-9\,]/', '', $ticket['articles']) . ")");
  1529. while ($article = hesk_dbFetchAssoc($articles)) {
  1530. $suggested[$article['id']] = '<a href="../knowledgebase.php?article=' . $article['id'] . '">' . $article['subject'] . '</a><br />';
  1531. }
  1532. // Loop through the IDs to preserve the order they were suggested in
  1533. $articles = explode(',', $ticket['articles']);
  1534. foreach ($articles as $article) {
  1535. if (isset($suggested[$article])) {
  1536. $suggested_list .= $suggested[$article];
  1537. }
  1538. }
  1539. // Finally print suggested articles
  1540. if (strlen($suggested_list)) {
  1541. $suggested_list = '<hr /><i>' . $hesklang['taws'] . '</i><br />' . $suggested_list . '&nbsp;';
  1542. echo $_SESSION['show_suggested'] ? $suggested_list : '<a href="Javascript:void(0)" onclick="Javascript:hesk_toggleLayerDisplay(\'suggested_articles\')">' . $hesklang['sska'] . '</a><span id="suggested_articles" style="display:none">' . $suggested_list . '</span>';
  1543. }
  1544. }
  1545. ?>
  1546. </div>
  1547. <?php endif; ?>
  1548. <div class="timeline-footer ticket-message-bottom">
  1549. <div class="row">
  1550. <div class="col-md-12 text-right">
  1551. <?php echo hesk_getAdminButtonsInTicket(0); ?>
  1552. </div>
  1553. </div>
  1554. </div>
  1555. </div>
  1556. </li>
  1557. <?php
  1558. }
  1559. function hesk_printTicketReplies()
  1560. {
  1561. global $hesklang, $hesk_settings, $result, $reply;
  1562. echo '<ul class="timeline">';
  1563. if (!$hesk_settings['new_top']) {
  1564. mfh_print_message();
  1565. } else {
  1566. echo '<li class="today-top"><i class="fa fa-clock-o bg-gray" data-toggle="tooltip" title="' . $hesklang['timeline_today'] . '"></i></li>';
  1567. }
  1568. while ($reply = hesk_dbFetchAssoc($result)) {
  1569. $reply['dt'] = hesk_date($reply['dt'], true);
  1570. ?>
  1571. <li>
  1572. <?php if ($reply['staffid']): ?>
  1573. <i class="fa fa-reply bg-orange" data-toggle="tooltip" title="<?php echo $hesklang['reply_by_staff']; ?>"></i>
  1574. <?php else: ?>
  1575. <i class="fa fa-share bg-blue" data-toggle="tooltip" title="<?php echo $hesklang['reply_by_customer']; ?>"></i>
  1576. <?php endif; ?>
  1577. <div class="timeline-item">
  1578. <span class="time"><i class="fa fa-clock-o"></i> <?php echo $reply['dt']; ?></span>
  1579. <h3 class="timeline-header"><?php echo $reply['name']; ?></h3>
  1580. <div class="timeline-body">
  1581. <div class="row">
  1582. <div class="col-md-3 text-right">
  1583. <strong><?php echo $hesklang['message_colon']; ?></strong>
  1584. </div>
  1585. <div class="col-md-9">
  1586. <?php
  1587. if ($reply['html']) {
  1588. echo hesk_html_entity_decode($reply['message']);
  1589. } else {
  1590. echo $reply['message'];
  1591. } ?>
  1592. </div>
  1593. </div>
  1594. </div>
  1595. <?php
  1596. if ($hesk_settings['attachments']['use'] && strlen($reply['attachments'])):
  1597. ?>
  1598. <div class="timeline-footer">
  1599. <?php mfh_listAttachments($reply['attachments'], $reply['id'], true); ?>
  1600. </div>
  1601. <?php endif; ?>
  1602. <div class="timeline-footer">
  1603. <div class="row">
  1604. <div class="col-md-6">
  1605. <?php
  1606. /* Staff rating */
  1607. if ($hesk_settings['rating'] && $reply['staffid']) {
  1608. if ($reply['rating'] == 1) {
  1609. echo '<p class="rate">' . $hesklang['rnh'] . '</p>';
  1610. } elseif ($reply['rating'] == 5) {
  1611. echo '<p class="rate">' . $hesklang['rh'] . '</p>';
  1612. }
  1613. }
  1614. /* Show "unread reply" message? */
  1615. if ($reply['staffid'] && !$reply['read']) {
  1616. echo '<p class="rate">' . $hesklang['unread'] . '</p>';
  1617. }
  1618. ?>
  1619. </div>
  1620. <div class="col-md-6 text-right">
  1621. <?php echo hesk_getAdminButtonsInTicket(); ?>
  1622. </div>
  1623. </div>
  1624. </div>
  1625. </div>
  1626. </li>
  1627. <?php
  1628. }
  1629. if ($hesk_settings['new_top']) {
  1630. mfh_print_message();
  1631. } else {
  1632. echo '<li><i class="fa fa-clock-o bg-gray" data-toggle="tooltip" title="' . $hesklang['timeline_today'] . '"></i></li>';
  1633. }
  1634. echo '</ul>';
  1635. return;
  1636. } // End hesk_printTicketReplies()
  1637. function hesk_printReplyForm()
  1638. {
  1639. global $hesklang, $hesk_settings, $ticket, $admins, $can_options, $can_resolve, $options, $can_assign_self, $isManager, $modsForHesk_settings;
  1640. // Force assigning a ticket before allowing to reply?
  1641. if ($hesk_settings['require_owner'] && ! $ticket['owner'])
  1642. {
  1643. hesk_show_notice($hesklang['atbr'].($can_assign_self ? '<br /><br /><a href="assign_owner.php?track='.$ticket['trackid'].'&amp;owner='.$_SESSION['id'].'&amp;token='.hesk_token_echo(0).'&amp;unassigned=1">'.$hesklang['attm'].'</a>' : ''), $hesklang['owneed']);
  1644. return '';
  1645. }
  1646. ?>
  1647. <!-- START REPLY FORM -->
  1648. <?php if ($modsForHesk_settings['rich_text_for_tickets']): ?>
  1649. <script type="text/javascript">
  1650. /* <![CDATA[ */
  1651. tinyMCE.init({
  1652. mode: "textareas",
  1653. editor_selector: "htmlEditor",
  1654. elements: "content",
  1655. theme: "advanced",
  1656. convert_urls: false,
  1657. plugins: "autolink",
  1658. theme_advanced_buttons1: "cut,copy,paste,|,undo,redo,|,formatselect,fontselect,fontsizeselect,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull",
  1659. theme_advanced_buttons2: "sub,sup,|,charmap,|,bullist,numlist,|,outdent,indent,insertdate,inserttime,preview,|,forecolor,backcolor,|,hr,removeformat,visualaid,|,link,unlink,anchor,image,cleanup,code",
  1660. theme_advanced_buttons3: "",
  1661. theme_advanced_toolbar_location: "top",
  1662. theme_advanced_toolbar_align: "left",
  1663. theme_advanced_statusbar_location: "bottom",
  1664. theme_advanced_resizing: true
  1665. });
  1666. /* ]]> */
  1667. </script>
  1668. <?php endif; ?>
  1669. <div class="box">
  1670. <div class="box-header with-border">
  1671. <h1 class="box-title">
  1672. <?php echo $hesklang['add_reply']; ?>
  1673. </h1>
  1674. <div class="box-tools pull-right">
  1675. <button type="button" class="btn btn-box-tool" data-widget="collapse">
  1676. <i class="fa fa-minus"></i>
  1677. </button>
  1678. </div>
  1679. </div>
  1680. <div class="box-body">
  1681. <?php
  1682. $onsubmit = 'onsubmit="force_stop();"';
  1683. if ($modsForHesk_settings['rich_text_for_tickets']) {
  1684. $onsubmit = 'onsubmit="force_stop();return validateRichText(\'message-help-block\', \'message-group\', \'message\', \''.htmlspecialchars($hesklang['this_field_is_required']).'\')"';
  1685. }
  1686. ?>
  1687. <form role="form" data-toggle="validator" class="form-horizontal" method="post" action="admin_reply_ticket.php"
  1688. enctype="multipart/form-data" name="form1" <?php echo $onsubmit; ?>>
  1689. <?php
  1690. /* Ticket assigned to someone else? */
  1691. if ($ticket['owner'] && $ticket['owner'] != $_SESSION['id'] && isset($admins[$ticket['owner']])) {
  1692. hesk_show_notice($hesklang['nyt'] . ' ' . $admins[$ticket['owner']]);
  1693. }
  1694. /* Ticket locked? */
  1695. if ($ticket['locked']) {
  1696. hesk_show_notice($hesklang['tislock']);
  1697. }
  1698. // Track time worked?
  1699. if ($hesk_settings['time_worked']) {
  1700. ?>
  1701. <div class="form-group">
  1702. <label for="time_worked" class="col-sm-3 control-label"><?php echo $hesklang['ts']; ?></label>
  1703. <div class="col-sm-6">
  1704. <input type="text" class="form-control" name="time_worked" id="time_worked" size="10"
  1705. value="<?php echo(isset($_SESSION['time_worked']) ? hesk_getTime($_SESSION['time_worked']) : '00:00:00'); ?>"/>
  1706. </div>
  1707. <div class="col-sm-3 text-right">
  1708. <div class="btn-group">
  1709. <input type="button" class="btn btn-success" onclick="ss()" id="startb"
  1710. value="<?php echo $hesklang['start']; ?>"/>
  1711. <input type="button" class="btn btn-danger" onclick="r()"
  1712. value="<?php echo $hesklang['reset']; ?>"/>
  1713. </div>
  1714. </div>
  1715. </div>
  1716. <?php
  1717. }
  1718. /* Do we have any canned responses? */
  1719. if (strlen($can_options)) {
  1720. ?>
  1721. <div class="form-group">
  1722. <label for="saved_replies" class="col-sm-3 control-label"><?php echo $hesklang['saved_replies']; ?></label>
  1723. <div class="col-sm-9">
  1724. <label><input type="radio" name="mode" id="modeadd" value="1"
  1725. checked="checked"/> <?php echo $hesklang['madd']; ?></label><br/>
  1726. <label><input type="radio" name="mode" id="moderep" value="0"/> <?php echo $hesklang['mrep']; ?>
  1727. </label>
  1728. <select class="form-control" name="saved_replies" onchange="setMessage(this.value)">
  1729. <option value="0"> - <?php echo $hesklang['select_empty']; ?> -</option>
  1730. <?php echo $can_options; ?>
  1731. </select>
  1732. </div>
  1733. </div>
  1734. <?php
  1735. }
  1736. ?>
  1737. <div class="form-group" id="message-group">
  1738. <label for="message" class="col-sm-3 control-label"><?php echo $hesklang['message']; ?><span
  1739. class="important">*</span></label>
  1740. <div class="col-sm-9">
  1741. <span id="HeskMsg">
  1742. <textarea class="form-control htmlEditor" name="message" id="message" rows="12"
  1743. placeholder="<?php echo htmlspecialchars($hesklang['message']); ?>" cols="72"
  1744. data-error="<?php echo htmlspecialchars($hesklang['enter_message']); ?>"
  1745. required><?php
  1746. // Do we have any message stored in session?
  1747. if (isset($_SESSION['ticket_message'])) {
  1748. echo stripslashes(hesk_input($_SESSION['ticket_message']));
  1749. } // Perhaps a message stored in reply drafts?
  1750. else {
  1751. $res = hesk_dbQuery("SELECT `message` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "reply_drafts` WHERE `owner`=" . intval($_SESSION['id']) . " AND `ticket`=" . intval($ticket['id']) . " LIMIT 1");
  1752. if (hesk_dbNumRows($res) == 1) {
  1753. echo hesk_dbResult($res);
  1754. }
  1755. }
  1756. ?></textarea>
  1757. <div class="help-block with-errors" id="message-help-block"></div></span>
  1758. </div>
  1759. </div>
  1760. <?php
  1761. /* attachments */
  1762. if ($hesk_settings['attachments']['use']) {
  1763. ?>
  1764. <div class="form-group">
  1765. <label for="attachments" class="col-sm-3 control-label"><?php echo $hesklang['attachments']; ?>:</label>
  1766. <div class="col-sm-9">
  1767. <?php build_dropzone_markup(true); ?>
  1768. </div>
  1769. </div>
  1770. <?php
  1771. display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/ticket/upload-attachment.php');
  1772. }
  1773. ?>
  1774. <div class="form-group">
  1775. <label for="options" class="col-sm-3 control-label"><?php echo $hesklang['addop']; ?>:</label>
  1776. <div class="col-sm-9">
  1777. <?php
  1778. if ($ticket['owner'] != $_SESSION['id'] && $can_assign_self) {
  1779. if (empty($ticket['owner'])) {
  1780. echo '<label><input type="checkbox" name="assign_self" value="1" checked="checked" /> <b>' . $hesklang['asss2'] . '</b></label><br />';
  1781. } else {
  1782. echo '<label><input type="checkbox" name="assign_self" value="1" /> ' . $hesklang['asss2'] . '</label><br />';
  1783. }
  1784. }
  1785. ?>
  1786. <div class="form-inline">
  1787. <label>
  1788. <input type="checkbox" name="set_priority"
  1789. value="1"/> <?php echo $hesklang['change_priority']; ?>
  1790. </label>
  1791. <select class="form-control" name="priority">
  1792. <?php echo implode('', $options); ?>
  1793. </select>
  1794. </div>
  1795. <br/>
  1796. <label>
  1797. <input type="checkbox" name="signature" value="1"
  1798. checked="checked"/> <?php echo $hesklang['attach_sign']; ?>
  1799. </label>
  1800. (<a href="profile.php"><?php echo $hesklang['profile_settings']; ?></a>)
  1801. <br/>
  1802. <label>
  1803. <input type="checkbox" name="no_notify"
  1804. value="1" <?php echo ($_SESSION['notify_customer_reply'] && !empty($ticket['email'])) ? '' : 'checked="checked" '; ?> <?php if (empty($ticket['email'])) {
  1805. echo 'disabled';
  1806. } ?>> <?php echo $hesklang['dsen']; ?>
  1807. </label><br/><br/>
  1808. <?php if (empty($ticket['email'])) {
  1809. echo '<input type="hidden" name="no_notify" value="1">';
  1810. } ?>
  1811. <input type="hidden" name="orig_id" value="<?php echo $ticket['id']; ?>"/>
  1812. <input type="hidden" name="token" value="<?php hesk_token_echo(); ?>"/>
  1813. <div class="btn-group dropup">
  1814. <input class="btn btn-primary" type="submit" value="<?php echo $hesklang['submit_reply']; ?>">
  1815. <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown"
  1816. aria-expanded="false">
  1817. <span class="caret"></span>
  1818. <span class="sr-only">Toggle Dropdown</span>
  1819. </button>
  1820. <ul class="dropdown-menu" role="menu">
  1821. <li><a>
  1822. <button class="dropdown-submit" type="submit" name="submit_as_customer">
  1823. <?php echo $hesklang['sasc']; ?>
  1824. </button>
  1825. </a></li>
  1826. <li class="divider"></li>
  1827. <?php
  1828. $statuses = mfh_getAllStatuses();
  1829. foreach ($statuses as $status) {
  1830. if ($status['IsClosed'] == '1' && !$can_resolve) {
  1831. continue;
  1832. }
  1833. echo '<li><a>
  1834. <button class="dropdown-submit" type="submit" name="submit_as_status" value="' . $status['ID'] . '"">
  1835. ' . $hesklang['submit_reply'] . ' ' . $hesklang['and_change_status_to'] . ' <b>
  1836. <span style="color:' . $status['TextColor'] . '">' . mfh_getDisplayTextForStatusId($status['ID']) . '</span></b>
  1837. </button>
  1838. </a></li>';
  1839. }
  1840. ?>
  1841. </ul>
  1842. </div>
  1843. <input class="btn btn-default" type="submit" name="save_reply" value="<?php echo $hesklang['sacl']; ?>">
  1844. <?php if ($isManager): ?>
  1845. <input type="hidden" name="isManager" value="1">
  1846. <?php endif; ?>
  1847. </div>
  1848. </div>
  1849. </form>
  1850. </div>
  1851. </div>
  1852. <!-- END REPLY FORM -->
  1853. <?php
  1854. } // End hesk_printReplyForm()
  1855. function hesk_printCanned()
  1856. {
  1857. global $hesklang, $hesk_settings, $can_reply, $ticket, $modsForHesk_settings;
  1858. /* Can user reply to tickets? */
  1859. if (!$can_reply) {
  1860. return '';
  1861. }
  1862. /* Get canned replies from the database */
  1863. $res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "std_replies` ORDER BY `reply_order` ASC");
  1864. /* If no canned replies return empty */
  1865. if (!hesk_dbNumRows($res)) {
  1866. return '';
  1867. }
  1868. /* We do have some replies, print the required Javascript and select field options */
  1869. $can_options = '';
  1870. ?>
  1871. <script language="javascript" type="text/javascript"><!--
  1872. // -->
  1873. var myMsgTxt = new Array();
  1874. myMsgTxt[0] = '';
  1875. <?php
  1876. while ($mysaved = hesk_dbFetchRow($res))
  1877. {
  1878. $can_options .= '<option value="' . $mysaved[0] . '">' . $mysaved[1]. "</option>\n";
  1879. if ($modsForHesk_settings['rich_text_for_tickets']) {
  1880. $theMessage = hesk_html_entity_decode($mysaved[2]);
  1881. $theMessage = addslashes($theMessage);
  1882. echo 'myMsgTxt['.$mysaved[0].']=\''.str_replace("\r\n","\\r\\n' + \r\n'", $theMessage)."';\n";
  1883. } else {
  1884. echo 'myMsgTxt['.$mysaved[0].']=\''.str_replace("\r\n","\\r\\n' + \r\n'", addslashes($mysaved[2]))."';\n";
  1885. }
  1886. }
  1887. ?>
  1888. function setMessage(msgid) {
  1889. var isHtml = <?php echo hesk_jsString($modsForHesk_settings['rich_text_for_tickets']); ?>;
  1890. var myMsg = myMsgTxt[msgid];
  1891. if (myMsg == '') {
  1892. if (document.form1.mode[1].checked) {
  1893. document.getElementById('message').value = '';
  1894. }
  1895. return true;
  1896. }
  1897. myMsg = myMsg.replace(/%%HESK_ID%%/g, '<?php echo hesk_jsString($ticket['id']); ?>');
  1898. myMsg = myMsg.replace(/%%HESK_TRACKID%%/g, '<?php echo hesk_jsString($ticket['trackid']); ?>');
  1899. myMsg = myMsg.replace(/%%HESK_TRACK_ID%%/g, '<?php echo hesk_jsString($ticket['trackid']); ?>');
  1900. myMsg = myMsg.replace(/%%HESK_NAME%%/g, '<?php echo hesk_jsString($ticket['name']); ?>');
  1901. myMsg = myMsg.replace(/%%HESK_EMAIL%%/g, '<?php echo hesk_jsString($ticket['email']); ?>');
  1902. myMsg = myMsg.replace(/%%HESK_OWNER%%/g, '<?php echo hesk_jsString( isset($admins[$ticket['owner']]) ? $admins[$ticket['owner']] : ''); ?>');
  1903. <?php
  1904. for ($i=1; $i<=50; $i++) {
  1905. echo 'myMsg = myMsg.replace(/%%HESK_custom'.$i.'%%/g, \''.hesk_jsString($ticket['custom'.$i]).'\');';
  1906. }
  1907. ?>
  1908. if (document.getElementById) {
  1909. if (document.getElementById('moderep').checked) {
  1910. if (isHtml) {
  1911. tinymce.get("message").setContent('');
  1912. tinymce.get("message").execCommand('mceInsertRawHTML', false, myMsg);
  1913. } else {
  1914. myMsg = $('<textarea />').html(myMsg).text();
  1915. $('#message').val(myMsg).trigger('input');
  1916. }
  1917. }
  1918. else {
  1919. if (isHtml) {
  1920. var oldMsg = tinymce.get("message").getContent();
  1921. tinymce.get("message").setContent('');
  1922. tinymce.get("message").execCommand('mceInsertRawHTML', false, oldMsg + myMsg);
  1923. } else {
  1924. var oldMsg = $('#message').val();
  1925. var newMsg = $('<textarea />').html(oldMsg + '\n' + myMsg).text();
  1926. $('#message').val(newMsg).trigger('input');
  1927. }
  1928. }
  1929. }
  1930. else {
  1931. if (document.form1.mode[0].checked) {
  1932. document.form1.message.value = myMsg;
  1933. }
  1934. else {
  1935. var oldMsg = document.form1.message.value;
  1936. document.form1.message.value = oldMsg + myMsg;
  1937. }
  1938. }
  1939. }
  1940. //-->
  1941. </script>
  1942. <?php
  1943. /* Return options for select box */
  1944. return $can_options;
  1945. } // End hesk_printCanned()
  1946. function buildUserAgentBody($user_agent, $width, $height) {
  1947. global $hesklang;
  1948. return '
  1949. <script>
  1950. var userAgent = platform.parse(\'' . addslashes($user_agent) . '\');
  1951. console.log(userAgent);
  1952. var screenResWidth = ' . intval($width) . ';
  1953. var screenResHeight = ' . intval($height) . ';
  1954. </script>
  1955. <table class="table table-striped">
  1956. <tbody>
  1957. <tr>
  1958. <td><strong>' . $hesklang['operating_system'] . '</strong>
  1959. </td>
  1960. <td id="operating-system">&nbsp;</td>
  1961. <script>$(\'#operating-system\').html(userAgent.os.toString());</script>
  1962. </tr>
  1963. <tr>
  1964. <td><strong>' . $hesklang['browser'] . '</strong></td>
  1965. <td id="browser">&nbsp;</td>
  1966. <script>$(\'#browser\').html(userAgent.name + \' \' + userAgent.version);</script>
  1967. </tr>
  1968. <tr>
  1969. <td><strong>' . $hesklang['screen_resolution'] . '</strong>
  1970. </td>
  1971. <td id="screen-resolution">&nbsp;</td>
  1972. <script>$(\'#screen-resolution\').html(screenResWidth + \' x \' + screenResHeight);</script>
  1973. </tr>
  1974. </tbody>
  1975. </table>';
  1976. }
  1977. ?>