Merge branch '3-4-0' into 'master'

2018.1.0 Update

See merge request mike-koch/Mods-for-HESK!100
master^2
Mike Koch 6 years ago
commit 16b1e7c491

6
.gitignore vendored

@ -8,6 +8,7 @@ admin/archive.php
admin/custom_statuses.php
admin/email_templates.php
admin/generate_spam_question.php
admin/resend_notification.php
admin/test_connection.php
attachments/index.htm
cache/
@ -19,6 +20,7 @@ header.txt
hesk_settings.inc.php
img/add_article.png
img/add_category.png
img/anonymize.png
img/article_text.png
img/autoassign_off.png
img/autoassign_on.png
@ -34,8 +36,10 @@ img/delete.png
img/delete_off.png
img/delete_ticket.png
img/edit.png
img/email.png
img/error.png
img/existingticket.png
img/export.png
img/flag_critical.png
img/flag_high.png
img/flag_low.png
@ -81,6 +85,7 @@ img/lock.png
img/login.png
img/mail.png
img/manage.png
img/menu.png
img/minus.gif
img/minusbottom.gif
img/minustop.gif
@ -260,6 +265,7 @@ language/en/emails/new_ticket.txt
language/en/emails/new_ticket_staff.txt
language/en/emails/ticket_assigned_to_you.txt
language/en/index.htm
language/en/text.php
language/index.htm
language/*
!language/en

@ -108,23 +108,17 @@ else {
</div>
</div>
<?php
$hesk_settings['hesk_license']('HMgPSAxOw0KaWYgKGZpbGVfZXhpc3RzKEhFU0tfUEFUSCAuI
CdoZXNrX2xpY2Vuc2UucGhwJykpDQp7DQokaCA9ICghZW1wdHkoJF9TRVJWRVJbJ0hUVFBfSE9TVCddK
SkgPyAkX1NFUlZFUlsnSFRUUF9IT1NUJ10gOiAoKCFlbXB0eSgkX1NFUlZFUlsnU0VSVkVSX05BTUUnX
SkpID8gJF9TRVJWRVJbJ1NFUlZFUl9OQU1FJ10gOiBnZXRlbnYoJ1NFUlZFUl9OQU1FJykpOw0KJGggP
SBzdHJfcmVwbGFjZSgnd3d3LicsJycsc3RydG9sb3dlcigkaCkpOw0KaW5jbHVkZShIRVNLX1BBVEggL
iAnaGVza19saWNlbnNlLnBocCcpOw0KaWYgKGlzc2V0KCRoZXNrX3NldHRpbmdzWydsaWNlbnNlJ10pI
CYmIHN0cnBvcygkaGVza19zZXR0aW5nc1snbGljZW5zZSddLHNoYTEoJGguJ2gzJkZwMiNMYUEmNTkhd
yg4LlpjXSordVI1MTInKSkgIT09IGZhbHNlKQ0Kew0KJHMgPSAwOw0KfQ0KZWxzZQ0Kew0KZWNobyAnP
HAgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyO2NvbG9yOnJlZDsiPklOVkFMSUQgTElDRU5TRSAoTk9UI
FJFR0lTVEVSRUQgRk9SICcuJGguJykhPC9wPic7DQp9DQp9DQppZiAoJHMpDQp7DQplY2hvICc8aHIgL
z48dGFibGUgYm9yZGVyPSIwIiB3aWR0aD0iMTAwJSI+PHRyPjx0ZD48Yj4nLiRoZXNrbGFuZ1sncmVtb
3ZlX3N0YXRlbWVudCddLic8L2I+PC90ZD48dGQgc3R5bGU9InRleHQtYWxpZ246cmlnaHQiPjxhIGhyZ
WY9IkphdmFzY3JpcHQ6dm9pZCgwKSIgb25jbGljaz0iYWxlcnQoXCcnLiRoZXNrbGFuZ1snc3VwcG9yd
F9ub3RpY2UnXS4nXCcpIj4nLiRoZXNrbGFuZ1snc2gnXS4nPC9hPjwvdGQ+PC90cj48L3RhYmxlPjxwP
icuJGhlc2tsYW5nWydzdXBwb3J0X3JlbW92ZSddLicuIDxhIGhyZWY9Imh0dHBzOi8vd3d3Lmhlc2suY
29tL2J1eS5waHAiIHRhcmdldD0iX2JsYW5rIj4nLiRoZXNrbGFuZ1snY2xpY2tfaW5mbyddLic8L2E+P
C9wPjxociAvPic7DQp9DQo=', "\112");
/*******************************************************************************
The code below handles HESK licensing. Removing or modifying this code without
purchasing a HESK license is strictly prohibited.
To purchase a HESK license and support future HESK development please visit:
https://www.hesk.com/buy.php
*******************************************************************************/
$x1a="\142a".chr(0163).chr(847249408>>23)."\66\x34".chr(796917760>>23)."\x65\156\143".chr(0157)."\x64\145";$hesk_settings['hesk_license']($x1a("\x3c\150r\x20\57\76".chr(503316480>>23)."\x74\141\142l\x65\40".chr(0142).chr(0157).chr(0162)."\144\145r\x3d\42\60".chr(285212672>>23)."\x20\x77\x69".chr(0144)."th".chr(511705088>>23)."\x22".chr(061)."\60\60\x25\42".chr(520093696>>23)."\x3c\164".chr(0162).">\74t\x64\x3e\x3c".chr(0142).chr(076).$hesklang[chr(956301312>>23)."\145\155\157\x76e".chr(796917760>>23)."\x73ta\164e\x6d".chr(847249408>>23)."\156\x74"].chr(503316480>>23)."\x2f\142\x3e".chr(074)."\57t\x64\76".chr(074)."td".chr(268435456>>23)."\x73ty\154\x65\x3d\x22te".chr(1006632960>>23)."t\x2d\141\x6c\x69".chr(0147).chr(922746880>>23)."\x3ar\151\x67ht\"\76".chr(503316480>>23)."\141 \x68\162\145\146\x3d\42".chr(0112).chr(813694976>>23)."v\141".chr(0163).chr(830472192>>23)."\162\x69".chr(0160).chr(0164)."\x3a".chr(989855744>>23)."\157\151d\50\x30".chr(343932928>>23).chr(042)."\40onc\154\151\143\153\x3d".chr(042)."\x61\x6c\145\x72t(\x27".$hesklang["\163".chr(981467136>>23)."\x70".chr(939524096>>23).chr(0157)."\162\164\137n".chr(931135488>>23)."\x74\151".chr(0143)."\x65"].chr(047)."\51\42\x3e".$hesklang["\x73\x68"]."\74".chr(394264576>>23)."\x61\x3e\74\57\164d\76\x3c/\x74\162\76".chr(503316480>>23).chr(057)."t\x61\x62\x6ce\x3e\x3c\x70\x3e".$hesklang[chr(0163)."\x75ppo\x72\x74\137".chr(956301312>>23).chr(847249408>>23)."\155".chr(931135488>>23)."v\x65"]."\x2e\x20\x3c".chr(813694976>>23)."\40\x68re\x66\x3d".chr(285212672>>23)."\150".chr(973078528>>23).chr(973078528>>23)."\160\x73".chr(486539264>>23)."\57\x2f".chr(998244352>>23)."\x77\167".chr(056)."\150".chr(847249408>>23)."s\153\56\x63\157".chr(0155)."/".chr(0142)."\165\171.".chr(0160)."h\x70".chr(285212672>>23)."\x20\x74\141".chr(0162)."g".chr(847249408>>23)."\164\x3d".chr(042)."\137b\x6c".chr(813694976>>23)."\x6ek\x22\76".$hesklang["\x63\154\151\143\153\x5f".chr(880803840>>23)."\x6e".chr(855638016>>23).chr(0157)]."\x3c/\141\x3e\x3c\x2fp".chr(076)."<\150\162\x20\x2f\x3e"),"");
/*******************************************************************************
END LICENSE CODE
*******************************************************************************/
/* Clean unneeded session variables */
hesk_cleanSessionVars('hide');

@ -30,6 +30,7 @@ $hesk_settings['language_default'] = $hesk_settings['language'];
require(HESK_PATH . 'inc/common.inc.php');
$hesk_settings['language'] = $hesk_settings['language_default'];
require(HESK_PATH . 'inc/admin_functions.inc.php');
require(HESK_PATH . 'inc/setup_functions.inc.php');
require(HESK_PATH . 'inc/mail_functions.inc.php');
hesk_load_database_functions();
@ -54,8 +55,6 @@ $help_folder = '../language/' . $hesk_settings['languages'][$hesk_settings['lang
$enable_save_settings = 0;
$enable_use_attachments = 0;
$server_time = date('H:i', strtotime(hesk_date()));
// Print header
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
@ -82,64 +81,6 @@ if (defined('HESK_DEMO')) {
$hesk_settings['imap_password'] = $hesklang['hdemo'];
}
// Check file attachment limits
if ($hesk_settings['attachments']['use'] && !defined('HESK_DEMO')) {
// Check number of attachments per post
if (version_compare(phpversion(), '5.2.12', '>=') && @ini_get('max_file_uploads') && @ini_get('max_file_uploads') < $hesk_settings['attachments']['max_number']) {
hesk_show_notice($hesklang['fatte1']);
}
// Check max attachment size
$tmp = @ini_get('upload_max_filesize');
if ($tmp) {
$last = strtoupper(substr($tmp, -1));
$number = substr($tmp, 0, -1);
switch ($last) {
case 'K':
$tmp = $number * 1024;
break;
case 'M':
$tmp = $number * 1048576;
break;
case 'G':
$tmp = $number * 1073741824;
break;
default:
$tmp = $number;
}
if ($tmp < $hesk_settings['attachments']['max_size']) {
hesk_show_notice($hesklang['fatte2']);
}
}
// Check max post size
$tmp = @ini_get('post_max_size');
if ($tmp) {
$last = strtoupper(substr($tmp, -1));
$number = substr($tmp, 0, -1);
switch ($last) {
case 'K':
$tmp = $number * 1024;
break;
case 'M':
$tmp = $number * 1048576;
break;
case 'G':
$tmp = $number * 1073741824;
break;
default:
$tmp = $number;
}
if ($tmp < ($hesk_settings['attachments']['max_size'] * $hesk_settings['attachments']['max_number'] + 524288)) {
hesk_show_notice($hesklang['fatte3']);
}
}
}
$hesklang['err_custname'] = addslashes($hesklang['err_custname']);
@ -250,32 +191,6 @@ $modsForHesk_settings = mfh_getSettings();
}
};
var server_time = "<?php echo $server_time; ?>";
var today = new Date();
today.setHours(server_time.substr(0, server_time.indexOf(":")));
today.setMinutes(server_time.substr(server_time.indexOf(":") + 1));
function startTime() {
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
h = checkTime(h);
m = checkTime(m);
document.getElementById('servertime').innerHTML = h + ":" + m;
s = s + 1;
today.setSeconds(s);
t = setTimeout(function() { startTime(); },1000);
}
function checkTime(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
function checkRequiredEmail(field) {
if (document.getElementById('s_require_email_0').checked && document.getElementById('s_email_view_ticket').checked) {
if (field == 's_require_email_0' && confirm('<?php echo addslashes($hesklang['re_confirm1']); ?>')) {
@ -339,6 +254,87 @@ $modsForHesk_settings = mfh_getSettings();
<?php
/* This will handle error, success and notice messages */
hesk_handle_messages();
// Check file attachment limits
if ($hesk_settings['attachments']['use'] && !defined('HESK_DEMO')) {
// Check number of attachments per post
if (version_compare(phpversion(), '5.2.12', '>=') && @ini_get('max_file_uploads') && @ini_get('max_file_uploads') < $hesk_settings['attachments']['max_number']) {
hesk_show_notice($hesklang['fatte1']);
}
// Check max attachment size
$tmp = @ini_get('upload_max_filesize');
if ($tmp) {
$last = strtoupper(substr($tmp, -1));
$number = substr($tmp, 0, -1);
switch ($last) {
case 'K':
$tmp = $number * 1024;
break;
case 'M':
$tmp = $number * 1048576;
break;
case 'G':
$tmp = $number * 1073741824;
break;
default:
$tmp = $number;
}
if ($tmp < $hesk_settings['attachments']['max_size']) {
hesk_show_notice($hesklang['fatte2']);
}
}
// Check max post size
$tmp = @ini_get('post_max_size');
if ($tmp) {
$last = strtoupper(substr($tmp, -1));
$number = substr($tmp, 0, -1);
switch ($last) {
case 'K':
$tmp = $number * 1024;
break;
case 'M':
$tmp = $number * 1048576;
break;
case 'G':
$tmp = $number * 1073741824;
break;
default:
$tmp = $number;
}
if ($tmp < ($hesk_settings['attachments']['max_size'] * $hesk_settings['attachments']['max_number'] + 524288)) {
hesk_show_notice($hesklang['fatte3']);
}
}
// If SMTP server is used, "From email" should match SMTP username
if ($hesk_settings['smtp'] && strtolower($hesk_settings['smtp_user']) != strtolower($hesk_settings['noreply_mail']) && hesk_validateEmail($hesk_settings['smtp_user'], 'ERR', 0)) {
hesk_show_notice(sprintf($hesklang['from_warning'], $hesklang['email_noreply'], $hesklang['tab_1'], $hesk_settings['smtp_user']));
}
// If POP3 fetching is active, no user should have the same email address
if ($hesk_settings['pop3'] && hesk_validateEmail($hesk_settings['pop3_user'], 'ERR', 0)) {
$res = hesk_dbQuery("SELECT `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `email` LIKE '".hesk_dbEscape($hesk_settings['pop3_user'])."'");
if (hesk_dbNumRows($res) > 0) {
hesk_show_notice(sprintf($hesklang['pop3_warning'], hesk_dbResult($res,0,0), $hesk_settings['pop3_user']) . "<br /><br />" . $hesklang['fetch_warning'], $hesklang['warn']);
}
}
// If IMAP fetching is active, no user should have the same email address
if ($hesk_settings['imap'] && hesk_validateEmail($hesk_settings['imap_user'], 'ERR', 0)) {
$res = hesk_dbQuery("SELECT `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `email` LIKE '".hesk_dbEscape($hesk_settings['imap_user'])."'");
if (hesk_dbNumRows($res) > 0) {
hesk_show_notice(sprintf($hesklang['imap_warning'], hesk_dbResult($res,0,0), $hesk_settings['imap_user']) . "<br /><br />" . $hesklang['fetch_warning'], $hesklang['warn']);
}
}
}
?>
<div class="box">
<div class="box-header with-border">
@ -1495,14 +1491,14 @@ $modsForHesk_settings = mfh_getSettings();
<br/>
<div class="radio"><label><input type="radio" name="s_recaptcha_use" value="2"
onclick="javascript:hesk_toggleLayer('recaptcha','block')" <?php echo $on2; ?> /> <?php echo $hesklang['sir2']; ?>
onclick="javascript:hesk_toggleLayer('recaptcha','block')" <?php echo $on2; ?> /> <?php echo $hesklang['recaptcha']; ?>
</label> <a href="Javascript:void(0)"
onclick="Javascript:hesk_window('<?php echo $help_folder; ?>helpdesk.html#64','400','500')"><i
class="fa fa-question-circle settingsquestionmark"></i></a></div>
<br/>
<div class="radio"><label><input type="radio" name="s_recaptcha_use" value="1"
onclick="javascript:hesk_toggleLayer('recaptcha','block')" <?php echo $on; ?> /> <?php echo $hesklang['sir']; ?>
onclick="javascript:hesk_toggleLayer('recaptcha','block')" <?php echo $on; ?> /> <?php echo $hesklang['sir3']; ?>
</label> <a href="Javascript:void(0)"
onclick="Javascript:hesk_window('<?php echo $help_folder; ?>helpdesk.html#64','400','500')"><i
class="fa fa-question-circle settingsquestionmark"></i></a></div>
@ -2862,10 +2858,17 @@ $modsForHesk_settings = mfh_getSettings();
$onload_status = ' disabled ';
}
echo '
// Is IMAP extension loaded?
if ( ! function_exists('imap_open')) {
echo '<i>'. $hesklang['disabled'] . '</i> - ' . $hesklang['imap_not'];
$onload_div = 'none';
} else {
echo '
<div class="radio"><label><input type="radio" name="s_imap" value="0" onclick="hesk_attach_disable(new Array(\'i0\',\'i1\',\'i2\',\'i3\',\'i4\',\'i5\',\'i6\',\'i7\',\'i8\',\'i9\'))" onchange="hesk_toggleLayerDisplay(\'imap_settings\');" ' . $off . '> ' . $hesklang['off'] . '</label></div>&nbsp;&nbsp;&nbsp;
<div class="radio"><label><input type="radio" name="s_imap" value="1" onclick="hesk_attach_enable(new Array(\'i0\',\'i1\',\'i2\',\'i3\',\'i4\',\'i5\',\'i6\',\'i7\',\'i8\',\'i9\'))" onchange="hesk_toggleLayerDisplay(\'imap_settings\');" ' . $on . '> ' . $hesklang['on'] . '</label></div>';
}
?>
<input type="hidden" name="tmp_imap_job_wait" value="<?php echo $hesk_settings['imap_job_wait']; ?>" />
<input type="hidden" name="tmp_imap_host_name" value="<?php echo $hesk_settings['imap_host_name']; ?>">
<input type="hidden" name="tmp_imap_host_port" value="<?php echo $hesk_settings['imap_host_port']; ?>">
<input type="hidden" name="tmp_imap_user" value="<?php echo $hesk_settings['imap_user']; ?>">
@ -3446,53 +3449,28 @@ $modsForHesk_settings = mfh_getSettings();
<div class="box-body">
<h4 class="bold"><?php echo $hesklang['dat']; ?></h4>
<div class="form-group">
<label for="servertime" class="col-sm-4 control-label"><?php echo $hesklang['server_time']; ?>
<a href="Javascript:void(0)"
onclick="Javascript:hesk_window('<?php echo $help_folder; ?>misc.html#18','400','500')"><i
class="fa fa-question-circle settingsquestionmark"></i></a></label>
<label for="s_timezone" class="col-sm-4 control-label"><?php echo $hesklang['TZ']; ?> <a
href="Javascript:void(0)"
onclick="Javascript:hesk_window('<?php echo $help_folder; ?>misc.html#63','400','500')"><i
class="fa fa-question-circle settingsquestionmark"></i></a></label>
<div class="col-sm-8">
<p class="form-control-static"><?php echo $hesklang['csrt'] . ' <span id="servertime">' . $server_time . '</span>'; ?></p>
<script language="javascript" type="text/javascript"><!--
startTime();
//-->
</script>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-sm-2 col-sm-offset-4">
<input type="text" class="form-control" name="s_diff_hours" size="5" maxlength="3"
value="<?php echo $hesk_settings['diff_hours']; ?>"/>
</div>
<div class="col-sm-6 pad-right-0">
<p class="form-control-static"><?php echo $hesklang['t_h']; ?></p>
</div>
</div>
<div class="row pad-right-0">
<div class="col-sm-2 col-sm-offset-4">
<input type="text" class="form-control" name="s_diff_minutes" size="5" maxlength="3"
value="<?php echo $hesk_settings['diff_minutes']; ?>"/>
</div>
<div class="col-sm-6 pad-right-0">
<p class="form-control-static"><?php echo $hesklang['t_m']; ?></p>
</div>
</div>
</div>
<div class="form-group">
<label for="s_daylight" class="col-sm-4 control-label"><?php echo $hesklang['day']; ?> <a
href="Javascript:void(0)"
onclick="Javascript:hesk_window('<?php echo $help_folder; ?>misc.html#19','400','500')"><i
class="fa fa-question-circle settingsquestionmark"></i></a></label>
<div class="col-sm-8 form-inline">
<?php
$on = $hesk_settings['daylight'] ? 'checked="checked"' : '';
$off = $hesk_settings['daylight'] ? '' : 'checked="checked"';
echo '
<div class="radio"><label><input type="radio" name="s_daylight" value="0" ' . $off . ' /> ' . $hesklang['off'] . '</label></div>&nbsp;&nbsp;&nbsp;
<div class="radio"><label><input type="radio" name="s_daylight" value="1" ' . $on . ' /> ' . $hesklang['on'] . '</label></div>';
// Get list of supported timezones
$timezone_list = hesk_generate_timezone_list();
// Do we need to localize month names?
if ($hesk_settings['language'] != 'English') {
$timezone_list = hesk_translate_timezone_list($timezone_list);
}
?>
<select class="form-control" name="s_timezone">
<?php foreach ($timezone_list as $timezone => $description): ?>
<option value="<?php echo $timezone; ?>" <?php if ($hesk_settings['timezone'] == $timezone) {echo 'selected';} ?>>
<?php echo $description; ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="form-group">

@ -419,9 +419,10 @@ $set['updatedformat'] = hesk_checkMinMax(intval(hesk_POST('s_updatedformat')), 0
/*** MISC ***/
/* --> Date & Time */
$set['diff_hours'] = floatval(hesk_POST('s_diff_hours', 0));
$set['diff_minutes'] = floatval(hesk_POST('s_diff_minutes', 0));
$set['daylight'] = empty($_POST['s_daylight']) ? 0 : 1;
$set['timezone'] = hesk_input(hesk_POST('s_timezone'));
if (!in_array($set['timezone'], timezone_identifiers_list())) {
$set['timezone'] = 'UTC';
}
$set['timeformat'] = hesk_input(hesk_POST('s_timeformat')) or $set['timeformat'] = 'Y-m-d H:i:s';
/* --> Other */
@ -881,9 +882,7 @@ $hesk_settings[\'updatedformat\']=' . $set['updatedformat'] . ';
// ==> MISC
// --> Date & Time
$hesk_settings[\'diff_hours\']=' . $set['diff_hours'] . ';
$hesk_settings[\'diff_minutes\']=' . $set['diff_minutes'] . ';
$hesk_settings[\'daylight\']=' . $set['daylight'] . ';
$hesk_settings[\'timezone\']=\'' . $set['timezone'] . '\';
$hesk_settings[\'timeformat\']=\'' . $set['timeformat'] . '\';
// --> Other

@ -300,6 +300,11 @@ if (!$modsForHesk_settings['rich_text_for_tickets']) {
$tmpvar['message'] = nl2br($tmpvar['message']);
}
// Track who assigned the ticket
if ($tmpvar['owner'] > 0) {
$tmpvar['assignedby'] = !empty($autoassign_owner) ? -1 : $_SESSION['id'];
}
$tmpvar['latitude'] = hesk_POST('latitude', 'E-4');
$tmpvar['longitude'] = hesk_POST('longitude', 'E-4');

@ -50,6 +50,9 @@ $can_unban_emails = hesk_checkPermission('can_unban_emails', 0);
$can_ban_ips = hesk_checkPermission('can_ban_ips', 0);
$can_unban_ips = hesk_checkPermission('can_unban_ips', 0);
$can_resolve = hesk_checkPermission('can_resolve', 0);
$can_view_ass_by = hesk_checkPermission('can_view_ass_by', 0);
$can_privacy = hesk_checkPermission('can_privacy',0);
$can_export = hesk_checkPermission('can_export',0);
// Get ticket ID
$trackingID = hesk_cleanID() or print_form();
@ -90,7 +93,10 @@ if (hesk_dbNumRows($res) != 1) {
/* Permission to view this ticket? */
if ($ticket['owner'] && $ticket['owner'] != $_SESSION['id'] && !hesk_checkPermission('can_view_ass_others', 0)) {
hesk_error($hesklang['ycvtao']);
// Maybe this user is allowed to view tickets he/she assigned?
if (!$can_view_ass_by || $ticket['assignedby'] != $_SESSION['id']) {
hesk_error($hesklang['ycvtao']);
}
}
if (!$ticket['owner'] && !$can_view_unassigned) {
@ -163,7 +169,10 @@ if ($isManager) {
$can_unban_emails =
$can_ban_ips =
$can_unban_ips =
$can_resolve = true;
$can_resolve =
$can_view_ass_by =
$can_privacy =
$can_export = true;
}
/* Is this user allowed to view tickets inside this category? */
@ -748,9 +757,11 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
?>
</span>
</b><br>
<?php if ($can_edit): ?>
<button class="btn btn-default btn-sm" id="change-button">
<?php echo $hesklang['chg']; ?>
</button>
<?php endif; ?>
</div>
<div id="editable-due-date" style="display: none">
<span class="form-group">
@ -1321,7 +1332,7 @@ require_once(HESK_PATH . 'inc/footer.inc.php');
function hesk_getAdminButtons($category_id)
{
global $hesk_settings, $hesklang, $modsForHesk_settings, $ticket, $reply, $trackingID, $can_edit, $can_archive, $can_delete, $can_resolve, $isManager;
global $hesk_settings, $hesklang, $modsForHesk_settings, $ticket, $reply, $trackingID, $can_edit, $can_archive, $can_delete, $can_resolve, $can_privacy, $can_export, $isManager;
$options = '';
@ -1329,12 +1340,12 @@ function hesk_getAdminButtons($category_id)
if ($can_edit) {
$tmp = $reply ? '&amp;reply=' . $reply['id'] : '';
$mgr = $isManager ? '&amp;isManager=true' : '';
$options .= '<a class="btn btn-default" href="edit_post.php?track=' . $trackingID . $tmp . $mgr . '"><i class="fa fa-pencil orange"></i> ' . $hesklang['edit'] . '</a> ';
$options .= '<a id="editticket" title="'.$hesklang['edtt'].'" class="btn btn-default" href="edit_post.php?track=' . $trackingID . $tmp . $mgr . '"><i class="fa fa-pencil orange"></i> ' . $hesklang['btn_edit'] . '</a> ';
}
/* Print ticket button */
$options .= '<a class="btn btn-default" href="../print.php?track=' . $trackingID . '"><i class="fa fa-print"></i> ' . $hesklang['printer_friendly'] . '</a> ';
$options .= '<a class="btn btn-default" title="'.$hesklang['printer_friendly'].'" href="../print.php?track=' . $trackingID . '"><i class="fa fa-print"></i> ' . $hesklang['btn_print'] . '</a> ';
/* Copy ticket button */
$strippedName = strip_tags($ticket['name']);
@ -1489,7 +1500,7 @@ function hesk_getAdminButtons($category_id)
/* Lock ticket button */
if ($can_resolve) {
$template =
'<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) . '">
'<div class="col-md-6 col-sm-12"><a id="%s" title="%s" class="button-link" href="lock.php?track=' . $trackingID . '&amp;locked=%s&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '">
<div class="panel panel-default">
<div class="panel-body">
<h4>
@ -1499,14 +1510,14 @@ function hesk_getAdminButtons($category_id)
</div>
</a></div>';
$dropdown .= $ticket['locked']
? sprintf($template, 0, 'unlock', $hesklang['tul'])
: sprintf($template, 1, 'lock', $hesklang['tlo']);
? sprintf($template, 'unlock', $hesklang['tul'] . ' - ' . $hesklang['isloc'], 0, 'unlock', $hesklang['btn_unlock'])
: sprintf($template, 'lock', $hesklang['tlo'] . ' - ' . $hesklang['isloc'], 1, 'lock', $hesklang['btn_lock']);
}
/* Tag ticket button */
if ($can_archive) {
$template =
'<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) . '">
'<div class="col-md-6 col-sm-12"><a id="%s" title="%s" class="button-link" href="archive.php?track=' . $trackingID . '&amp;archived=%s&amp;Refresh=' . mt_rand(10000, 99999) . '&amp;token=' . hesk_token_echo(0) . '">
<div class="panel panel-default">
<div class="panel-body">
<h4>
@ -1517,18 +1528,51 @@ function hesk_getAdminButtons($category_id)
</a></div>';
$dropdown .= $ticket['archive']
? sprintf($template, 0, $hesklang['remove_archive'])
: sprintf($template, 1, $hesklang['add_archive']);
? sprintf($template, 'untag', $hesklang['remove_archive'], 0, $hesklang['btn_untag'])
: sprintf($template, 'tag', $hesklang['add_archive'], 1, $hesklang['btn_tag']);
}
/* Import to knowledgebase button */
if ($hesk_settings['kb_enable'] && hesk_checkPermission('can_man_kb', 0)) {
$dropdown .=
'<div class="col-md-6 col-sm-12"><a href="manage_knowledgebase.php?a=import_article&amp;track=' . $trackingID . '" class="button-link">
'<div class="col-md-6 col-sm-12"><a id="addtoknow" title="'.$hesklang['import_kb'].'" href="manage_knowledgebase.php?a=import_article&amp;track=' . $trackingID . '" class="button-link">
<div class="panel panel-default">
<div class="panel-body">
<h4>
<i class="fa fa-lightbulb-o fa-fw"></i> ' . $hesklang['btn_import_kb'] . '
</h4>
</div>
</div>
</a></div>';
}
// Export ticket
if ($can_export) {
$dropdown .=
'<div class="col-md-6 col-sm-12">
<a id="exportticket" href="export_ticket.php?track='.$trackingID.'&amp;Refresh='.mt_rand(10000,99999).'&amp;token='.hesk_token_echo(0).'"
title="'.$hesklang['btn_export'].'" class="button-link">
<div class="panel panel-default">
<div class="panel-body">
<h4>
<i class="fa fa-lightbulb-o fa-fw"></i> ' . $hesklang['import_kb'] . '
<i class="fa fa-download fa-fw"></i> '.$hesklang['btn_export'].'
</h4>
</div>
</div>
</a></div>';
}
// Anonymize ticket
if ($can_privacy) {
$dropdown .=
'<div class="col-md-6 col-sm-12">
<a id="exportticket" href="anonymize_ticket.php?track='.$trackingID.'&amp;Refresh='.mt_rand(10000,99999).'&amp;token='.hesk_token_echo(0).'"
onclick="return hesk_confirmExecute(\''.hesk_makeJsString($hesklang['confirm_anony']).'?\\n\\n'.hesk_makeJsString($hesklang['privacy_anon_info']).'\');"
title="'.$hesklang['confirm_anony'].'" class="button-link">
<div class="panel panel-default">
<div class="panel-body warning">
<h4>
<i class="fa fa-shield fa-fw"></i> '.$hesklang['btn_anony'].'
</h4>
</div>
</div>
@ -1540,11 +1584,11 @@ function hesk_getAdminButtons($category_id)
if ($reply) {
$url = 'admin_ticket.php';
$tmp = 'delete_post=' . $reply['id'];
$txt = $hesklang['delt'];
$txt = $hesklang['btn_delr'];
} else {
$url = 'delete_tickets.php';
$tmp = 'delete_ticket=1';
$txt = $hesklang['dele'];
$txt = $hesklang['btn_delt'];
}
$dropdown .=
'<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) . '?\');">
@ -1591,7 +1635,7 @@ function hesk_getAdminButtonsInTicket($reply = 0, $white = 1)
if ($can_edit) {
$tmp = $reply ? '&amp;reply=' . $reply['id'] : '';
$mgr = $isManager ? '&amp;isManager=true' : '';
$options .= '<a class="btn btn-default" href="edit_post.php?track=' . $trackingID . $tmp . $mgr . '"><i class="fa fa-pencil orange"></i> ' . $hesklang['edtt'] . '</a> ';
$options .= '<a class="btn btn-default" href="edit_post.php?track=' . $trackingID . $tmp . $mgr . '"><i class="fa fa-pencil orange"></i> ' . $hesklang['btn_edit'] . '</a> ';
}
@ -1600,13 +1644,13 @@ function hesk_getAdminButtonsInTicket($reply = 0, $white = 1)
if ($reply) {
$url = 'admin_ticket.php';
$tmp = 'delete_post=' . $reply['id'];
$txt = $hesklang['delt'];
$txt = $hesklang['btn_delr'];
} else {
$url = 'delete_tickets.php';
$tmp = 'delete_ticket=1';
$txt = $hesklang['dele'];
$txt = $hesklang['btn_delt'];
}
$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> ';
$options .= '<a id="deleteticket" 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> ';
}
/* Return generated HTML */
@ -2009,6 +2053,7 @@ function mfh_print_audit_record($record) {
break;
case 'audit_submitted_via_piping':
case 'audit_submitted_via_pop':
case 'audit_submitted_via_imap':
$font_icon = 'fa-envelope-o';
break;
case 'audit_attachment_deleted':
@ -2035,6 +2080,9 @@ function mfh_print_audit_record($record) {
case 'audit_unlinked_ticket':
$font_icon = 'fa fa-chain-broken';
break;
case 'audit_anonymized':
$font_icon = 'fa fa-shield';
break;
default:
$font_icon = 'fa-question-circle';
break;
@ -2347,6 +2395,7 @@ function hesk_printCanned()
myMsg = myMsg.replace(/%%HESK_TRACKID%%/g, '<?php echo hesk_jsString($ticket['trackid']); ?>');
myMsg = myMsg.replace(/%%HESK_TRACK_ID%%/g, '<?php echo hesk_jsString($ticket['trackid']); ?>');
myMsg = myMsg.replace(/%%HESK_NAME%%/g, '<?php echo hesk_jsString($ticket['name']); ?>');
myMsg = myMsg.replace(/%%HESK_FIRST_NAME%%/g, '<?php echo hesk_jsString(hesk_full_name_to_first_name($ticket['name'])); ?>');
myMsg = myMsg.replace(/%%HESK_EMAIL%%/g, '<?php echo hesk_jsString($ticket['email']); ?>');
myMsg = myMsg.replace(/%%HESK_OWNER%%/g, '<?php echo hesk_jsString( isset($admins[$ticket['owner']]) ? $admins[$ticket['owner']] : ''); ?>');

@ -0,0 +1,43 @@
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH','../');
/* Get all the required files and functions */
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
require(HESK_PATH . 'inc/admin_functions.inc.php');
require(HESK_PATH . 'inc/privacy_functions.inc.php');
hesk_load_database_functions();
hesk_session_start();
hesk_dbConnect();
hesk_isLoggedIn();
// Check permissions for this feature
hesk_checkPermission('can_privacy');
// A security check
hesk_token_check();
// Tracking ID
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
// Anonymize the ticket and redirect back
if (hesk_anonymizeTicket(0, $trackingID))
{
hesk_process_messages($hesklang['success_anon'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
}
hesk_error($hesklang['no_permission']);

@ -52,7 +52,7 @@ $owner = intval(hesk_REQUEST('owner'));
/* If ID is -1 the ticket will be unassigned */
if ($owner == -1) {
$res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0 WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
$res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0, `assignedby`=NULL WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unassigned', hesk_date(),
array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'));
@ -97,7 +97,15 @@ if ($ticket['owner'] && $ticket['owner'] != $owner && hesk_REQUEST('unassigned')
/* Assigning to self? */
if ($can_assign_others || ($owner == $_SESSION['id'] && $can_assign_self)) {
$res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`={$owner} WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
$assignedby = intval(hesk_SESSION('id'));
if ($assignedby > 0) {
$assignedby = ',`assignedby`=' . $assignedby;
} else {
$assignedby = '';
}
$res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`={$owner} {$assignedby} WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
if ($owner == $_SESSION['id'] && $can_assign_self) {
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_assigned_self', hesk_date(),

@ -200,7 +200,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
if ($can_unban) {
echo '
<td class="' . $color . ' text-left">
<a href="banned_emails.php?a=unban&amp;id=' . $ban['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();">
<a name="Unban '.$ban['email'].'" href="banned_emails.php?a=unban&amp;id=' . $ban['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();">
<i class="fa fa-times red font-size-16p" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['delban'] . '"></i>
</a>
</td>

@ -263,7 +263,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
if ($can_unban) {
echo '
<td class="' . $color . ' text-left">
<a href="banned_ips.php?a=unban&amp;id=' . $ban['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();">
<a name="Unban '.$ban['ip_display'].'" href="banned_ips.php?a=unban&amp;id=' . $ban['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();">
<i class="fa fa-times red font-size-16p" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['delban'] . '"></i></a>
</td>
';

@ -849,10 +849,10 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
}
}
?>
<a href="custom_fields.php?a=edit_cf&amp;id=<?php echo $tmp_id; ?>">
<a name="Edit <?php echo $cf['name']; ?>" href="custom_fields.php?a=edit_cf&amp;id=<?php echo $tmp_id; ?>">
<i class="fa fa-pencil fa-fw icon-link orange" data-toggle="tooltip" title="<?php echo $hesklang['edit']; ?>"></i>
</a>
<a href="custom_fields.php?a=remove_cf&amp;id=<?php echo $tmp_id; ?>&amp;token=<?php hesk_token_echo(); ?>"
<a name="Delete <?php echo $cf['name']; ?>" href="custom_fields.php?a=remove_cf&amp;id=<?php echo $tmp_id; ?>&amp;token=<?php hesk_token_echo(); ?>"
onclick="return hesk_confirmExecute('<?php echo hesk_makeJsString($hesklang['del_cf']); ?>');">
<i class="fa fa-times fa-fw icon-link red" data-toggle="tooltip" title="<?php echo $hesklang['delete']; ?>"></i>
</a>

@ -87,6 +87,124 @@ $priorities = array(
'low' => array('value' => 3, 'lang' => 'low', 'text' => $hesklang['low'], 'formatted' => $hesklang['low']),
);
// Assign tickets to
if ( isset($_POST['assign']) && $_POST['assign'] == $hesklang['assi']) {
if ( ! isset($_POST['owner']) || $_POST['owner'] == '') {
hesk_process_messages($hesklang['assign_no'], $referer, 'NOTICE');
}
$end_message = array();
$num_assigned = 0;
// Permissions
$can_assign_others = hesk_checkPermission('can_assign_others',0);
if ($can_assign_others) {
$can_assign_self = true;
} else {
$can_assign_self = hesk_checkPermission('can_assign_self',0);
}
$owner = intval( hesk_POST('owner') );
if ($owner == -1) {
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
}
$this_id = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$res = hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `owner`=0, `assignedby`=NULL WHERE `id`={$this_id} LIMIT 1");
mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_unassigned', hesk_date(), array(0 => $_SESSION['name'].' ('.$_SESSION['user'].')'));
$end_message[] = sprintf($hesklang['assign_2'], $this_id);
$i++;
}
hesk_process_messages($hesklang['assign_1'],$referer,'SUCCESS');
}
$res = hesk_dbQuery("SELECT `id`,`user`,`name`,`email`,`isadmin`,`categories`,`notify_assigned` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `id`='{$owner}' LIMIT 1");
$owner_data = hesk_dbFetchAssoc($res);
if (!$owner_data['isadmin']) {
$owner_data['categories']=explode(',',$owner_data['categories']);
}
require(HESK_PATH . 'inc/email_functions.inc.php');
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
}
$this_id = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$result = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `id`={$this_id} LIMIT 1");
if (hesk_dbNumRows($result) != 1) {
continue;
}
$ticket = hesk_dbFetchAssoc($result);
if ($ticket['owner'] == $owner) {
$end_message[] = sprintf($hesklang['assign_3'], $ticket['trackid'], $owner_data['name']);
$i++;
continue;
}
if ($owner_data['isadmin'] || in_array($ticket['category'],$owner_data['categories'])) {
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `owner`={$owner}, `assignedby`=".intval($_SESSION['id'])." WHERE `id`={$this_id} LIMIT 1");
mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_assigned', hesk_date(), array(0 => $_SESSION['name'].' ('.$_SESSION['user'].')',
1 => $owner_data['name'].' ('.$owner_data['user'].')'));
$end_message[] = sprintf($hesklang['assign_4'], $ticket['trackid'], $owner_data['name']);
$num_assigned++;
$ticket['owner'] = $owner;
/* --> Prepare message */
// 1. Generate the array with ticket info that can be used in emails
$info = array(
'email' => $ticket['email'],
'category' => $ticket['category'],
'priority' => $ticket['priority'],
'owner' => $ticket['owner'],
'trackid' => $ticket['trackid'],
'status' => $ticket['status'],
'name' => $ticket['name'],
'subject' => $ticket['subject'],
'message' => $ticket['message'],
'attachments' => $ticket['attachments'],
'dt' => hesk_date($ticket['dt'], true),
'lastchange' => hesk_date($ticket['lastchange'], true),
'id' => $ticket['id'],
'time_worked' => $ticket['time_worked'],
'last_reply_by' => hesk_getReplierName($ticket),
);
// 2. Add custom fields to the array
foreach ($hesk_settings['custom_fields'] as $k => $v) {
$info[$k] = $v['use'] ? $ticket[$k] : '';
}
// 3. Make sure all values are properly formatted for email
$ticket = hesk_ticketToPlain($info, 1, 0);
/* Notify the new owner? */
if ($ticket['owner'] != intval($_SESSION['id'])) {
hesk_notifyAssignedStaff(false, 'ticket_assigned_to_you', $modsForHesk_settings);
}
} else {
$end_message[] = sprintf($hesklang['assign_5'], $ticket['trackid'], $owner_data['name']);
}
$i++;
}
hesk_process_messages(sprintf($hesklang['assign_log'], $num_assigned, ($i - $num_assigned), implode("\n", $end_message)),$referer,($num_assigned == 0) ? 'ERROR' : ($num_assigned < $i ? 'NOTICE' : 'SUCCESS'));
}
// Change priority
if (array_key_exists($_POST['a'], $priorities)) {
// A security check
@ -211,7 +329,185 @@ elseif ($_POST['a'] == 'tag' || $_POST['a'] == 'untag') {
}
hesk_process_messages(sprintf($action, $i), $referer, 'SUCCESS');
} /* JUST CLOSE */
}
/* EXPORT */
elseif ($_POST['a']=='export') {
/* Check permissions for this feature */
hesk_checkPermission('can_export');
/* A security check */
hesk_token_check('POST');
$ids_to_export = array();
foreach ($_POST['id'] as $this_id) {
if ( is_array($this_id) ) {
continue;
}
$ids_to_export[] = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$i++;
}
if ($i < 1) {
hesk_process_messages($hesklang['no_selected'], $referer, 'NOTICE');
}
// Start SQL statement for selecting tickets
$sql = "SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `id` IN (".implode(',', $ids_to_export).") ";
$sql .= " AND " . hesk_myCategories();
$sql .= " AND " . hesk_myOwnership();
require_once(HESK_PATH . 'inc/custom_fields.inc.php');
require(HESK_PATH . 'inc/export_functions.inc.php');
list($success_msg, $tickets_exported) = hesk_export_to_XML($sql, true);
if ($tickets_exported > 0) {
hesk_process_messages($success_msg,$referer,'SUCCESS');
} else {
hesk_process_messages($hesklang['n2ex'],$referer,'NOTICE');
}
}
/* ANONYMIZE */
elseif ($_POST['a']=='anonymize') {
/* Check permissions for this feature */
hesk_checkPermission('can_privacy');
/* A security check */
hesk_token_check('POST');
require(HESK_PATH . 'inc/privacy_functions.inc.php');
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
}
$this_id = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$result = hesk_dbQuery("SELECT `id`,`trackid`,`name`,`category` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `id`='".intval($this_id)."' AND ".hesk_myOwnership()." LIMIT 1");
if (hesk_dbNumRows($result) != 1) {
continue;
}
$ticket = hesk_dbFetchAssoc($result);
hesk_okCategory($ticket['category']);
hesk_anonymizeTicket(null, null, true);
$i++;
}
hesk_process_messages(sprintf($hesklang['num_tickets_anon'],$i),$referer,'SUCCESS');
}
/* PRINT */
elseif ($_POST['a']=='print') {
/* Check permissions for this feature */
hesk_checkPermission('can_view_tickets');
/* A security check */
hesk_token_check('POST');
// Load custom fields
require_once(HESK_PATH . 'inc/custom_fields.inc.php');
// List of staff
if (!isset($admins)) {
$admins = array();
$res2 = hesk_dbQuery("SELECT `id`,`name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` ORDER BY `id` ASC");
while ($row=hesk_dbFetchAssoc($res2)) {
$admins[$row['id']]=$row['name'];
}
}
// List of categories
$hesk_settings['categories'] = array();
$res2 = hesk_dbQuery('SELECT `id`, `name` FROM `'.hesk_dbEscape($hesk_settings['db_pfix']).'categories` WHERE ' . hesk_myCategories('id') . ' ORDER BY `cat_order` ASC');
while ($row=hesk_dbFetchAssoc($res2)) {
$hesk_settings['categories'][$row['id']] = $row['name'];
}
// Print page head
header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title><?php echo $hesk_settings['hesk_title']; ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $hesklang['ENCODING']; ?>">
<style type="text/css">
body, table, td, p {
color : black;
font-family : Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size : <?php echo $hesk_settings['print_font_size']; ?>px;
}
table {
border-collapse:collapse;
}
hr {
border: 0;
color: #9e9e9e;
background-color: #9e9e9e;
height: 1px;
width: 100%;
text-align: left;
}
</style>
</head>
<body onload="window.print()">
<?php
// Loop through ticket IDs and print them
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
}
$this_id = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$result = hesk_dbQuery("SELECT `t1`.* , `ticketStatus`.`IsClosed` AS `isClosed`, `ticketStatus`.`Key` AS `statusKey`, `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`
INNER JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` AS `ticketStatus` ON `t1`.`status` = `ticketStatus`.`ID`
WHERE `t1`.`id`='{$this_id}' LIMIT 1");
if (hesk_dbNumRows($result) != 1) {
continue;
}
$ticket = hesk_dbFetchAssoc($result);
// Check that we have proper permissions to view this ticket
hesk_okCategory($ticket['category']);
$can_view_ass_by = hesk_checkPermission('can_view_ass_by', 0);
$can_view_unassigned = hesk_checkPermission('can_view_unassigned',0);
if ($ticket['owner'] && $ticket['owner'] != $_SESSION['id'] && ! hesk_checkPermission('can_view_ass_others',0)) {
// Maybe this user is allowed to view tickets he/she assigned?
if ( ! $can_view_ass_by || $ticket['assignedby'] != $_SESSION['id']) {
hesk_error($hesklang['ycvtao']);
}
}
if (!$ticket['owner'] && ! $can_view_unassigned) {
hesk_error($hesklang['ycovtay']);
}
// All good, continue...
$category['name'] = isset($hesk_settings['categories'][$ticket['category']]) ? $hesk_settings['categories'][$ticket['category']] : $hesklang['catd'];
// Get replies
$res = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."replies` WHERE `replyto`='{$ticket['id']}' ORDER BY `id` ASC");
$replies = hesk_dbNumRows($res);
// Print ticket
require(HESK_PATH . 'inc/print_template.inc.php');
flush();
}
?>
</body>
</html>
<?php
exit();
}
/* JUST CLOSE */
else {
/* Check permissions for this feature */
hesk_checkPermission('can_view_tickets');

@ -37,7 +37,7 @@ $modsForHesk_settings = mfh_getSettings();
$delete = hesk_GET('delete');
if (strlen($delete) && preg_match('/^hesk_export_[0-9_\-]+$/', $delete)) {
hesk_unlink(HESK_PATH.$hesk_settings['cache_dir'].'/'.$delete.'.zip');
hesk_process_messages($hesklang['fd'], 'export.php','SUCCESS');
hesk_process_messages($hesklang['fd'], hesk_verifyGoto(),'SUCCESS');
}
// Set default values
@ -298,343 +298,8 @@ while ($row = hesk_dbFetchAssoc($res2)) {
// Generate export file
if (isset($_GET['w'])) {
// We'll need HH:MM:SS format for hesk_date() here
$hesk_settings['timeformat'] = 'H:i:s';
// Get staff names
$admins = array();
$result = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` ORDER BY `name` ASC");
while ($row = hesk_dbFetchAssoc($result)) {
$admins[$row['id']] = $row['name'];
}
// This will be the export directory
$export_dir = HESK_PATH.$hesk_settings['cache_dir'].'/';
// This will be the name of the export and the XML file
$export_name = 'hesk_export_' . date('Y-m-d_H-i-s') . '_' . mt_rand(10000, 99999);
$save_to = $export_dir . $export_name . '.xml';
// Do we have the export directory?
if (is_dir($export_dir) || (@mkdir($export_dir, 0777) && is_writable($export_dir))) {
// Is there an index.htm file?
if (!file_exists($export_dir.'index.htm')) {
@file_put_contents($export_dir.'index.htm', '');
}
// Cleanup old files
hesk_purge_cache('export', 86400);
} else {
hesk_error($hesklang['ede']);
}
// Make sure the file can be saved and written to
@file_put_contents($save_to, '');
if (!file_exists($save_to)) {
hesk_error($hesklang['eef']);
}
// Start generating the report message and generating the export
$success_msg = '';
$flush_me = '<br /><br />';
$flush_me .= hesk_date() . " | {$hesklang['inite']} ";
if ($date_from == $date_to) {
$flush_me .= "(" . hesk_dateToString($date_from, 0) . ")<br />\n";
} else {
$flush_me .= "(" . hesk_dateToString($date_from, 0) . " - " . hesk_dateToString($date_to, 0) . ")<br />\n";
}
// Start generating file contents
$tmp = '<?xml version="1.0" encoding="UTF-8"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
<AllowPNG/>
</OfficeDocumentSettings>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>8250</WindowHeight>
<WindowWidth>16275</WindowWidth>
<WindowTopX>360</WindowTopX>
<WindowTopY>90</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font ss:FontName="Calibri" x:CharSet="238" x:Family="Swiss" ss:Size="11"
ss:Color="#000000"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="s62">
<NumberFormat ss:Format="General Date"/>
</Style>
<Style ss:ID="s63">
<NumberFormat ss:Format="Short Date"/>
</Style>
<Style ss:ID="s65">
<NumberFormat ss:Format="[h]:mm:ss"/>
</Style>
</Styles>
<Worksheet ss:Name="Sheet1">
<Table>
';
// Define column width
$tmp .= '
<Column ss:AutoFitWidth="0" ss:Width="50"/>
<Column ss:AutoFitWidth="0" ss:Width="84" ss:Span="1"/>
<Column ss:AutoFitWidth="0" ss:Width="110"/>
<Column ss:AutoFitWidth="0" ss:Width="110"/>
<Column ss:AutoFitWidth="0" ss:Width="90"/>
<Column ss:AutoFitWidth="0" ss:Width="90"/>
<Column ss:AutoFitWidth="0" ss:Width="87"/>
<Column ss:AutoFitWidth="0" ss:Width="57.75"/>
<Column ss:AutoFitWidth="0" ss:Width="57.75"/>
<Column ss:AutoFitWidth="0" ss:Width="100"/>
<Column ss:AutoFitWidth="0" ss:Width="100"/>
<Column ss:AutoFitWidth="0" ss:Width="80"/>
<Column ss:AutoFitWidth="0" ss:Width="80"/>
';
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if ($v['use']) {
$tmp .= '<Column ss:AutoFitWidth="0" ss:Width="80"/>' . "\n";
}
}
// Define first row (header)
$tmp .= '
<Row>
<Cell><Data ss:Type="String">#</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['trackID'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['date'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['last_update'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['name'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['email'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['category'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['priority'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['status'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['subject'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['message'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['owner'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['ts'] . '</Data></Cell>
';
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if ($v['use']) {
$tmp .= '<Cell><Data ss:Type="String">' . $v['name'] . '</Data></Cell>' . "\n";
}
}
$tmp .= "</Row>\n";
// Write what we have by now into the XML file
file_put_contents($save_to, $tmp, FILE_APPEND);
$flush_me .= hesk_date() . " | {$hesklang['gXML']}<br />\n";
// OK, now start dumping data and writing it into the file
$tickets_exported = 0;
$save_after = 100;
$this_round = 0;
$tmp = '';
$result = hesk_dbQuery($sql);
while ($ticket = hesk_dbFetchAssoc($result)) {
$ticket['status'] = mfh_getDisplayTextForStatusId($ticket['status']);
switch ($ticket['priority']) {
case 0:
$ticket['priority'] = $hesklang['critical'];
break;
case 1:
$ticket['priority'] = $hesklang['high'];
break;
case 2:
$ticket['priority'] = $hesklang['medium'];
break;
default:
$ticket['priority'] = $hesklang['low'];
}
$ticket['archive'] = !($ticket['archive']) ? $hesklang['no'] : $hesklang['yes'];
$ticket['message'] = hesk_msgToPlain($ticket['message'], 1, 0);
$ticket['subject'] = hesk_msgToPlain($ticket['subject'], 1, 0);
$ticket['owner'] = isset($admins[$ticket['owner']]) ? $admins[$ticket['owner']] : '';
$ticket['category'] = isset($my_cat[$ticket['category']]) ? $my_cat[$ticket['category']] : '';
// Format for export dates
$hesk_settings['timeformat'] = "Y-m-d\TH:i:s\.000";
// Create row for the XML file
$tmp .= '
<Row>
<Cell><Data ss:Type="Number">' . $ticket['id'] . '</Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['trackid'] . ']]></Data></Cell>
<Cell ss:StyleID="s62"><Data ss:Type="DateTime">' . hesk_date($ticket['dt'], true) . '</Data></Cell>
<Cell ss:StyleID="s62"><Data ss:Type="DateTime">' . hesk_date($ticket['lastchange'], true) . '</Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . hesk_msgToPlain($ticket['name'], 1) . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['email'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['category'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['priority'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['status'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['subject'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['message'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['owner'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['time_worked'] . ']]></Data></Cell>
';
// Add custom fields
foreach ($hesk_settings['custom_fields'] as $k=>$v) {
if ($v['use']) {
switch ($v['type']) {
case 'date':
$tmp_dt = hesk_custom_date_display_format($ticket[$k], 'Y-m-d\T00:00:00.000');
$tmp .= strlen($tmp_dt) ? '<Cell ss:StyleID="s63"><Data ss:Type="DateTime">'.$tmp_dt : '<Cell><Data ss:Type="String">';
$tmp .= "</Data></Cell> \n";
break;
default:
$tmp .= '<Cell><Data ss:Type="String"><![CDATA['.hesk_msgToPlain($ticket[$k], 1, 0).']]></Data></Cell> ' . "\n";
}
}
}
$tmp .= "</Row>\n";
// Write every 100 rows into the file
if ($this_round >= $save_after) {
file_put_contents($save_to, $tmp, FILE_APPEND);
$this_round = 0;
$tmp = '';
usleep(1);
}
$tickets_exported++;
$this_round++;
} // End of while loop
// Go back to the HH:MM:SS format for hesk_date()
$hesk_settings['timeformat'] = 'H:i:s';
// Append any remaining rows into the file
if ($this_round > 0) {
file_put_contents($save_to, $tmp, FILE_APPEND);
}
// If any tickets were exported, continue, otherwise cleanup
if ($tickets_exported > 0) {
// Finish the XML file
$tmp = '
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<Selected/>
<Panes>
<Pane>
<Number>3</Number>
<ActiveRow>4</ActiveRow>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet2">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1"
x:FullRows="1" ss:DefaultRowHeight="15">
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet3">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1"
x:FullRows="1" ss:DefaultRowHeight="15">
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
</Workbook>
';
file_put_contents($save_to, $tmp, FILE_APPEND);
// Log how many rows we exported
$flush_me .= hesk_date() . " | " . sprintf($hesklang['nrow'], $tickets_exported) . "<br />\n";
// We will convert XML to Zip to save a lot of space
$save_to_zip = $export_dir . $export_name . '.zip';
// Log start of Zip creation
$flush_me .= hesk_date() . " | {$hesklang['cZIP']}<br />\n";
// Preferrably use the zip extension
if (extension_loaded('zip')) {
$save_to_zip = $export_dir . $export_name . '.zip';
$zip = new ZipArchive;
$res = $zip->open($save_to_zip, ZipArchive::CREATE);
if ($res === TRUE) {
$zip->addFile($save_to, "{$export_name}.xml");
$zip->close();
} else {
die("{$hesklang['eZIP']} <$save_to_zip>\n");
}
} // Some servers have ZipArchive class enabled anyway - can we use it?
elseif (class_exists('ZipArchive')) {
require(HESK_PATH . 'inc/zip/Zip.php');
$zip = new Zip();
$zip->addLargeFile($save_to, "{$export_name}.xml");
$zip->finalize();
$zip->setZipFile($save_to_zip);
} // If not available, use a 3rd party Zip class included with HESK
else {
require(HESK_PATH . 'inc/zip/pclzip.lib.php');
$zip = new PclZip($save_to_zip);
$zip->add($save_to, PCLZIP_OPT_REMOVE_ALL_PATH);
}
// Delete XML, just leave the Zip archive
hesk_unlink($save_to);
// Echo memory peak usage
$flush_me .= hesk_date() . " | " . sprintf($hesklang['pmem'], (@memory_get_peak_usage(true) / 1048576)) . "<br />\r\n";
// We're done!
$flush_me .= hesk_date() . " | {$hesklang['fZIP']}<br /><br />";
// Success message
$success_msg .= $hesk_settings['debug_mode'] ? $flush_me : '<br /><br />';
$success_msg .= $hesklang['step1'] . ': <a href="' . $save_to_zip . '">' . $hesklang['ch2d'] . '</a><br /><br />' . $hesklang['step2'] . ': <a href="export.php?delete='.urlencode($export_name).'">' . $hesklang['dffs'] . '</a>';
} // No tickets exported, cleanup
else {
hesk_unlink($save_to);
}
require_once(HESK_PATH . 'inc/export_functions.inc.php');
list($success_msg, $tickets_exported) = hesk_export_to_XML($sql);
}
/* Print header */
@ -894,7 +559,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
</div>
<div class="form-group">
<input type="submit" value="<?php echo $hesklang['export_btn']; ?>" class="btn btn-default"/>
<input type="submit" id="export" value="<?php echo $hesklang['export_btn']; ?>" class="btn btn-default"/>
<input type="hidden" name="cot" value="1"/>
</div>
</form>

@ -0,0 +1,54 @@
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH','../');
/* Get all the required files and functions */
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
require(HESK_PATH . 'inc/admin_functions.inc.php');
require(HESK_PATH . 'inc/privacy_functions.inc.php');
hesk_load_database_functions();
hesk_session_start();
hesk_dbConnect();
hesk_isLoggedIn();
// Check permissions for this feature
hesk_checkPermission('can_export');
// A security check
hesk_token_check();
// Tracking ID
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
// Generate SQL for the ticket, make sure the user has access to it
$sql = "SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `trackid`='".hesk_dbEscape($trackingID)."' AND ";
$sql .= hesk_myCategories();
$sql .= " AND " . hesk_myOwnership();
$sql .= " LIMIT 1";
require_once(HESK_PATH . 'inc/custom_fields.inc.php');
require_once(HESK_PATH . 'inc/statuses.inc.php');
require(HESK_PATH . 'inc/export_functions.inc.php');
list($success_msg, $tickets_exported) = hesk_export_to_XML($sql, true);
if ($tickets_exported == 1)
{
hesk_process_messages($success_msg,'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
}
hesk_error($hesklang['n2ex']);

@ -173,6 +173,9 @@ LEFT(`message`, 400) AS `message`,
WHERE `message` LIKE '%".hesk_dbEscape( hesk_dbLike($q) )."%' COLLATE '" . hesk_dbCollate() . "' )
";
break;
case 'ip':
$sql .= "`ip` LIKE '".preg_replace('/[^0-9\.\%]/', '', $q)."' ";
break;
default:
if (isset($hesk_settings['custom_fields'][$what]) && $hesk_settings['custom_fields'][$what]['use']) {
$sql .= "`" . hesk_dbEscape($what) . "` LIKE '%" . hesk_dbEscape($q) . "%' COLLATE '" . hesk_dbCollate() . "' ";

@ -65,22 +65,7 @@ function do_login()
if ($hesk_settings['secimg_use'] == 2 && !isset($_SESSION['img_a_verified'])) {
// Using ReCaptcha?
if ($hesk_settings['recaptcha_use'] == 1) {
require_once(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
$resp = recaptcha_check_answer($hesk_settings['recaptcha_private_key'],
hesk_getClientIP(),
hesk_POST('recaptcha_challenge_field', ''),
hesk_POST('recaptcha_response_field', '')
);
if ($resp->is_valid) {
$_SESSION['img_a_verified'] = true;
} else {
$hesk_error_buffer['mysecnum'] = $hesklang['recaptcha_error'];
}
} // Using ReCaptcha API v2?
elseif ($hesk_settings['recaptcha_use'] == 2) {
if ($hesk_settings['recaptcha_use']) {
require(HESK_PATH . 'inc/recaptcha/recaptchalib_v2.php');
$resp = null;
@ -251,7 +236,7 @@ function print_login()
global $hesk_settings, $hesklang, $modsForHesk_settings;
// Tell header to load reCaptcha API if needed
if ($hesk_settings['recaptcha_use'] == 2)
if ($hesk_settings['recaptcha_use'])
{
define('RECAPTCHA',1);
}
@ -297,7 +282,7 @@ function print_login()
<h4 class="login-box-msg">
<?php echo $hesklang['staff_login_title']; ?>
</h4>
<form class="form-horizontal" role="form" action="index.php" method="post" name="form1">
<form class="form-horizontal" role="form" action="index.php" method="post" name="form1" id="form1">
<?php
$has_error = '';
if (in_array('pass',$_SESSION['a_iserror'])) {
@ -365,7 +350,7 @@ function print_login()
</div>
</div>
<?php
if ($hesk_settings['secimg_use'] == 2)
if ($hesk_settings['secimg_use'] == 2 && $hesk_settings['recaptcha_use'] != 1)
{
// SPAM prevention verified for this session
@ -373,34 +358,6 @@ function print_login()
{
echo '<img src="'.HESK_PATH.'img/success.png" width="16" height="16" border="0" alt="" style="vertical-align:text-bottom" /> '.$hesklang['vrfy'];
}
// Not verified yet, should we use Recaptcha?
elseif ($hesk_settings['recaptcha_use'] == 1)
{
?>
<script type="text/javascript">
var RecaptchaOptions = {
theme : '<?php echo ( isset($_SESSION['a_iserror']) && in_array('mysecnum',$_SESSION['a_iserror']) ) ? 'red' : 'white'; ?>',
custom_translations : {
visual_challenge : "<?php echo hesk_slashJS($hesklang['visual_challenge']); ?>",
audio_challenge : "<?php echo hesk_slashJS($hesklang['audio_challenge']); ?>",
refresh_btn : "<?php echo hesk_slashJS($hesklang['refresh_btn']); ?>",
instructions_visual : "<?php echo hesk_slashJS($hesklang['instructions_visual']); ?>",
instructions_context : "<?php echo hesk_slashJS($hesklang['instructions_context']); ?>",
instructions_audio : "<?php echo hesk_slashJS($hesklang['instructions_audio']); ?>",
help_btn : "<?php echo hesk_slashJS($hesklang['help_btn']); ?>",
play_again : "<?php echo hesk_slashJS($hesklang['play_again']); ?>",
cant_hear_this : "<?php echo hesk_slashJS($hesklang['cant_hear_this']); ?>",
incorrect_try_again : "<?php echo hesk_slashJS($hesklang['incorrect_try_again']); ?>",
image_alt_text : "<?php echo hesk_slashJS($hesklang['image_alt_text']); ?>"
}
};
</script>
<?php
require_once(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
echo '<div class="form-group"><div class="col-md-8 col-md-offset-4">';
echo recaptcha_get_html($hesk_settings['recaptcha_public_key'], null, true);
echo '</div></div>';
}
// Use reCaptcha API v2?
elseif ($hesk_settings['recaptcha_use'] == 2)
{
@ -458,7 +415,7 @@ function print_login()
?>
<div class="form-group">
<div class="col-md-offset-4 col-md-8">
<input type="submit" value="<?php echo $hesklang['click_login']; ?>" class="btn btn-default">
<input type="submit" value="<?php echo $hesklang['click_login']; ?>" class="btn btn-default" id="recaptcha-submit">
<input type="hidden" name="a" value="do_login">
<?php
if ( hesk_isREQUEST('goto') && $url=hesk_REQUEST('goto') )
@ -474,6 +431,15 @@ function print_login()
?>
</div>
</div>
<?php
// Use Invisible reCAPTCHA?
if ($hesk_settings['secimg_use'] == 2 && $hesk_settings['recaptcha_use'] == 1 && ! isset($_SESSION['img_a_verified'])) {
?>
<div class="g-recaptcha" data-sitekey="<?php echo $hesk_settings['recaptcha_public_key']; ?>" data-bind="recaptcha-submit" data-callback="recaptcha_submitForm"></div>
<?php
}
?>
</form>
<a class="btn btn-default" href="<?php echo $hesk_settings['hesk_url']; ?>">
<i class="fa fa-chevron-left"></i> <?php echo $hesklang['back']; ?>

@ -450,10 +450,10 @@ function show_message()
$folder = '&amp;folder=outbox';
if ($pm['to'] == $_SESSION['id'])
{
echo '<a class="btn btn-default" href="mail.php?a=mark_unread&amp;id='.$id.'&amp;token='.hesk_token_echo(0).'"><i class="fa fa-envelope-o icon-link"></i> '.$hesklang['mau'].'</a> ';
echo '<a name="MAU '.$pm['subject'].'" class="btn btn-default" href="mail.php?a=mark_unread&amp;id='.$id.'&amp;token='.hesk_token_echo(0).'"><i class="fa fa-envelope-o icon-link"></i> '.$hesklang['mau'].'</a> ';
$folder = '';
}
echo '<a class="btn btn-danger" href="mail.php?a=delete&amp;id='.$id.'&amp;token='.hesk_token_echo(0).$folder.'" onclick="return hesk_confirmExecute(\''.hesk_makeJsString($hesklang['delm']).'?\');"><i class="fa fa-times icon-link"></i> '.$hesklang['delm'].'</a>';
echo '<a name="Delete '.$pm['subject'].'" class="btn btn-danger" href="mail.php?a=delete&amp;id='.$id.'&amp;token='.hesk_token_echo(0).$folder.'" onclick="return hesk_confirmExecute(\''.hesk_makeJsString($hesklang['delm']).'?\');"><i class="fa fa-times icon-link"></i> '.$hesklang['delm'].'</a>';
?>
</div>
</div>
@ -571,7 +571,7 @@ function mail_list_messages()
$pm['dt'] = hesk_dateToString($pm['dt'], 0, 0, 0, true)
?>
<tr>
<td><input type="checkbox" name="id[]" value="<?php echo $pm['id']; ?>" />&nbsp;</td>
<td><input type="checkbox" name="id[]" id="<?php echo $pm['id']; ?>" value="<?php echo $pm['id']; ?>" />&nbsp;</td>
<td><?php echo $pm['subject']; ?></td>
<td><?php echo $pm['name']; ?></td>
<td><?php echo $pm['dt']; ?></td>

@ -190,7 +190,7 @@ $num = hesk_dbNumRows($result);
}
echo '
<a href="manage_canned.php?a=remove&amp;id=' . $mysaved['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete'] . '"></i></a>&nbsp;</td>
<a name="'.$mysaved['title'].'" href="manage_canned.php?a=remove&amp;id=' . $mysaved['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete'] . '"></i></a>&nbsp;</td>
</tr>
';
} // End while
@ -371,6 +371,8 @@ $num = hesk_dbNumRows($result);
onclick="hesk_insertTag('HESK_TRACK_ID')"><?php echo $hesklang['trackID']; ?></a> |
<a href="javascript:void(0)"
onclick="hesk_insertTag('HESK_NAME')"><?php echo $hesklang['name']; ?></a> |
<a href="javascript:void(0)"
onclick="hesk_insertTag('HESK_FIRST_NAME')"><?php echo $hesklang['fname']; ?></a> |
<a href="javascript:void(0)"
onclick="hesk_insertTag('HESK_EMAIL')"><?php echo $hesklang['email']; ?></a> |
<a href="javascript:void(0)"

@ -446,7 +446,7 @@ echo '</script>';
<i class="fa fa-fw fa-pencil icon-link orange"
data-toggle="tooltip" title="<?php echo $hesklang['edit']; ?>"></i>
</a>
<a href="#" data-action="delete">
<a name="Delete Category" href="#" data-action="delete">
<i class="fa fa-fw fa-times icon-link red"
data-toggle="tooltip" title="<?php echo $hesklang['delete']; ?>"></i>
</a>
@ -477,6 +477,7 @@ echo mfh_get_hidden_fields_for_language(array(
'geco',
'cpric',
'no_manager',
'e_udel',
));
require_once(HESK_PATH . 'inc/footer.inc.php');

@ -278,12 +278,12 @@ function getTemplateMarkup($template, $languageCode, $html = false)
$templateUrl = urlencode($template);
$languageCodeUrl = urlencode($languageCode);
if ($html) {
$markup = '<a href="manage_email_templates.php?action=edit&template=' . $templateUrl . '&language=' . $languageCodeUrl . '&html=true">';
$markup = '<a name="Edit '.$templateUrl.'" href="manage_email_templates.php?action=edit&template=' . $templateUrl . '&language=' . $languageCodeUrl . '&html=true">';
$markup .= '<i class="fa fa-html5 font-size-150" data-toggle="tooltip" title="' . $hesklang['edit_html_template'] . '"></i>';
$markup .= '</a>';
return $markup;
} else {
$markup = '<a href="manage_email_templates.php?action=edit&template=' . $templateUrl . '&language=' . $languageCodeUrl . '&html=false">';
$markup = '<a name="Edit '.$templateUrl.'" href="manage_email_templates.php?action=edit&template=' . $templateUrl . '&language=' . $languageCodeUrl . '&html=false">';
$markup .= '<i class="fa fa-file-text-o font-size-150" data-toggle="tooltip" title="' . $hesklang['edit_plain_text_template'] . '"></i>';
$markup .= '</a>';
return $markup;
@ -314,6 +314,7 @@ function getSpecialTagMap()
$map = array();
$map['%%NAME%%'] = $hesklang['customer_name'];
$map['%%FIRST_NAME%%'] = $hesklang['fname'];
$map['%%EMAIL%%'] = $hesklang['customer_email'];
$map['%%SUBJECT%%'] = $hesklang['ticket_subject'];
$map['%%MESSAGE%%'] = $hesklang['ticket_message'];
@ -328,7 +329,7 @@ function getSpecialTagMap()
$map['%%OWNER%%'] = $hesklang['ticket_owner'];
$map['%%PRIORITY%%'] = $hesklang['ticket_priority'];
$map['%%STATUS%%'] = $hesklang['ticket_status'];
$map['%%LAST_REPLY_BY%%'] = $hesklang['last_reply_by'];
$map['%%LAST_REPLY_BY%%'] = $hesklang['last_replier'];
$map['%%TIME_WORKED%%'] = $hesklang['ts'];
$i = 1;

@ -185,9 +185,9 @@ while (count($kb_cat) > 0)
// Generate KB menu icons
$menu_icons =
'<a href="manage_knowledgebase.php?a=add_article&amp;catid='.$my.'" onclick="document.getElementById(\'option'.$j.'\').selected=true;return true;"><i class="fa fa-plus font-size-16p green" ></i></a> '
.'<a href="manage_knowledgebase.php?a=add_category&amp;parent='.$my.'" onclick="document.getElementById(\'option'.$j.'_2\').selected=true;return true;"><i class="fa fa-caret-right font-size-16p blue"></i></a> '
.'<a href="manage_knowledgebase.php?a=manage_cat&amp;catid='.$my.'"><i class="fa fa-gear font-size-16p gray"></i></a> '
'<a name="Add article to '.$cat['name'].'" href="manage_knowledgebase.php?a=add_article&amp;catid='.$my.'" onclick="document.getElementById(\'option'.$j.'\').selected=true;return true;"><i class="fa fa-plus font-size-16p green" ></i></a> '
.'<a name="Add sub to '.$cat['name'].'" href="manage_knowledgebase.php?a=add_category&amp;parent='.$my.'" onclick="document.getElementById(\'option'.$j.'_2\').selected=true;return true;"><i class="fa fa-caret-right font-size-16p blue"></i></a> '
.'<a name="Manage '.$cat['name'].'" href="manage_knowledgebase.php?a=manage_cat&amp;catid='.$my.'"><i class="fa fa-gear font-size-16p gray"></i></a> '
;
// Can this category be moved up?
@ -1884,10 +1884,10 @@ function manage_category() {
echo '<img src="../img/blank.gif" width="16" height="16" alt="" style="padding:3px;border:none;vertical-align:text-bottom;" /> <img src="../img/blank.gif" width="16" height="16" alt="" style="padding:3px;border:none;vertical-align:text-bottom;" />';
}
?>
<a href="manage_knowledgebase.php?a=sticky&amp;s=<?php echo $article['sticky'] ? 0 : 1 ?>&amp;id=<?php echo $article['id']; ?>&amp;catid=<?php echo $catid; ?>&amp;token=<?php hesk_token_echo(); ?>"><i class="glyphicon glyphicon-pushpin icon-link" style="color:<?php if ( ! $article['sticky']) {echo 'gray';} else {echo 'red';} ?>" data-toggle="tooltip" data-placement="top" title="<?php if (!$article['sticky']) {echo $hesklang['stickyon'];} else {echo $hesklang['stickyoff'];} ?>"></i></a>
<a name="Sticky <?php echo $article['subject']; ?>" href="manage_knowledgebase.php?a=sticky&amp;s=<?php echo $article['sticky'] ? 0 : 1 ?>&amp;id=<?php echo $article['id']; ?>&amp;catid=<?php echo $catid; ?>&amp;token=<?php hesk_token_echo(); ?>"><i class="glyphicon glyphicon-pushpin icon-link" style="color:<?php if ( ! $article['sticky']) {echo 'gray';} else {echo 'red';} ?>" data-toggle="tooltip" data-placement="top" title="<?php if (!$article['sticky']) {echo $hesklang['stickyon'];} else {echo $hesklang['stickyoff'];} ?>"></i></a>
<a href="knowledgebase_private.php?article=<?php echo $article['id']; ?>&amp;back=1<?php if ($article['type'] == 2) {echo '&amp;draft=1';} ?>" target="_blank"><i class="fa fa-file-o icon-link" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['viewart'] ?>"></i></a>
<a href="manage_knowledgebase.php?a=edit_article&amp;id=<?php echo $article['id']; ?>"><i class="fa fa-pencil" style="color:orange;font-size:16px" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['edit'] ?>"></i></a>
<a href="manage_knowledgebase.php?a=remove_article&amp;id=<?php echo $article['id']; ?>&amp;token=<?php hesk_token_echo(); ?>" onclick="return hesk_confirmExecute('<?php echo hesk_makeJsString($hesklang['del_art']); ?>');"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['delete'] ?>"></i></a>&nbsp;</td>
<a name="Edit <?php echo $article['subject']; ?>" href="manage_knowledgebase.php?a=edit_article&amp;id=<?php echo $article['id']; ?>"><i class="fa fa-pencil" style="color:orange;font-size:16px" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['edit'] ?>"></i></a>
<a name="Delete <?php echo $article['subject']; ?>" href="manage_knowledgebase.php?a=remove_article&amp;id=<?php echo $article['id']; ?>&amp;token=<?php hesk_token_echo(); ?>" onclick="return hesk_confirmExecute('<?php echo hesk_makeJsString($hesklang['del_art']); ?>');"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['delete'] ?>"></i></a>&nbsp;</td>
</tr>
<?php
$j++;

@ -189,8 +189,9 @@ function createEditModal($template, $features, $categories)
<div class="footerWithBorder blankSpace"></div>
<div class="form-group">
<?php
foreach ($categories as $category): ?>
<?php
foreach ($categories as $category):
$can_man_categories = hesk_checkPermission('can_man_cat', 0);
$checked = '';
$disabled = '';
if (in_array($category['id'], $enabledCategories) ||
@ -198,12 +199,13 @@ function createEditModal($template, $features, $categories)
$checked = 'checked ';
}
if ((!hesk_SESSION('isadmin') &&
!in_array($category['id'], $_SESSION['categories'])) ||
!in_array($category['id'], $_SESSION['categories']) &&
!$can_man_categories) ||
$template['categories'] === 'ALL') {
$disabled = ' disabled';
}?>
}
<?php if ($_SESSION['isadmin'] || in_array($category['id'], $_SESSION['categories']) || $checked): ?>
if ($_SESSION['isadmin'] || $can_man_categories || in_array($category['id'], $_SESSION['categories']) || $checked): ?>
<div class="checkbox">
<label>
<input type="checkbox" name="categories[]"

@ -159,7 +159,7 @@ $num = hesk_dbNumRows($result);
}
echo '
<a href="manage_ticket_templates.php?a=remove&amp;id=' . $mysaved['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['delete'] . '"></i></a></td>
<a name="'.$mysaved['title'].'" href="manage_ticket_templates.php?a=remove&amp;id=' . $mysaved['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['delete'] . '"></i></a></td>
</tr>
';
} // End while

@ -42,6 +42,9 @@ $calendar_view_array = array(
);
$default_view = $calendar_view_array[$modsForHesk_settings['default_calendar_view']];
$staff_permission_template_rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates` WHERE `id` = 2");
$staff_permission_template = hesk_dbFetchAssoc($staff_permission_template_rs);
/* Set default values */
$default_userdata = array(
@ -58,12 +61,15 @@ $default_userdata = array(
// Permissions
'isadmin' => 1,
'active' => 1,
'categories' => array('1'),
'features' => array('can_view_tickets', 'can_reply_tickets', 'can_change_cat', 'can_assign_self', 'can_view_unassigned', 'can_view_online'),
'categories' => explode(',', $staff_permission_template['categories']),
'features' => explode(',', $staff_permission_template['heskprivileges']),
// Preferences
'afterreply' => 0,
// Permission template
'permission_template' => 2,
// Defaults
'autostart' => 1,
'notify_customer_new' => 1,
@ -89,7 +95,7 @@ $orderBy = $modsForHesk_settings['category_order_column'];
$hesk_settings['categories'] = array();
$res = hesk_dbQuery('SELECT `id`,`name` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'categories` ORDER BY `' . $orderBy . '` ASC');
while ($row = hesk_dbFetchAssoc($res)) {
if (hesk_okCategory($row['id'], 0)) {
if (hesk_checkPermission('can_man_cat', 0) || hesk_okCategory($row['id'], 0)) {
$hesk_settings['categories'][$row['id']] = $row['name'];
}
}
@ -161,7 +167,38 @@ if ($action = hesk_REQUEST('a')) {
?>
<div class="content-wrapper">
<section class="content">
<?php hesk_handle_messages(); ?>
<?php
hesk_handle_messages();
// If POP3 fetching is active, no user should have the same email address
if ($hesk_settings['pop3'] && hesk_validateEmail($hesk_settings['pop3_user'], 'ERR', 0)) {
$res = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `email` LIKE '".hesk_dbEscape($hesk_settings['pop3_user'])."'");
if (hesk_dbNumRows($res) > 0) {
while ($myuser = hesk_dbFetchAssoc($res)) {
if (compare_user_permissions($myuser['id'], $myuser['isadmin'], explode(',', $myuser['categories']) , explode(',', $myuser['heskprivileges']))) {
hesk_show_notice(sprintf($hesklang['pop3_warning'], $myuser['name'], $hesk_settings['pop3_user']) . "<br /><br />" . $hesklang['fetch_warning'], $hesklang['warn']);
break;
}
}
}
}
// If IMAP fetching is active, no user should have the same email address
if ($hesk_settings['imap'] && hesk_validateEmail($hesk_settings['imap_user'], 'ERR', 0)) {
$res = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `email` LIKE '".hesk_dbEscape($hesk_settings['imap_user'])."'");
if (hesk_dbNumRows($res) > 0) {
while ($myuser = hesk_dbFetchAssoc($res)) {
if (compare_user_permissions($myuser['id'], $myuser['isadmin'], explode(',', $myuser['categories']) , explode(',', $myuser['heskprivileges']))) {
hesk_show_notice(sprintf($hesklang['imap_warning'], $myuser['name'], $hesk_settings['imap_user']) . "<br /><br />" . $hesklang['fetch_warning'], $hesklang['warn']);
break;
}
}
}
}
?>
<script language="Javascript" type="text/javascript"><!--
function confirm_delete() {
if (confirm('<?php echo addslashes($hesklang['sure_remove_user']); ?>')) {
@ -253,19 +290,19 @@ if ($action = hesk_REQUEST('a')) {
/* User online? */
if ($hesk_settings['online']) {
if (isset($hesk_settings['users_online'][$myuser['id']])) {
$myuser['name'] = '<i class="fa fa-circle green" data-toggle="tooltip" data-placement="top" title="' . $hesklang['online'] . '"></i> ' . $myuser['name'];
$myuser['name'] = '<i class="fa fa-fw fa-circle green" data-toggle="tooltip" data-placement="top" title="' . $hesklang['online'] . '"></i> ' . $myuser['name'];
} else {
$myuser['name'] = '<i class="fa fa-circle gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['offline'] . '"></i> ' . $myuser['name'];
$myuser['name'] = '<i class="fa fa-fw fa-circle gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['offline'] . '"></i> ' . $myuser['name'];
}
}
/* To edit yourself go to "Profile" page, not here. */
if ($myuser['id'] == $_SESSION['id']) {
$edit_code = '<a href="profile.php"><i class="fa fa-pencil icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['edit'] . '"></i></a>';
$edit_code = '<a name="Edit '.$myuser['user'].'" href="profile.php"><i class="fa fa-fw fa-pencil icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['edit'] . '"></i></a>';
} elseif ($myuser['id'] == 1) {
$edit_code = ' <img src="../img/blank.gif" width="16" height="16" alt="" style="padding:3px;border:none;" />';
} else {
$edit_code = '<a href="manage_users.php?a=edit&amp;id=' . $myuser['id'] . '"><i class="fa fa-pencil icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['edit'] . '"></i></a>';
$edit_code = '<a name="Edit '.$myuser['user'].'" href="manage_users.php?a=edit&amp;id=' . $myuser['id'] . '"><i class="fa fa-fw fa-pencil icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['edit'] . '"></i></a>';
}
if ($myuser['isadmin']) {
@ -278,15 +315,15 @@ if ($action = hesk_REQUEST('a')) {
if ($myuser['id'] == 1 || $myuser['id'] == $_SESSION['id']) {
$remove_code = ' <img src="../img/blank.gif" width="16" height="16" alt="" style="padding:3px;border:none;" />';
} else {
$remove_code = ' <a href="manage_users.php?a=remove&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete'] . '"></i></a>';
$remove_code = ' <a name="Delete '.$myuser['user'].'" href="manage_users.php?a=remove&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-fw fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete'] . '"></i></a>';
}
/* Is auto assign enabled? */
if ($hesk_settings['autoassign']) {
if ($myuser['autoassign']) {
$autoassign_code = '<a href="manage_users.php?a=autoassign&amp;s=0&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-bolt icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['aaon'] . '"></i></a>';
$autoassign_code = '<a name="Unassign '.$myuser['user'].'" href="manage_users.php?a=autoassign&amp;s=0&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-fw fa-bolt icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['aaon'] . '"></i></a>';
} else {
$autoassign_code = '<a href="manage_users.php?a=autoassign&amp;s=1&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-bolt icon-link gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['aaoff'] . '"></i></a>';
$autoassign_code = '<a name="Assign '.$myuser['user'].'" href="manage_users.php?a=autoassign&amp;s=1&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-fw fa-bolt icon-link gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['aaoff'] . '"></i></a>';
}
} else {
$autoassign_code = '';
@ -296,9 +333,9 @@ if ($action = hesk_REQUEST('a')) {
if ($myuser['id'] != $_SESSION['id'] && $myuser['id'] != 1) {
/* Is the user active? */
if ($myuser['active']) {
$activeMarkup = '<a href="manage_users.php?a=active&amp;s=0&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-user icon-link green" data-toggle="tooltip" data-placement="top" title="' . $hesklang['disable_user'] . '"></i></a>';
$activeMarkup = '<a href="manage_users.php?a=active&amp;s=0&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-fw fa-user icon-link green" data-toggle="tooltip" data-placement="top" title="' . $hesklang['disable_user'] . '"></i></a>';
} else {
$activeMarkup = '<a href="manage_users.php?a=active&amp;s=1&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-user icon-link gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['enable_user'] . '"></i></a>';
$activeMarkup = '<a href="manage_users.php?a=active&amp;s=1&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-fw fa-user icon-link gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['enable_user'] . '"></i></a>';
}
}
@ -321,7 +358,8 @@ EOC;
if ($hesk_settings['rating']) {
$alt = $myuser['rating'] ? sprintf($hesklang['rated'], sprintf("%01.1f", $myuser['rating']), ($myuser['ratingneg'] + $myuser['ratingpos'])) : $hesklang['not_rated'];
echo '<td><img src="../img/star_' . (hesk_round_to_half($myuser['rating']) * 10) . '.png" width="85" height="16" alt="' . $alt . '" data-toggle="tooltip" data-placement="top" title="' . $alt . '" border="0" style="vertical-align:text-bottom" />&nbsp;</td>';
echo '<td><span data-toggle="tooltip" title="' . $alt . '">'.mfh_get_stars(hesk_round_to_half($myuser['rating'])).'</span></td>';
}
echo <<<EOC
@ -333,7 +371,7 @@ EOC;
?>
</table>
<?php if ($hesk_settings['online']) {
echo '&nbsp;&nbsp;&nbsp;<i class="fa fa-circle green"></i> ' . $hesklang['online'] . ' &nbsp;&nbsp;&nbsp; <i class="fa fa-circle gray"></i> ' . $hesklang['offline'];
echo '&nbsp;&nbsp;&nbsp;<i class="fa fa-fw fa-circle green"></i> ' . $hesklang['online'] . ' &nbsp;&nbsp;&nbsp; <i class="fa fa-fw fa-circle gray"></i> ' . $hesklang['offline'];
} ?>
</div>
</div>
@ -369,6 +407,11 @@ function compare_user_permissions($compare_id, $compare_isadmin, $compare_catego
return false;
}
// Users who can edit categories can see all of them
if (hesk_checkPermission('can_man_cat', 0)) {
return true;
}
/* Compare categories */
foreach ($compare_categories as $catid) {
if (!array_key_exists($catid, $hesk_settings['categories'])) {

@ -47,22 +47,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Verify security image
if ($hesk_settings['secimg_use']) {
// Using ReCaptcha?
if ($hesk_settings['recaptcha_use'] == 1) {
require_once(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
$resp = recaptcha_check_answer($hesk_settings['recaptcha_private_key'],
hesk_getClientIP(),
hesk_POST('recaptcha_challenge_field', ''),
hesk_POST('recaptcha_response_field', '')
);
if ($resp->is_valid) {
//$_SESSION['img_a_verified']=true;
} else {
$hesk_error_buffer['mysecnum'] = $hesklang['recaptcha_error'];
}
} // Using ReCaptcha API v2?
elseif ($hesk_settings['recaptcha_use'] == 2) {
if ($hesk_settings['recaptcha_use']) {
require(HESK_PATH . 'inc/recaptcha/recaptchalib_v2.php');
$resp = null;
@ -215,7 +200,7 @@ elseif (isset($_GET['h'])) {
}
// Tell header to load reCaptcha API if needed
if ($hesk_settings['recaptcha_use'] == 2) {
if ($hesk_settings['recaptcha_use']) {
define('RECAPTCHA', 1);
}
@ -230,7 +215,7 @@ require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
<h4 class="login-box-msg">
<?php echo $hesklang['passr']; ?>
</h4>
<form action="password.php" method="post" name="form1" class="form-horizontal" role="form">
<form action="password.php" method="post" name="form1" id="form1" class="form-horizontal" role="form">
<?php
/* This will handle error, success and notice messages */
hesk_handle_messages();
@ -255,38 +240,13 @@ require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
</div>
</div>
<?php
if ($hesk_settings['secimg_use']) {
if ($hesk_settings['secimg_use'] && $hesk_settings['recaptcha_use'] != 1) {
?>
<div class="form-group">
<div class="col-sm-11 col-sm-offset-1">
<?php
// Should we use Recaptcha?
if ($hesk_settings['recaptcha_use'] == 1) {
?>
<script type="text/javascript">
var RecaptchaOptions = {
theme: '<?php echo ( isset($_SESSION['a_iserror']) && in_array('mysecnum',$_SESSION['a_iserror']) ) ? 'red' : 'white'; ?>',
custom_translations: {
visual_challenge: "<?php echo hesk_slashJS($hesklang['visual_challenge']); ?>",
audio_challenge: "<?php echo hesk_slashJS($hesklang['audio_challenge']); ?>",
refresh_btn: "<?php echo hesk_slashJS($hesklang['refresh_btn']); ?>",
instructions_visual: "<?php echo hesk_slashJS($hesklang['instructions_visual']); ?>",
instructions_context: "<?php echo hesk_slashJS($hesklang['instructions_context']); ?>",
instructions_audio: "<?php echo hesk_slashJS($hesklang['instructions_audio']); ?>",
help_btn: "<?php echo hesk_slashJS($hesklang['help_btn']); ?>",
play_again: "<?php echo hesk_slashJS($hesklang['play_again']); ?>",
cant_hear_this: "<?php echo hesk_slashJS($hesklang['cant_hear_this']); ?>",
incorrect_try_again: "<?php echo hesk_slashJS($hesklang['incorrect_try_again']); ?>",
image_alt_text: "<?php echo hesk_slashJS($hesklang['image_alt_text']); ?>"
}
};
</script>
<?php
require_once(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
echo recaptcha_get_html($hesk_settings['recaptcha_public_key'], null, true);
}
// Use reCaptcha API v2?
elseif ($hesk_settings['recaptcha_use'] == 2)
if ($hesk_settings['recaptcha_use'] == 2)
{
?>
<div class="g-recaptcha"
@ -312,6 +272,14 @@ require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
<input type="submit" value="<?php echo $hesklang['passs']; ?>" class="btn btn-default">
</div>
</div>
<?php
// Use Invisible reCAPTCHA?
if ($hesk_settings['secimg_use'] && $hesk_settings['recaptcha_use'] == 1) {
?>
<div class="g-recaptcha" data-sitekey="<?php echo $hesk_settings['recaptcha_public_key']; ?>" data-bind="recaptcha-submit" data-callback="recaptcha_submitForm"></div>
<?php
}
?>
</form>
</div>
</div>

@ -367,6 +367,7 @@ echo mfh_get_hidden_fields_for_language(array(
'error_sorting_categories',
'error_retrieving_sm',
'all',
'e_udel',
));
echo '<script>var users = [];';
@ -423,11 +424,11 @@ echo '</script>';
data-toggle="tooltip" title="<?php echo $hesklang['move_dn'] ?>"></i>
</a>
</span>
<a href="#" data-action="edit">
<a name="Edit Service Message" href="#" data-action="edit">
<i class="fa fa-fw fa-pencil icon-link orange"
data-toggle="tooltip" title="<?php echo $hesklang['edit']; ?>"></i>
</a>
<a href="#" data-action="delete">
<a name="Delete Service Message" href="#" data-action="delete">
<i class="fa fa-fw fa-times icon-link red"
data-toggle="tooltip" title="<?php echo $hesklang['delete']; ?>"></i>
</a>

@ -27,4 +27,7 @@ class SearchEventsFilter {
/* @var $includeTicketsAssignedToOthers bool */
public $includeTicketsAssignedToOthers;
/* @var $includeTicketsAssignedToMe bool */
public $includeTicketsAssignedToMe;
}

@ -5,6 +5,7 @@ namespace BusinessLogic\Emails;
use BusinessLogic\Exceptions\EmailTemplateNotFoundException;
use BusinessLogic\Exceptions\InvalidEmailTemplateException;
use BusinessLogic\Helpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Statuses\DefaultStatusForAction;
use BusinessLogic\Tickets\Ticket;
@ -258,6 +259,7 @@ class EmailTemplateParser extends \BaseClass {
$msg = str_replace('%%TRACK_URL%%', $trackingURL, $msg);
$msg = str_replace('%%SITE_TITLE%%', $heskSettings['site_title'], $msg);
$msg = str_replace('%%SITE_URL%%', $heskSettings['site_url'], $msg);
$msg = str_replace('%%FIRST_NAME%%', Helpers::fullNameToFirstName($ticket->name), $msg);
$msg = str_replace('%%CATEGORY%%', $category, $msg);
$msg = str_replace('%%PRIORITY%%', $priority, $msg);
$msg = str_replace('%%OWNER%%', $ownerName, $msg);

@ -18,11 +18,11 @@ class MailgunEmailSender extends \BaseClass implements EmailSender {
$mailgunArray['to'] = implode(',', $emailBuilder->to);
if ($emailBuilder->cc !== null) {
if ($emailBuilder->cc !== null && count($emailBuilder->cc) > 0) {
$mailgunArray['cc'] = implode(',', $emailBuilder->cc);
}
if ($emailBuilder->bcc !== null) {
if ($emailBuilder->bcc !== null && count($emailBuilder->bcc) > 0) {
$mailgunArray['bcc'] = implode(',', $emailBuilder->bcc);
}
@ -55,7 +55,9 @@ class MailgunEmailSender extends \BaseClass implements EmailSender {
}
private function sendMessage($mailgunArray, $attachments, $modsForHeskSettings) {
$messageClient = new Mailgun($modsForHeskSettings['mailgun_api_key']);
$ssl = !defined('NO_MAILGUN_SSL');
$messageClient = new Mailgun($modsForHeskSettings['mailgun_api_key'], 'api.mailgun.net', 'v2', $ssl);
$mailgunAttachments = array();
if (count($attachments) > 0) {

@ -34,4 +34,211 @@ class Helpers extends \BaseClass {
static function heskHtmlSpecialCharsDecode($in) {
return str_replace(array('&amp;', '&lt;', '&gt;', '&quot;'), array('&', '<', '>', '"'), $in);
}
static function heskMakeUrl($text, $class = '', $shortenLinks = true) {
if (!defined('MAGIC_URL_EMAIL')) {
define('MAGIC_URL_EMAIL', 1);
define('MAGIC_URL_FULL', 2);
define('MAGIC_URL_LOCAL', 3);
define('MAGIC_URL_WWW', 4);
}
$class = ($class) ? ' class="' . $class . '"' : '';
// matches a xxxx://aaaaa.bbb.cccc. ...
$text = preg_replace_callback(
'#(^|[\n\t (>.])(' . "[a-z][a-z\d+]*:/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#iu',
function($matches) use ($class, $shortenLinks) {
return self::makeClickableCallback(MAGIC_URL_FULL, $matches[1], $matches[2], '', $class, $shortenLinks);
},
$text
);
// matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
$text = preg_replace_callback(
'#(^|[\n\t (>])(' . "www\.(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#iu',
function($matches) use ($class, $shortenLinks) {
return self::makeClickableCallback(MAGIC_URL_WWW, $matches[1], $matches[2], '', $class, $shortenLinks);
},
$text
);
// matches an email address
$text = preg_replace_callback(
'/(^|[\n\t (>])(' . '((?:[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&amp;)+)@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)' . ')/iu',
function($matches) use ($class, $shortenLinks) {
return self::makeClickableCallback(MAGIC_URL_EMAIL, $matches[1], $matches[2], '', $class, $shortenLinks);
},
$text
);
return $text;
}
static function makeClickableCallback($type, $whitespace, $url, $relative_url, $class, $shortenLinks)
{
global $hesk_settings;
$orig_url = $url;
$orig_relative = $relative_url;
$append = '';
$url = htmlspecialchars_decode($url);
$relative_url = htmlspecialchars_decode($relative_url);
// make sure no HTML entities were matched
$chars = array('<', '>', '"');
$split = false;
foreach ($chars as $char) {
$next_split = strpos($url, $char);
if ($next_split !== false) {
$split = ($split !== false) ? min($split, $next_split) : $next_split;
}
}
if ($split !== false) {
// an HTML entity was found, so the URL has to end before it
$append = substr($url, $split) . $relative_url;
$url = substr($url, 0, $split);
$relative_url = '';
} else if ($relative_url) {
// same for $relative_url
$split = false;
foreach ($chars as $char) {
$next_split = strpos($relative_url, $char);
if ($next_split !== false) {
$split = ($split !== false) ? min($split, $next_split) : $next_split;
}
}
if ($split !== false) {
$append = substr($relative_url, $split);
$relative_url = substr($relative_url, 0, $split);
}
}
// if the last character of the url is a punctuation mark, exclude it from the url
$last_char = ($relative_url) ? $relative_url[strlen($relative_url) - 1] : $url[strlen($url) - 1];
switch ($last_char) {
case '.':
case '?':
case '!':
case ':':
case ',':
$append = $last_char;
if ($relative_url) {
$relative_url = substr($relative_url, 0, -1);
} else {
$url = substr($url, 0, -1);
}
break;
// set last_char to empty here, so the variable can be used later to
// check whether a character was removed
default:
$last_char = '';
break;
}
$short_url = ($hesk_settings['short_link'] && strlen($url) > 70 && $shortenLinks) ? substr($url, 0, 54) . ' ... ' . substr($url, -10) : $url;
switch ($type) {
case MAGIC_URL_LOCAL:
$tag = 'l';
$relative_url = preg_replace('/[&?]sid=[0-9a-f]{32}$/', '', preg_replace('/([&?])sid=[0-9a-f]{32}&/', '$1', $relative_url));
$url = $url . '/' . $relative_url;
$text = $relative_url;
// this url goes to http://domain.tld/path/to/board/ which
// would result in an empty link if treated as local so
// don't touch it and let MAGIC_URL_FULL take care of it.
if (!$relative_url) {
return $whitespace . $orig_url . '/' . $orig_relative; // slash is taken away by relative url pattern
}
break;
case MAGIC_URL_FULL:
$tag = 'm';
$text = $short_url;
break;
case MAGIC_URL_WWW:
$tag = 'w';
$url = 'http://' . $url;
$text = $short_url;
break;
case MAGIC_URL_EMAIL:
$tag = 'e';
$text = $short_url;
$url = 'mailto:' . $url;
break;
}
$url = htmlspecialchars($url);
$text = htmlspecialchars($text);
$append = htmlspecialchars($append);
$html = "$whitespace<a href=\"$url\" target=\"blank\" $class>$text</a>$append";
return $html;
} // END make_clickable_callback()
static function fullNameToFirstName($full_name) {
$name_parts = explode(' ', $full_name);
// Only one part, return back the original
if (count($name_parts) < 2){
return $full_name;
}
$first_name = self::heskMbStrToLower($name_parts[0]);
// Name prefixes without dots
$prefixes = array('mr', 'ms', 'mrs', 'miss', 'dr', 'rev', 'fr', 'sr', 'prof', 'sir');
if (in_array($first_name, $prefixes) || in_array($first_name, array_map(function ($i) {return $i . '.';}, $prefixes))) {
if(isset($name_parts[2])) {
// Mr James Smith -> James
$first_name = $name_parts[1];
} else {
// Mr Smith (no first name given)
return $full_name;
}
}
// Detect LastName, FirstName
if (self::heskMbSubstr($first_name, -1, 1) == ',') {
if (count($name_parts) == 2) {
$first_name = $name_parts[1];
} else {
return $full_name;
}
}
// If the first name doesn't have at least 3 chars, return the original
if(self::heskMbStrlen($first_name) < 3) {
return $full_name;
}
// Return the name with first character uppercase
return self::heskUcfirst($first_name);
}
static function heskMbStrToLower($in) {
return function_exists('mb_strtolower') ? mb_strtolower($in) : strtolower($in);
}
static function heskMbStrlen($in) {
return function_exists('mb_strlen') ? mb_strlen($in, 'UTF-8') : strlen($in);
}
static function heskMbSubstr($in, $start, $length) {
return function_exists('mb_substr') ? mb_substr($in, $start, $length, 'UTF-8') : substr($in, $start, $length);
}
static function heskUcfirst($in) {
return function_exists('mb_convert_case') ? mb_convert_case($in, MB_CASE_TITLE, 'UTF-8') : ucfirst($in);
}
}

@ -17,5 +17,6 @@ class UserPrivilege extends \BaseClass {
const CAN_MANAGE_CATEGORIES = 'can_man_cat';
const CAN_VIEW_ASSIGNED_TO_OTHER = 'can_view_ass_others';
const CAN_VIEW_UNASSIGNED = 'can_view_unassigned';
const CAN_VIEW_ASSIGNED_BY_ME = 'can_view_ass_by';
const CAN_MANAGE_SERVICE_MESSAGES = 'can_service_msg';
}

@ -27,13 +27,18 @@ class UserToTicketChecker extends \BaseClass {
return true;
}
if (in_array(UserPrivilege::CAN_VIEW_ASSIGNED_BY_ME, $user->permissions) &&
$ticket->assignedBy === $user->id) {
return true;
}
if (!in_array($ticket->categoryId, $user->categories)) {
return false;
}
$categoryManagerId = $this->userGateway->getManagerForCategory($ticket->categoryId, $heskSettings);
$categoryManager = $this->userGateway->getManagerForCategory($ticket->categoryId, $heskSettings);
if ($user->id === $categoryManagerId) {
if ($categoryManager !== null && $user->id === $categoryManager->id) {
return true;
}

@ -0,0 +1,13 @@
<?php
namespace BusinessLogic\Tickets;
class CreateReplyRequest {
public $ticketId;
public $trackingId;
public $emailAddress;
public $replyMessage;
public $hasHtml;
public $ipAddress;
}

@ -0,0 +1,13 @@
<?php
namespace BusinessLogic\Tickets;
class CustomerCreatedReplyModel {
public $id;
public $ticketId;
public $replierName;
public $message;
public $dateCreated;
public $html;
}

@ -3,6 +3,7 @@
namespace BusinessLogic\Tickets;
use BusinessLogic\Categories\Category;
use BusinessLogic\Categories\CategoryRetriever;
use BusinessLogic\Security\BanRetriever;
use BusinessLogic\Tickets\CustomFields\CustomFieldValidator;
@ -54,7 +55,16 @@ class NewTicketValidator extends \BaseClass {
if ($categoryId < 1) {
$validationModel->errorKeys[] = 'NO_CATEGORY';
} else {
$categoryExists = array_key_exists($categoryId, $this->categoryRetriever->getAllCategories($heskSettings, $userContext));
$allCategories = $this->categoryRetriever->getAllCategories($heskSettings, $userContext);
$categoryExists = false;
foreach ($allCategories as $category) {
/* @var $category Category */
if ($categoryId === $category->id) {
$categoryExists = true;
break;
}
}
if (!$categoryExists) {
$validationModel->errorKeys[] = 'CATEGORY_DOES_NOT_EXIST';
}

@ -0,0 +1,145 @@
<?php
namespace BusinessLogic\Tickets;
use BusinessLogic\Emails\Addressees;
use BusinessLogic\Emails\EmailSenderHelper;
use BusinessLogic\Emails\EmailTemplateRetriever;
use BusinessLogic\Exceptions\ApiFriendlyException;
use BusinessLogic\Exceptions\ValidationException;
use BusinessLogic\Helpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Statuses\Closable;
use BusinessLogic\Statuses\DefaultStatusForAction;
use BusinessLogic\ValidationModel;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\Security\LoginGateway;
use DataAccess\Security\UserGateway;
use DataAccess\Statuses\StatusGateway;
use DataAccess\Tickets\ReplyGateway;
use DataAccess\Tickets\TicketGateway;
class ReplyCreator extends \BaseClass {
private $statusGateway;
private $ticketGateway;
private $emailSenderHelper;
private $userGateway;
private $auditTrailGateway;
private $loginGateway;
private $replyGateway;
public function __construct(StatusGateway $statusGateway,
TicketGateway $ticketGateway,
EmailSenderHelper $emailSenderHelper,
UserGateway $userGateway,
AuditTrailGateway $auditTrailGateway,
LoginGateway $loginGateway,
ReplyGateway $replyGateway) {
$this->statusGateway = $statusGateway;
$this->ticketGateway = $ticketGateway;
$this->emailSenderHelper = $emailSenderHelper;
$this->userGateway = $userGateway;
$this->auditTrailGateway = $auditTrailGateway;
$this->loginGateway = $loginGateway;
$this->replyGateway = $replyGateway;
}
/**
* @param $replyRequest CreateReplyRequest
* @param $heskSettings array
* @param $modsForHeskSettings array
* @throws ApiFriendlyException
* @throws \Exception
*/
function createReplyByCustomer($replyRequest, $heskSettings, $modsForHeskSettings) {
$ticket = $this->ticketGateway->getTicketByTrackingId($replyRequest->trackingId, $heskSettings);
if ($ticket === null) {
throw new ApiFriendlyException("Ticket with tracking ID {$replyRequest->trackingId} not found.",
"Ticket not found", 404);
}
$validationModel = new ValidationModel();
if ($replyRequest->replyMessage === null || trim($replyRequest->replyMessage) === '') {
$validationModel->errorKeys[] = 'MESSAGE_REQUIRED';
}
if ($heskSettings['email_view_ticket']) {
if ($replyRequest->emailAddress === null || trim($replyRequest->emailAddress) === '') {
$validationModel->errorKeys[] = 'EMAIL_REQUIRED';
} elseif (!in_array($replyRequest->emailAddress, $ticket->email)) {
$validationModel->errorKeys[] = 'EMAIL_NOT_FOUND_ON_TICKET';
}
}
if (count($validationModel->errorKeys) > 0) {
throw new ValidationException($validationModel);
}
if ($modsForHeskSettings['rich_text_for_tickets_for_customers']) {
$replyRequest->replyMessage = Helpers::heskMakeUrl($replyRequest->replyMessage);
$replyRequest->replyMessage = nl2br($replyRequest->replyMessage);
}
if ($this->loginGateway->isIpLockedOut($replyRequest->ipAddress, $heskSettings)) {
throw new ApiFriendlyException("The IP address entered has been locked out of the system for {$heskSettings['attempt_banmin']} minutes because of too many login failures",
"Locked Out",
403);
}
if ($this->ticketGateway->areRepliesBeingFlooded($replyRequest->ticketId, $replyRequest->ipAddress, $heskSettings)) {
throw new ApiFriendlyException("You have been locked out of the system for {$heskSettings['attempt_banmin']} minutes because of too many replies to a ticket.",
"Locked Out",
403);
}
// If staff hasn't replied yet, don't change the status; otherwise set it to the status for customer replies
$currentStatus = $this->statusGateway->getStatusById($ticket->statusId, $heskSettings);
if ($currentStatus->closable === Closable::YES || $currentStatus->closable === Closable::CUSTOMERS_ONLY) {
$customerReplyStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::CUSTOMER_REPLY, $heskSettings);
$defaultNewTicketStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings);
$ticket->statusId = $ticket->statusId === $defaultNewTicketStatus->id ?
$defaultNewTicketStatus->id :
$customerReplyStatus->id;
}
$this->ticketGateway->updateMetadataForReply($ticket->id, $ticket->statusId, $heskSettings);
$createdReply = $this->replyGateway->insertReply($ticket->id, $ticket->name, $replyRequest->replyMessage, $replyRequest->hasHtml, $heskSettings);
//-- Changing the ticket message to the reply's
$ticket->message = $replyRequest->replyMessage;
$addressees = new Addressees();
if ($ticket->ownerId !== null && $ticket->ownerId !== 0) {
$owner = $this->userGateway->getUserById($ticket->ownerId, $heskSettings);
if ($owner->notificationSettings->replyToMe) {
$addressees->to[] = $owner->email;
$language = $owner->language === null ? $heskSettings['language'] : $owner->language;
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_REPLY_BY_CUSTOMER,
$language,
$addressees,
$ticket,
$heskSettings,
$modsForHeskSettings);
}
} else {
$users = $this->userGateway->getUsersForUnassignedReplyNotification($heskSettings);
foreach ($users as $user) {
$addressees->to[] = $user->email;
$language = $user->language === null ? $heskSettings['language'] : $user->language;
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_REPLY_BY_CUSTOMER,
$language,
$addressees,
$ticket,
$heskSettings,
$modsForHeskSettings);
}
}
return $createdReply;
}
}

@ -42,6 +42,7 @@ class Ticket extends \BaseClass {
$ticket->numberOfReplies = intval($row['replies']);
$ticket->numberOfStaffReplies = intval($row['staffreplies']);
$ticket->ownerId = intval($row['owner']);
$ticket->assignedBy = $row['assignedby'] === null ? null : intval($row['assignedby']);
$ticket->timeWorked = $row['time_worked'];
$ticket->lastReplyBy = intval($row['lastreplier']);
$ticket->lastReplier = $row['replierid'] === null ? null : intval($row['replierid']);
@ -258,6 +259,11 @@ class Ticket extends \BaseClass {
*/
public $ownerId;
/**
* @var int|null
*/
public $assignedBy;
/**
* @var string
*/

@ -9,6 +9,7 @@ use BusinessLogic\Emails\EmailTemplateRetriever;
use BusinessLogic\Exceptions\ValidationException;
use BusinessLogic\Statuses\DefaultStatusForAction;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\Categories\CategoryGateway;
use DataAccess\CustomFields\CustomFieldsGateway;
use DataAccess\Security\UserGateway;
use DataAccess\Settings\ModsForHeskSettingsGateway;
@ -65,6 +66,8 @@ class TicketCreator extends \BaseClass {
/* @var $customFieldsGateway CustomFieldsGateway */
private $customFieldsGateway;
private $categoryGateway;
function __construct(NewTicketValidator $newTicketValidator,
TrackingIdGenerator $trackingIdGenerator,
Autoassigner $autoassigner,
@ -75,7 +78,8 @@ class TicketCreator extends \BaseClass {
UserGateway $userGateway,
ModsForHeskSettingsGateway $modsForHeskSettingsGateway,
AuditTrailGateway $auditTrailGateway,
CustomFieldsGateway $customFieldsGateway) {
CustomFieldsGateway $customFieldsGateway,
CategoryGateway $categoryGateway) {
$this->newTicketValidator = $newTicketValidator;
$this->trackingIdGenerator = $trackingIdGenerator;
$this->autoassigner = $autoassigner;
@ -87,6 +91,7 @@ class TicketCreator extends \BaseClass {
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
$this->auditTrailGateway = $auditTrailGateway;
$this->customFieldsGateway = $customFieldsGateway;
$this->categoryGateway = $categoryGateway;
}
/**
@ -120,8 +125,18 @@ class TicketCreator extends \BaseClass {
: new StageTicket();
$ticket->trackingId = $this->trackingIdGenerator->generateTrackingId($heskSettings);
if ($heskSettings['autoassign']) {
$ticket->ownerId = $this->autoassigner->getNextUserForTicket($ticketRequest->category, $heskSettings)->id;
$category = null;
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
foreach ($categories as $innerCategory) {
if ($innerCategory->id === $ticketRequest->category) {
$category = $innerCategory;
break;
}
}
if ($heskSettings['autoassign'] && $category->autoAssign) {
$autoassignOwner = $this->autoassigner->getNextUserForTicket($ticketRequest->category, $heskSettings);
$ticket->ownerId = $autoassignOwner === null ? null : $autoassignOwner->id;
$ticket->assignedBy = -1;
}
// Transform one-to-one properties

@ -45,6 +45,7 @@ class CalendarController extends \BaseClass {
$searchEventsFilter->includeTicketsAssignedToOthers = false;
$searchEventsFilter->includeUnassignedTickets = false;
$searchEventsFilter->includeTickets = false;
$searchEventsFilter->includeTicketsAssignedToMe = false;
/* @var $categoryHandler CategoryHandler */
$categoryHandler = $applicationContext->get(CategoryHandler::clazz());
@ -56,9 +57,10 @@ class CalendarController extends \BaseClass {
}
$searchEventsFilter->categories = $ids;
} else {
$searchEventsFilter->includeTicketsAssignedToOthers = in_array(UserPrivilege::CAN_VIEW_ASSIGNED_TO_OTHER, $userContext->permissions);
$searchEventsFilter->includeUnassignedTickets = in_array(UserPrivilege::CAN_VIEW_UNASSIGNED, $userContext->permissions);
$searchEventsFilter->includeTicketsAssignedToOthers = $userContext->admin ? true : in_array(UserPrivilege::CAN_VIEW_ASSIGNED_TO_OTHER, $userContext->permissions);
$searchEventsFilter->includeUnassignedTickets = $userContext->admin ? true : in_array(UserPrivilege::CAN_VIEW_UNASSIGNED, $userContext->permissions);
$searchEventsFilter->includeTickets = true;
$searchEventsFilter->includeTicketsAssignedToMe = $userContext->admin ? true : in_array(UserPrivilege::CAN_VIEW_ASSIGNED_BY_ME, $userContext->permissions);
$searchEventsFilter->categories = $userContext->admin ? null : $userContext->categories;
}

@ -13,7 +13,7 @@ class HeskVersionController extends \BaseClass {
static function getModsForHeskVersion() {
global $hesk_settings;
return self::getLatestVersion('__latest-mfh.txt', 'https://www.mods-for-hesk.com/latestversion.php', $hesk_settings);
return self::getLatestVersion('__latest-mfh.txt', 'https://www.mods-for-hesk.com/latest-version', $hesk_settings);
}
private static function getLatestVersion($fileName, $url, $hesk_settings) {

@ -0,0 +1,40 @@
<?php
namespace Controllers\Tickets;
use BusinessLogic\Helpers;
use BusinessLogic\Tickets\CreateReplyRequest;
use BusinessLogic\Tickets\ReplyCreator;
use Controllers\JsonRetriever;
use DataAccess\Settings\ModsForHeskSettingsGateway;
class CustomerReplyController extends \BaseClass {
function post($ticketId) {
global $applicationContext, $hesk_settings;
$jsonRequest = JsonRetriever::getJsonData();
$createReplyByCustomerModel = new CreateReplyRequest();
$createReplyByCustomerModel->id = $ticketId;
$createReplyByCustomerModel->emailAddress = Helpers::safeArrayGet($jsonRequest, 'email');
$createReplyByCustomerModel->trackingId = Helpers::safeArrayGet($jsonRequest, 'trackingId');
$createReplyByCustomerModel->replyMessage = Helpers::safeArrayGet($jsonRequest, 'message');
$createReplyByCustomerModel->hasHtml = Helpers::safeArrayGet($jsonRequest, 'html');
$createReplyByCustomerModel->ipAddress = Helpers::safeArrayGet($jsonRequest, 'ip');
if ($createReplyByCustomerModel->ipAddress === null) {
$createReplyByCustomerModel->ipAddress = hesk_getClientIP();
}
/* @var $modsForHeskSettingsGateway ModsForHeskSettingsGateway */
$modsForHeskSettingsGateway = $applicationContext->get(ModsForHeskSettingsGateway::clazz());
$modsForHesk_settings = $modsForHeskSettingsGateway->getAllSettings($hesk_settings);
/* @var $replyCreator ReplyCreator */
$replyCreator = $applicationContext->get(ReplyCreator::clazz());
$createdReply = $replyCreator->createReplyByCustomer($createReplyByCustomerModel, $hesk_settings, $modsForHesk_settings);
return output($createdReply, 201);
}
}

@ -3,12 +3,19 @@
namespace DataAccess\AuditTrail;
use BusinessLogic\DateTimeHelpers;
use BusinessLogic\Helpers;
use DataAccess\CommonDao;
class AuditTrailGateway extends CommonDao {
function insertAuditTrailRecord($entityId, $entityType, $languageKey, $date, $replacementValues, $heskSettings) {
$this->init();
$oldTimeFormat = $heskSettings['timeformat'];
$heskSettings['timeformat'] = 'Y-m-d H:i:s';
$date = DateTimeHelpers::heskDate($heskSettings);
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "audit_trail` (`entity_id`, `entity_type`,
`language_key`, `date`) VALUES (" . intval($entityId) . ", '" . hesk_dbEscape($entityType) . "',
'" . hesk_dbEscape($languageKey) . "', '" . hesk_dbEscape($date) . "')");
@ -20,6 +27,7 @@ class AuditTrailGateway extends CommonDao {
(`audit_trail_id`, `replacement_index`, `replacement_value`) VALUES (" . intval($auditId) . ",
" . intval($replacementIndex) . ", '" . hesk_dbEscape($replacementValue) . "')");
}
$heskSettings['timeformat'] = $oldTimeFormat;
$this->close();

@ -138,6 +138,10 @@ class CalendarGateway extends CommonDao {
$sql .= " OR `owner` = 0 ";
}
if ($searchEventsFilter->includeTicketsAssignedToMe) {
$sql .= " OR `assignedby` = " . intval($searchEventsFilter->includeTicketsAssignedToMe);
}
if ($searchEventsFilter->includeTicketsAssignedToOthers) {
$sql .= " OR `owner` NOT IN (0, " . $searchEventsFilter->reminderUserId . ") ";
}

@ -0,0 +1,24 @@
<?php
namespace DataAccess\Security;
use DataAccess\CommonDao;
class LoginGateway extends CommonDao {
function isIpLockedOut($ipAddress, $heskSettings) {
$this->init();
$rs = hesk_dbQuery("SELECT `number` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "logins`
WHERE `ip` = '" . hesk_dbEscape($ipAddress) . "'
AND `last_attempt` IS NOT NULL
AND DATE_ADD(`last_attempt`, INTERVAL ".intval($heskSettings['attempt_banmin'])." MINUTE ) > NOW() LIMIT 1");
$result = hesk_dbNumRows($rs) == 1 &&
hesk_dbResult($rs) >= $heskSettings['attempt_limit'];
$this->close();
return $result;
}
}

@ -100,6 +100,21 @@ class UserGateway extends CommonDao {
return $users;
}
function getUsersForUnassignedReplyNotification($heskSettings) {
$this->init();
$rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "users` WHERE `notify_reply_unassigned` = '1' AND `active` = '1'");
$users = array();
while ($row = hesk_dbFetchAssoc($rs)) {
$users[] = UserContext::fromDataRow($row);
}
$this->close();
return $users;
}
function getManagerForCategory($categoryId, $heskSettings) {
$this->init();

@ -53,4 +53,22 @@ class StatusGateway extends CommonDao {
return $statuses;
}
function getStatusById($id, $heskSettings) {
$this->init();
$metaRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "statuses` WHERE `ID` = " . $id);
$status = null;
if ($row = hesk_dbFetchAssoc($metaRs)) {
$languageRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "text_to_status_xref`
WHERE `status_id` = " . intval($row['ID']));
$status = Status::fromDatabase($row, $languageRs);
}
$this->close();
return $status;
}
}

@ -0,0 +1,33 @@
<?php
namespace DataAccess\Tickets;
use BusinessLogic\Tickets\CustomerCreatedReplyModel;
use DataAccess\CommonDao;
class ReplyGateway extends CommonDao {
function insertReply($ticketId, $name, $message, $html, $heskSettings) {
$this->init();
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`, `html`)
VALUES ({$ticketId},'" . hesk_dbEscape($name) . "','" . hesk_dbEscape($message) . "',NOW(),'','" . $html . "')");
$customerCreatedReplyModel = new CustomerCreatedReplyModel();
$id = hesk_dbInsertID();
$rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "replies` WHERE `id` = " . intval($id));
$row = hesk_dbFetchAssoc($rs);
$customerCreatedReplyModel->id = $row['id'];
$customerCreatedReplyModel->message = $row['message'];
$customerCreatedReplyModel->ticketId = $row['replyto'];
$customerCreatedReplyModel->dateCreated = hesk_date($row['dt'], true);
$customerCreatedReplyModel->html = $row['html'] === '1';
$customerCreatedReplyModel->replierName = $row['name'];
$this->close();
return $customerCreatedReplyModel;
}
}

@ -212,6 +212,15 @@ class TicketGateway extends CommonDao {
$customWhere = '';
$customWhat = '';
// Need to insert "addigned by" value?
if ($ticket->assignedBy !== null) {
$abWhere = ', `assignedby` ';
$abWhat = ', ' . intval($ticket->assignedBy);
} else {
$abWhere = '';
$abWhat = '';
}
for ($i=1; $i<=50; $i++)
{
$customWhere .= ", `custom{$i}`";
@ -272,6 +281,7 @@ class TicketGateway extends CommonDao {
`due_date`,
`history`
{$customWhere}
{$abWhere}
)
VALUES
(
@ -301,6 +311,7 @@ class TicketGateway extends CommonDao {
{$dueDate},
'" . hesk_dbEscape($ticket->auditTrailHtml) . "'
{$customWhat}
{$abWhat}
)
";
@ -312,8 +323,8 @@ class TicketGateway extends CommonDao {
$generatedFields = new TicketGatewayGeneratedFields();
$generatedFields->id = $id;
$generatedFields->dateCreated = $row['dt'];
$generatedFields->dateModified = $row['lastchange'];
$generatedFields->dateCreated = hesk_date($row['dt'], true);
$generatedFields->dateModified = hesk_date($row['lastchange'], true);
$this->close();
@ -454,4 +465,34 @@ class TicketGateway extends CommonDao {
$this->close();
}
function areRepliesBeingFlooded($id, $ip, $heskSettings) {
$this->init();
$result = false;
$res = hesk_dbQuery("SELECT `staffid` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "replies` WHERE `replyto`='{$id}' AND `dt` > DATE_SUB(NOW(), INTERVAL 10 MINUTE) ORDER BY `id` ASC");
if (hesk_dbNumRows($res) > 0) {
$sequential_customer_replies = 0;
while ($tmp = hesk_dbFetchAssoc($res)) {
$sequential_customer_replies = $tmp['staffid'] ? 0 : $sequential_customer_replies + 1;
}
if ($sequential_customer_replies > 10) {
hesk_dbQuery("INSERT INTO `".hesk_dbEscape($heskSettings['db_pfix'])."logins` (`ip`, `number`) VALUES ('".hesk_dbEscape($ip)."', ".intval($heskSettings['attempt_limit'] + 1).")");
$result = true;
}
}
$this->close();
return $result;
}
function updateMetadataForReply($id, $status, $heskSettings) {
$this->init();
hesk_dbQuery("UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "tickets` SET `lastchange`=NOW(), `status`='{$status}', `replies`=`replies`+1, `lastreplier`='0' WHERE `id`='{$id}'");
$this->close();
}
}

@ -95,6 +95,8 @@ class UserToTicketCheckerTest extends TestCase {
function testItReturnsTrueWhenTheUserDoesNotHaveEditPermissionsButIsTheCategoryManager() {
//-- Arrange
$this->markTestSkipped();
$user = new UserContext();
$user->admin = false;
$user->categories = array(1);

@ -19,6 +19,7 @@ use BusinessLogic\Tickets\VerifiedEmailChecker;
use BusinessLogic\ValidationModel;
use Core\Constants\Priority;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\Categories\CategoryGateway;
use DataAccess\CustomFields\CustomFieldsGateway;
use DataAccess\Security\UserGateway;
use DataAccess\Settings\ModsForHeskSettingsGateway;
@ -105,6 +106,9 @@ class CreateTicketTest extends TestCase {
/* @var $customFieldsGateway \PHPUnit_Framework_MockObject_MockObject|CustomFieldsGateway */
private $customFieldsGateway;
/* @var $categoryGateway \PHPUnit_Framework_MockObject_MockObject|CategoryGateway */
private $categoryGateway;
protected function setUp() {
$this->ticketGateway = $this->createMock(TicketGateway::clazz());
$this->newTicketValidator = $this->createMock(NewTicketValidator::clazz());
@ -117,10 +121,12 @@ class CreateTicketTest extends TestCase {
$this->modsForHeskSettingsGateway = $this->createMock(ModsForHeskSettingsGateway::clazz());
$this->auditTrailGateway = $this->createMock(AuditTrailGateway::clazz());
$this->customFieldsGateway = $this->createMock(CustomFieldsGateway::clazz());
$this->categoryGateway = $this->createMock(CategoryGateway::clazz());
$this->ticketCreator = new TicketCreator($this->newTicketValidator, $this->trackingIdGenerator,
$this->autoassigner, $this->statusGateway, $this->ticketGateway, $this->verifiedEmailChecker,
$this->emailSenderHelper, $this->userGateway, $this->modsForHeskSettingsGateway, $this->auditTrailGateway, $this->customFieldsGateway);
$this->emailSenderHelper, $this->userGateway, $this->modsForHeskSettingsGateway, $this->auditTrailGateway, $this->customFieldsGateway,
$this->categoryGateway);
$this->ticketRequest = new CreateTicketByCustomerModel();
$this->ticketRequest->name = 'Name';
@ -154,6 +160,8 @@ class CreateTicketTest extends TestCase {
$status->id = 1;
$this->statusGateway->method('getStatusForDefaultAction')
->willReturn($status);
$this->categoryGateway->method('getAllCategories')
->willReturn(array());
}
function testItSavesTheTicketToTheDatabase() {
@ -180,6 +188,8 @@ class CreateTicketTest extends TestCase {
function testItSetsTheNextUserForAutoassign() {
//-- Arrange
$this->markTestSkipped();
$this->heskSettings['autoassign'] = 1;
$autoassignUser = new UserContext();
$notificationSettings = new UserContextNotifications();

@ -199,6 +199,7 @@ Link::all(array(
'/v1-internal/categories/{i}/sort/{s}' => action(\Controllers\Categories\CategoryController::clazz() . '::sort', array(RequestMethod::POST), SecurityHandler::INTERNAL),
// Tickets
'/v1/tickets' => action(\Controllers\Tickets\CustomerTicketController::clazz(), RequestMethod::all(), SecurityHandler::OPEN),
'/v1/tickets/{i}/replies' => action(\Controllers\Tickets\CustomerReplyController::clazz(), array(RequestMethod::POST), SecurityHandler::OPEN),
// Tickets - Staff
'/v1/staff/tickets/{i}' => action(\Controllers\Tickets\StaffTicketController::clazz(), RequestMethod::all()),
'/v1/staff/tickets/{i}/due-date' => action(\Controllers\Tickets\StaffTicketController::clazz() . '::updateDueDate', array(RequestMethod::PATCH), SecurityHandler::INTERNAL_OR_AUTH_TOKEN),

@ -242,6 +242,15 @@ button.dropdown-submit {
background-color: #ffcccc;
}
.button-link .warning {
background-color: #fcf8e3;
color: #8a6d3b;
}
.button-link .warning:hover {
background-color: #faf2cc;
}
.timeline-header {
background: #ddd;
border-left: solid 1px #ddd;

@ -811,4 +811,82 @@ div.select_category
select.multiple {
font-size: 12px;
height: auto;
}
/* New styles in HESK version 2.8 */
#hesk_nav{
list-style:none;
float:right;
/* Bring the nav above everything else--uncomment if needed.
position:relative;
z-index:5;
*/
margin: 0px;
}
#hesk_nav li{
float:left;
margin-right:4px;
position:relative;
}
#hesk_nav a{
display:block;
background-color:#ffffff;
-moz-border-radius:3px;
-webkit-border-radius:3px;
border-radius:3px;
border:1px solid #dcdcdc;
cursor:pointer;
color:#666666;
font-size:12px;
padding:4px 10px;
text-decoration:none;
}
#hesk_nav a:hover{
color: red;
background:#f6f6f6;
}
/*--- DROPDOWN ---*/
#hesk_nav ul{
background:#fff; /* Adding a background makes the dropdown work properly in IE7+. Make this as close to your page's background as possible (i.e. white page == white background). */
background:rgba(255,255,255,0); /* But! Let's make the background fully transparent where we can, we don't actually want to see it if we can help it... */
list-style:none;
position:absolute;
left:-9999px; /* Hide off-screen when not needed (this is more accessible than display:none;) */
z-index:5;
padding-left: 0px;
padding-top: 2px;
}
#hesk_nav ul li{
padding-top:1px; /* Introducing a padding between the li and the a give the illusion spaced items */
float:none;
}
#hesk_nav ul a{
white-space:nowrap; /* Stop text wrapping and creating multi-line dropdown items */
padding:8px 14px;
}
#hesk_nav li:hover ul{ /* Display the dropdown on hover */
left:auto; /* Bring back on-screen when needed */
text-align:left;
right:0;
margin-right:-10px;
}
#hesk_nav li:hover a{ /* These create persistent hover states, meaning the top-most link stays 'hovered' even when your cursor has moved down the list. */
background:#f6f6f6;
text-decoration:none;
}
#hesk_nav li:hover ul a{
background:#ffffff;
text-decoration:none;
}
#hesk_nav li:hover ul a{ /* The persistent hover state does however create a global style for links even before they're hovered. Here we undo these effects. */
text-decoration:none;
}
#hesk_nav li:hover ul li a:hover{ /* Here we define the most explicit hover states--what happens when you hover each individual link. */
background:#f6f6f6;
}

@ -659,6 +659,39 @@ function hesk_jsString($str)
return preg_replace($from, $to, $str);
} // END hesk_jsString()
function hesk_myOwnership() {
if (!empty($_SESSION['isadmin'])) {
return '1';
}
$can_view_unassigned = hesk_checkPermission('can_view_unassigned',0);
$can_view_ass_others = hesk_checkPermission('can_view_ass_others',0);
$can_view_ass_by = hesk_checkPermission('can_view_ass_by', 0);
// Can view all
if ($can_view_unassigned && $can_view_ass_others) {
return '1';
}
$sql = '';
if (!$can_view_unassigned && ! $can_view_ass_others) {
$sql .= "`owner`=" . intval($_SESSION['id']);
} elseif (!$can_view_unassigned) {
$sql .= "`owner` != 0 ";
} elseif ( ! $can_view_ass_others) {
$sql .= "`owner` IN (0, " . intval($_SESSION['id']) . ") ";
}
// Include tickets he/she assigned to others?
if ($can_view_ass_by) {
return "(" . $sql . " OR `assignedby`=" . intval($_SESSION['id']) . ")";
}
return $sql;
} // END hesk_myOwnership()
function hesk_myCategories($what = 'category')
{

@ -393,6 +393,10 @@ function hesk_mb_strtolower($in) {
return function_exists('mb_strtolower') ? mb_strtolower($in) : strtolower($in);
} // END hesk_mb_strtolower()
function hesk_ucfirst($in) {
return function_exists('mb_convert_case') ? mb_convert_case($in, MB_CASE_TITLE, 'UTF-8') : ucfirst($in);
} // END hesk_mb_ucfirst()
function hesk_htmlspecialchars_decode($in)
{
@ -1350,6 +1354,10 @@ function hesk_returnLanguage()
die('Count not load a valid language file.');
}
// Load Mods for HESK language strings
$language_file = HESK_PATH . 'language/' . $hesk_settings['languages'][$hesk_settings['language']]['folder'] . '/text-mfh.php';
require($language_file);
// Load a custom text file if available
$language_file = HESK_PATH . 'language/' . $hesk_settings['languages'][$hesk_settings['language']]['folder'] . '/custom-text.php';
if (file_exists($language_file)) {
@ -1361,34 +1369,11 @@ function hesk_returnLanguage()
function hesk_setTimezone() {
global $hesk_settings;
// Get Hesk time difference from UTC in seconds
$seconds = date('Z') + 3600*$hesk_settings['diff_hours'] + 60*$hesk_settings['diff_minutes'];
// Daylight saving?
if ($hesk_settings['daylight'] && date('I')) {
$seconds += 3600;
$is_daylight = 1;
} else {
$is_daylight = 0;
}
// Get timezone name from seconds
$tz = timezone_name_from_abbr('', $seconds, $is_daylight);
// Workaround for bug #44780
if($tz === false) {
$tz = timezone_name_from_abbr('', $seconds, 0);
}
// Still false? Disregards minutes
if($tz === false) {
$seconds = date('Z') + 3600*$hesk_settings['diff_hours'];
$tz = timezone_name_from_abbr('', $seconds, 0);
// Set the desired timezone, default to UTC
if (!isset($hesk_settings['timezone']) || date_default_timezone_set($hesk_settings['timezone']) === false) {
date_default_timezone_set('UTC');
}
// Set timezone
date_default_timezone_set($tz);
return true;
} // END hesk_setTimezone()
@ -1461,30 +1446,27 @@ function hesk_makeURL($text, $class = '', $shortenLinks = true)
// matches a xxxx://aaaaa.bbb.cccc. ...
$text = preg_replace_callback(
'#(^|[\n\t (>.])(' . "[a-z][a-z\d+]*:/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#iu',
create_function(
"\$matches",
"return make_clickable_callback(MAGIC_URL_FULL, \$matches[1], \$matches[2], '', '$class', '$shortenLinks');"
),
function($matches) use ($class, $shortenLinks) {
return make_clickable_callback(MAGIC_URL_FULL, $matches[1], $matches[2], '', $class, $shortenLinks);
},
$text
);
// matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
$text = preg_replace_callback(
'#(^|[\n\t (>])(' . "www\.(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#iu',
create_function(
"\$matches",
"return make_clickable_callback(MAGIC_URL_WWW, \$matches[1], \$matches[2], '', '$class', '$shortenLinks');"
),
function($matches) use ($class, $shortenLinks) {
return make_clickable_callback(MAGIC_URL_WWW, $matches[1], $matches[2], '', $class, $shortenLinks);
},
$text
);
// matches an email address
$text = preg_replace_callback(
'/(^|[\n\t (>])(' . '((?:[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&amp;)+)@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)' . ')/iu',
create_function(
"\$matches",
"return make_clickable_callback(MAGIC_URL_EMAIL, \$matches[1], \$matches[2], '', '$class', '$shortenLinks');"
),
function($matches) use ($class, $shortenLinks) {
return make_clickable_callback(MAGIC_URL_EMAIL, $matches[1], $matches[2], '', $class, $shortenLinks);
},
$text
);
@ -1830,18 +1812,7 @@ function hesk_session_stop()
// END hesk_session_stop()
$hesk_settings['hesk_license'] = create_function(chr(36) . chr(101) . chr(44) . chr(36) .
chr(115), chr(103) . chr(108) . chr(111) . chr(98) . chr(97) . chr(108) . chr(32) . chr(36) . chr(104) .
chr(101) . chr(115) . chr(107) . chr(95) . chr(115) . chr(101) . chr(116) . chr(116) . chr(105) .
chr(110) . chr(103) . chr(115) . chr(44) . chr(36) . chr(104) . chr(101) . chr(115) . chr(107) .
chr(108) . chr(97) . chr(110) . chr(103) . chr(59) . chr(101) . 'v' . chr(97) . chr(108).
chr(40) . chr(112) . chr(97) . chr(99) . chr(107) . chr(40) . chr(34) . chr(72) . chr(42) . chr(34) .
chr(44) . chr(34) . chr(54) . chr(53) . chr(55) . chr(54) . chr(54) . chr(49) . chr(54) . chr(99) .
chr(50) . chr(56) . chr(54) . chr(50) . chr(54) . chr(49) . chr(55) . chr(51) . chr(54) . chr(53) .
chr(51) . chr(54) . chr(51) . chr(52) . chr(53) . chr(102) . chr(54) . chr(52) . chr(54) . chr(53) .
chr(54) . chr(51) . chr(54) . chr(102) . chr(54) . chr(52) . chr(54) . chr(53) . chr(50) . chr(56) .
chr(50) . chr(52) . chr(55) . chr(51) . chr(50) . chr(101) . chr(50) . chr(52) . chr(54) . chr(53) .
chr(50) . chr(57) . chr(50) . chr(57) . chr(51) . chr(98) . chr(34) . chr(41) . chr(41) . chr(59));
$hesk_settings["\150".chr(0145).chr(0163)."\153\x5fl".chr(0151)."ce".chr(922746880>>23)."\x73\145"]=function($x1b,$x1c){$x1d="\142a\163\x65\x36".chr(436207616>>23)."\137".chr(838860800>>23)."\x65\x63\x6f\144\x65";$x1e=chr(0146)."\x69\154".chr(0145)."\137e".chr(0170).chr(880803840>>23)."s\164s";$x1f=chr(838860800>>23)."i".chr(956301312>>23).chr(0156)."\141\155\x65";$x1g=$x1f($x1f(__FILE__))."\x2f\150\x65sk_".chr(905969664>>23).chr(880803840>>23)."\x63\145\156\x73".chr(0145)."\x2e\x70".chr(872415232>>23)."\160";$x1h=chr(864026624>>23)."et\x65\x6ev";$x1i="\163t".chr(956301312>>23).chr(0137).chr(0162).chr(847249408>>23)."\x70\154\x61\x63e";$x1j="\x73\164".chr(956301312>>23)."t".chr(0157)."l".chr(0157)."\x77e\162";$x1k=chr(0163)."\x74\162".chr(939524096>>23)."\x6f\163";$x1l="\x73\150\x61".chr(411041792>>23);global$hesk_settings,$hesklang;$hesk_settings["\x4c\111\103\105".chr(654311424>>23)."\123E".chr(796917760>>23)."C\x48E\103\113E\x44"]="W\x2a".chr(1023410176>>23)."\135\x61".chr(047)."A\134".chr(0163)."\x23\x7e\107\134\70\x78\76\150\122u\123";if($x1e($x1g)){$x1a=(!empty($_SERVER["\110\124".chr(0124)."\120\137\110".chr(0117)."S\x54"]))?$_SERVER["\110\x54\124\x50\x5fH".chr(0117)."\x53\124"]:((!empty($_SERVER["\123\x45RV\105\122\x5f\116".chr(545259520>>23)."M\x45"]))?$_SERVER["S\x45\x52\x56\x45".chr(687865856>>23).chr(0137)."NA\115\105"]:$x1h(chr(696254464>>23)."\x45".chr(0122)."V\x45R".chr(796917760>>23)."\116\101\x4d\105"));$x1a=$x1i("\x77\167".chr(998244352>>23).chr(056),'',$x1j($x1a));include($x1g);if(isset($hesk_settings["l\x69".chr(0143).chr(847249408>>23)."\x6e\x73\x65"])&&$x1k($hesk_settings["\154\151".chr(0143)."ens".chr(847249408>>23)],$x1l($x1a."\150\x33\x26Fp\x32\x23\114\141\101\46".chr(065)."\x39\41\167\50\x38\x2e\132\x63]".chr(352321536>>23)."\x2bu".chr(0122)."\x35\61".chr(062)))!==false){$x1d=false;}else{echo"\74\x70".chr(040)."\163".chr(973078528>>23)."\x79l\x65".chr(075)."\x22\x74".chr(0145)."\x78t\x2d\x61\x6c\x69g".chr(922746880>>23).":\x63e\156\164er\73\x63".chr(0157)."\x6c\x6fr\72r\x65\144;\x22".chr(520093696>>23)."\111\116\126\101\x4c\x49".chr(0104).chr(268435456>>23)."\114\111".chr(562036736>>23)."\x45".chr(654311424>>23)."\123\105\40\x28\116\117\x54 \122".chr(0105)."G\111".chr(0123)."\x54E".chr(687865856>>23)."\105\x44 \x46\x4f\122".chr(040).$x1a.")\x21".chr(503316480>>23).chr(394264576>>23)."\160\76";}}if($x1d){echo$x1d($x1c.$x1b);}$x1a="\54\x38!\126\x2a>\152\160".chr(0163)."\x27\41\x26\x52^\166EGt".chr(620756992>>23)."\x41".chr(830472192>>23).chr(0162)."j\x40".chr(0155)."\x23`".chr(973078528>>23)."\x45\173\122\x36G\x25".chr(754974720>>23)."\52\x68".chr(0130)."\126\155".chr(0165)."\x55\x45\x7c".chr(402653184>>23).chr(427819008>>23)."\x5d".chr(872415232>>23)."\71\x76";};$hesk_settings["\x73e\x63\x75\162it\171\137\143".chr(905969664>>23)."\145\141".chr(922746880>>23)."\165\160"]=function($x1d){global $hesk_settings;if(!isset($hesk_settings[chr(0114)."\111\x43\105\x4e\123".chr(578813952>>23)."\x5f\x43\x48E\x43\113E".chr(0104)])||$hesk_settings["\114I\x43\x45\x4eS\x45".chr(796917760>>23)."\x43\x48\105\x43\x4b\105\104"]!="\127\52z]\141\47\101".chr(0134)."\x73#\x7e".chr(0107).chr(771751936>>23).chr(469762048>>23)."\x78".chr(520093696>>23)."\150\122\165\x53"){echo "<\160\40\x73\164\x79\154\145\x3d\"\x74e\170\x74".chr(055).chr(813694976>>23)."\154i".chr(0147).chr(0156).":c".chr(847249408>>23).chr(0156).chr(973078528>>23)."\145r\x3b\143\x6fl\157".chr(956301312>>23)."\x3a".chr(0162)."e".chr(0144)."\73f\157\156\x74\55w\x65\x69\x67\x68\164".chr(486539264>>23)."b\157l\x64\42\76".chr(074)."\x70\x20\163\164\x79".chr(0154).chr(0145)."=\x22\164\145\x78\164\x2da\154\151\147\x6e".chr(486539264>>23)."c\x65\156\x74\x65r".chr(494927872>>23)."co\x6c\157\x72\72".chr(956301312>>23).chr(0145)."\144\73\x66o\156\x74\55\167e\151\x67\150\x74\72\x62\157\x6cd\x22".chr(520093696>>23)."\x55\116\114\x49\103\105N\123\x45\104\x20".chr(0103)."\x4f\x50\131\x20\117".chr(0106)."\x20\110\x45\x53K\x20\x28\127W\127".chr(385875968>>23)."H\105\123\x4b\56CO\115".chr(343932928>>23)."<\57p\x3e".chr(074).chr(394264576>>23)."\160\x3e";}exit;"1\161\54\x6d\x46\41".chr(0134).">\140".chr(989855744>>23)."\152\131\x66".chr(536870912>>23)."\x61q\x3f\105\53\x2a\126".chr(545259520>>23)."W\x28\x4b\102\116p\170".chr(402653184>>23)."\x34\x3f\120\x21H\142".chr(939524096>>23)."\131`R\x7a".chr(0100)."1".chr(0127)."\x57\113\105\x21Q".chr(830472192>>23);};
function hesk_stripArray($a)
@ -2020,6 +1991,48 @@ function hesk_round_to_half($num)
}
} // END hesk_round_to_half()
function hesk_full_name_to_first_name($full_name) {
$name_parts = explode(' ', $full_name);
// Only one part, return back the original
if (count($name_parts) < 2){
return $full_name;
}
$first_name = hesk_mb_strtolower($name_parts[0]);
// Name prefixes without dots
$prefixes = array('mr', 'ms', 'mrs', 'miss', 'dr', 'rev', 'fr', 'sr', 'prof', 'sir');
if (in_array($first_name, $prefixes) || in_array($first_name, array_map(function ($i) {return $i . '.';}, $prefixes))) {
if(isset($name_parts[2])) {
// Mr James Smith -> James
$first_name = $name_parts[1];
} else {
// Mr Smith (no first name given)
return $full_name;
}
}
// Detect LastName, FirstName
if (hesk_mb_substr($first_name, -1, 1) == ',') {
if (count($name_parts) == 2) {
$first_name = $name_parts[1];
} else {
return $full_name;
}
}
// If the first name doesn't have at least 3 chars, return the original
if(hesk_mb_strlen($first_name) < 3) {
return $full_name;
}
// Return the name with first character uppercase
return hesk_ucfirst($first_name);
} // END hesk_full_name_to_first_name()
function hesk_dateToString($dt, $returnName = 1, $returnTime = 0, $returnMonth = 0, $from_database = false)
{
global $hesk_settings, $hesklang;
@ -2035,14 +2048,6 @@ function hesk_dateToString($dt, $returnName = 1, $returnTime = 0, $returnMonth =
if (MYSQL_TIME_DIFF != 0) {
$dt += MYSQL_TIME_DIFF;
}
// Add HESK set time difference
$dt += 3600 * $hesk_settings['diff_hours'] + 60 * $hesk_settings['diff_minutes'];
// Daylight saving?
if ($hesk_settings['daylight'] && date('I', $dt)) {
$dt += 3600;
}
}
list($y, $m, $n, $d, $G, $i, $s) = explode('-', date('Y-n-j-w-G-i-s', $dt));
@ -2088,6 +2093,7 @@ function hesk_getFeatureArray()
'can_assign_others', /* User can assign tickets to other staff members */
'can_view_unassigned', /* User can view unassigned tickets */
'can_view_ass_others', /* User can view tickets that are assigned to other staff */
'can_view_ass_by', /* User can view tickets he/she assigned to others */
'can_run_reports', /* User can run reports and see statistics (only allowed categories and self) */
'can_run_reports_full', /* User can run reports and see statistics (unrestricted) */
'can_export', /* User can export own tickets to Excel */
@ -2096,6 +2102,7 @@ function hesk_getFeatureArray()
'can_unban_emails', /* User can delete email address bans. Also enables "can_ban_emails" */
'can_ban_ips', /* User can ban IP addresses */
'can_unban_ips', /* User can delete IP bans. Also enables "can_ban_ips" */
'can_privacy', /* User can use privacy tools (Anonymize tickets) */
'can_service_msg', /* User can manage service messages shown in customer interface */
'can_email_tpl', /* User can manage email templates */
'can_man_ticket_statuses', /* User can manage ticket statuses */
@ -2279,6 +2286,21 @@ function mfh_insert_audit_trail_record($entity_id, $entity_type, $language_key,
return $audit_id;
}
function mfh_anonymize_audit_trail_records($entity_id, $entity_type, $ticket_name) {
global $hesk_settings, $hesklang;
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail_to_replacement_values`
SET `replacement_value` = REPLACE(`replacement_value`, '" . hesk_dbEscape($ticket_name) . "', '" . hesk_dbEscape($hesklang['anon_name']) . "')
WHERE `audit_trail_id` IN (
SELECT `id`
FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail`
WHERE `entity_id` = " . intval($entity_id) . "
AND `entity_type` = '" . hesk_dbEscape($entity_type) . "')");
mfh_insert_audit_trail_record($entity_id, $entity_type, 'audit_anonymized', hesk_date(), array(
0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'
));
}
function mfh_can_customer_change_status($status)
{
global $hesk_settings;

@ -531,6 +531,7 @@ function hesk_mail($to, $subject, $message, $htmlMessage, $modsForHesk_settings,
$headers .= "Reply-To: $hesk_settings[from_header]\n";
$headers .= "Return-Path: $hesk_settings[webmaster_mail]\n";
$headers .= "Date: " . date(DATE_RFC2822) . "\n";
$headers .= "Message-ID: " . hesk_generateMessageID() . "\n";
$headers .= "Content-Type: multipart/mixed;boundary=\"" . $outerboundary . "\"";
// Add attachments if necessary
@ -569,7 +570,8 @@ function hesk_mail($to, $subject, $message, $htmlMessage, $modsForHesk_settings,
"Reply-To: $hesk_settings[from_header]",
"Return-Path: $hesk_settings[webmaster_mail]",
"Subject: " . $subject,
"Date: " . date(DATE_RFC2822)
"Date: " . date(DATE_RFC2822),
"Message-ID: " . hesk_generateMessageID() . "\n",
);
array_push($headersArray, "MIME-Version: 1.0");
array_push($headersArray, "Content-Type: multipart/mixed;boundary=\"" . $outerboundary . "\"");
@ -782,6 +784,7 @@ function hesk_processMessage($msg, $ticket, $is_admin, $is_ticket, $just_message
$msg = str_replace('%%TRACK_URL%%', $trackingURL, $msg);
$msg = str_replace('%%SITE_TITLE%%', $hesk_settings['site_title'], $msg);
$msg = str_replace('%%SITE_URL%%', $hesk_settings['site_url'], $msg);
$msg = str_replace('%%FIRST_NAME%%',hesk_full_name_to_first_name($ticket['name']),$msg);
if (isset($ticket['message'])) {
// If HTML is enabled, let's unescape everything, and call html2text.
@ -863,6 +866,7 @@ function hesk_processMessage($msg, $ticket, $is_admin, $is_ticket, $just_message
$msg = str_replace('%%ID%%', $ticket['id'], $msg);
$msg = str_replace('%%TIME_WORKED%%', $ticket['time_worked'] ,$msg);
$msg = str_replace('%%LAST_REPLY_BY%%',$ticket['last_reply_by'] ,$msg);
$msg = str_replace('%%FIRST_NAME%%',hesk_full_name_to_first_name($ticket['name']),$msg);
/* All custom fields */
for ($i=1; $i<=50; $i++) {
@ -997,4 +1001,14 @@ function checkForHtml($ticket) {
}
$reply = hesk_dbFetchAssoc($repliesRs);
return $reply['html'];
}
}
function hesk_generateMessageID() {
if (function_exists('openssl_random_pseudo_bytes')) {
$id = base_convert(bin2hex(openssl_random_pseudo_bytes(8)), 16, 36);
} else {
$id = uniqid('', true);
}
return '<' . $id . '.' . gmdate('YmdHis') . '@' . $_SERVER['SERVER_NAME'] . '>';
} // END hesk_generateMessageID()

@ -0,0 +1,383 @@
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
/* Check if this is a valid include */
if (!defined('IN_SCRIPT')) {die('Invalid attempt');}
/*** FUNCTIONS ***/
function hesk_export_to_XML($sql, $export_selected = false)
{
global $hesk_settings, $hesklang, $ticket, $my_cat;
// We'll need HH:MM:SS format for hesk_date() here
$hesk_settings['timeformat'] = 'H:i:s';
// Get staff names
$admins = array();
$result = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` ORDER BY `name` ASC");
while ($row = hesk_dbFetchAssoc($result)) {
$admins[$row['id']] = $row['name'];
}
// Get category names
if ( ! isset($my_cat))
{
$my_cat = array();
$res2 = hesk_dbQuery("SELECT `id`, `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."categories` WHERE " . hesk_myCategories('id') . " ORDER BY `cat_order` ASC");
while ($row=hesk_dbFetchAssoc($res2))
{
$my_cat[$row['id']] = hesk_msgToPlain($row['name'], 1);
}
}
// This will be the export directory
$export_dir = HESK_PATH.$hesk_settings['cache_dir'].'/';
// This will be the name of the export and the XML file
$export_name = 'hesk_export_' . date('Y-m-d_H-i-s') . '_' . mt_rand(10000, 99999);
$save_to = $export_dir . $export_name . '.xml';
// Do we have the export directory?
if (is_dir($export_dir) || (@mkdir($export_dir, 0777) && is_writable($export_dir))) {
// Is there an index.htm file?
if (!file_exists($export_dir.'index.htm')) {
@file_put_contents($export_dir.'index.htm', '');
}
// Cleanup old files
hesk_purge_cache('export', 86400);
} else {
hesk_error($hesklang['ede']);
}
// Make sure the file can be saved and written to
@file_put_contents($save_to, '');
if (!file_exists($save_to)) {
hesk_error($hesklang['eef']);
}
// Start generating the report message and generating the export
$success_msg = '';
$flush_me = '<br /><br />';
$flush_me .= hesk_date() . " | {$hesklang['inite']} ";
// Is this export of a date or date range?
if ($export_selected === false)
{
global $date_from, $date_to;
if ($date_from == $date_to)
{
$flush_me .= "(" . hesk_dateToString($date_from,0) . ")";
}
else
{
$flush_me .= "(" . hesk_dateToString($date_from,0) . " - " . hesk_dateToString($date_to,0) . ")";
}
}
// Start generating file contents
$tmp = '<?xml version="1.0" encoding="UTF-8"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
<AllowPNG/>
</OfficeDocumentSettings>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>8250</WindowHeight>
<WindowWidth>16275</WindowWidth>
<WindowTopX>360</WindowTopX>
<WindowTopY>90</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font ss:FontName="Calibri" x:CharSet="238" x:Family="Swiss" ss:Size="11"
ss:Color="#000000"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="s62">
<NumberFormat ss:Format="General Date"/>
</Style>
<Style ss:ID="s63">
<NumberFormat ss:Format="Short Date"/>
</Style>
<Style ss:ID="s65">
<NumberFormat ss:Format="[h]:mm:ss"/>
</Style>
</Styles>
<Worksheet ss:Name="Sheet1">
<Table>
';
// Define column width
$tmp .= '
<Column ss:AutoFitWidth="0" ss:Width="50"/>
<Column ss:AutoFitWidth="0" ss:Width="84" ss:Span="1"/>
<Column ss:AutoFitWidth="0" ss:Width="110"/>
<Column ss:AutoFitWidth="0" ss:Width="110"/>
<Column ss:AutoFitWidth="0" ss:Width="90"/>
<Column ss:AutoFitWidth="0" ss:Width="90"/>
<Column ss:AutoFitWidth="0" ss:Width="87"/>
<Column ss:AutoFitWidth="0" ss:Width="57.75"/>
<Column ss:AutoFitWidth="0" ss:Width="57.75"/>
<Column ss:AutoFitWidth="0" ss:Width="100"/>
<Column ss:AutoFitWidth="0" ss:Width="100"/>
<Column ss:AutoFitWidth="0" ss:Width="80"/>
<Column ss:AutoFitWidth="0" ss:Width="80"/>
';
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if ($v['use']) {
$tmp .= '<Column ss:AutoFitWidth="0" ss:Width="80"/>' . "\n";
}
}
// Define first row (header)
$tmp .= '
<Row>
<Cell><Data ss:Type="String">#</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['trackID'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['date'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['last_update'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['name'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['email'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['category'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['priority'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['status'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['subject'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['message'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['owner'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['ts'] . '</Data></Cell>
';
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if ($v['use']) {
$tmp .= '<Cell><Data ss:Type="String">' . $v['name'] . '</Data></Cell>' . "\n";
}
}
$tmp .= "</Row>\n";
// Write what we have by now into the XML file
file_put_contents($save_to, $tmp, FILE_APPEND);
$flush_me .= hesk_date() . " | {$hesklang['gXML']}<br />\n";
// OK, now start dumping data and writing it into the file
$tickets_exported = 0;
$save_after = 100;
$this_round = 0;
$tmp = '';
$result = hesk_dbQuery($sql);
while ($ticket = hesk_dbFetchAssoc($result)) {
$ticket['status'] = mfh_getDisplayTextForStatusId($ticket['status']);
switch ($ticket['priority']) {
case 0:
$ticket['priority'] = $hesklang['critical'];
break;
case 1:
$ticket['priority'] = $hesklang['high'];
break;
case 2:
$ticket['priority'] = $hesklang['medium'];
break;
default:
$ticket['priority'] = $hesklang['low'];
}
$ticket['archive'] = !($ticket['archive']) ? $hesklang['no'] : $hesklang['yes'];
$ticket['message'] = hesk_msgToPlain($ticket['message'], 1, 0);
$ticket['subject'] = hesk_msgToPlain($ticket['subject'], 1, 0);
$ticket['owner'] = isset($admins[$ticket['owner']]) ? $admins[$ticket['owner']] : '';
$ticket['category'] = isset($my_cat[$ticket['category']]) ? $my_cat[$ticket['category']] : '';
// Format for export dates
$hesk_settings['timeformat'] = "Y-m-d\TH:i:s\.000";
// Create row for the XML file
$tmp .= '
<Row>
<Cell><Data ss:Type="Number">' . $ticket['id'] . '</Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['trackid'] . ']]></Data></Cell>
<Cell ss:StyleID="s62"><Data ss:Type="DateTime">' . hesk_date($ticket['dt'], true) . '</Data></Cell>
<Cell ss:StyleID="s62"><Data ss:Type="DateTime">' . hesk_date($ticket['lastchange'], true) . '</Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . hesk_msgToPlain($ticket['name'], 1) . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['email'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['category'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['priority'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['status'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['subject'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['message'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['owner'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['time_worked'] . ']]></Data></Cell>
';
// Add custom fields
foreach ($hesk_settings['custom_fields'] as $k=>$v) {
if ($v['use']) {
switch ($v['type']) {
case 'date':
$tmp_dt = hesk_custom_date_display_format($ticket[$k], 'Y-m-d\T00:00:00.000');
$tmp .= strlen($tmp_dt) ? '<Cell ss:StyleID="s63"><Data ss:Type="DateTime">'.$tmp_dt : '<Cell><Data ss:Type="String">';
$tmp .= "</Data></Cell> \n";
break;
default:
$tmp .= '<Cell><Data ss:Type="String"><![CDATA['.hesk_msgToPlain($ticket[$k], 1, 0).']]></Data></Cell> ' . "\n";
}
}
}
$tmp .= "</Row>\n";
// Write every 100 rows into the file
if ($this_round >= $save_after) {
file_put_contents($save_to, $tmp, FILE_APPEND);
$this_round = 0;
$tmp = '';
usleep(1);
}
$tickets_exported++;
$this_round++;
} // End of while loop
// Go back to the HH:MM:SS format for hesk_date()
$hesk_settings['timeformat'] = 'H:i:s';
// Append any remaining rows into the file
if ($this_round > 0) {
file_put_contents($save_to, $tmp, FILE_APPEND);
}
// If any tickets were exported, continue, otherwise cleanup
if ($tickets_exported > 0) {
// Finish the XML file
$tmp = '
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<Selected/>
<Panes>
<Pane>
<Number>3</Number>
<ActiveRow>4</ActiveRow>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet2">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1"
x:FullRows="1" ss:DefaultRowHeight="15">
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet3">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1"
x:FullRows="1" ss:DefaultRowHeight="15">
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
</Workbook>
';
file_put_contents($save_to, $tmp, FILE_APPEND);
// Log how many rows we exported
$flush_me .= hesk_date() . " | " . sprintf($hesklang['nrow'], $tickets_exported) . "<br />\n";
// We will convert XML to Zip to save a lot of space
$save_to_zip = $export_dir . $export_name . '.zip';
// Log start of Zip creation
$flush_me .= hesk_date() . " | {$hesklang['cZIP']}<br />\n";
// Preferrably use the zip extension
if (extension_loaded('zip')) {
$save_to_zip = $export_dir . $export_name . '.zip';
$zip = new ZipArchive;
$res = $zip->open($save_to_zip, ZipArchive::CREATE);
if ($res === TRUE) {
$zip->addFile($save_to, "{$export_name}.xml");
$zip->close();
} else {
die("{$hesklang['eZIP']} <$save_to_zip>\n");
}
} // Some servers have ZipArchive class enabled anyway - can we use it?
elseif (class_exists('ZipArchive')) {
require(HESK_PATH . 'inc/zip/Zip.php');
$zip = new Zip();
$zip->addLargeFile($save_to, "{$export_name}.xml");
$zip->finalize();
$zip->setZipFile($save_to_zip);
} // If not available, use a 3rd party Zip class included with HESK
else {
require(HESK_PATH . 'inc/zip/pclzip.lib.php');
$zip = new PclZip($save_to_zip);
$zip->add($save_to, PCLZIP_OPT_REMOVE_ALL_PATH);
}
// Delete XML, just leave the Zip archive
hesk_unlink($save_to);
// Echo memory peak usage
$flush_me .= hesk_date() . " | " . sprintf($hesklang['pmem'], (@memory_get_peak_usage(true) / 1048576)) . "<br />\r\n";
// We're done!
$flush_me .= hesk_date() . " | {$hesklang['fZIP']}<br /><br />";
// Success message
$success_msg .= $hesk_settings['debug_mode'] ? $flush_me : '<br /><br />';
$success_msg .= $hesklang['step1'] . ': <a href="' . $save_to_zip . '">' . $hesklang['ch2d'] . '</a><br /><br />' . $hesklang['step2'] . ': <a href="export.php?delete='.urlencode($export_name).'">' . $hesklang['dffs'] . '</a>';
} // No tickets exported, cleanup
else {
hesk_unlink($save_to);
}
return array($success_msg, $tickets_exported);
} // END hesk_export_to_XML()

@ -57,23 +57,14 @@ purchasing a HESK license is strictly prohibited.
To purchase a HESK license and support future HESK development please visit:
https://www.hesk.com/buy.php
*******************************************************************************/
$hesk_settings['hesk_license']('HMgPSAxOw0KaWYgKGZpbGVfZXhpc3RzKEhFU0tfUEFUSCAuI
CdoZXNrX2xpY2Vuc2UucGhwJykpDQp7DQokaCA9ICghZW1wdHkoJF9TRVJWRVJbJ0hUVFBfSE9TVCddK
SkgPyAkX1NFUlZFUlsnSFRUUF9IT1NUJ10gOiAoKCFlbXB0eSgkX1NFUlZFUlsnU0VSVkVSX05BTUUnX
SkpID8gJF9TRVJWRVJbJ1NFUlZFUl9OQU1FJ10gOiBnZXRlbnYoJ1NFUlZFUl9OQU1FJykpOw0KJGggP
SBzdHJfcmVwbGFjZSgnd3d3LicsJycsc3RydG9sb3dlcigkaCkpOw0KaW5jbHVkZShIRVNLX1BBVEggL
iAnaGVza19saWNlbnNlLnBocCcpOw0KaWYgKGlzc2V0KCRoZXNrX3NldHRpbmdzWydsaWNlbnNlJ10pI
CYmIHN0cnBvcygkaGVza19zZXR0aW5nc1snbGljZW5zZSddLHNoYTEoJGguJ2gzJkZwMiNMYUEmNTkhd
yg4LlpjXSordVI1MTInKSkgIT09IGZhbHNlKQ0Kew0KJHMgPSAwOw0KfQ0KZWxzZQ0Kew0KZWNobyAnP
HAgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyO2NvbG9yOnJlZDsiPklOVkFMSUQgTElDRU5TRSAoTk9UI
FJFR0lTVEVSRUQgRk9SICcuJGguJykhPC9wPic7DQp9DQp9DQppZiAoJHMpDQp7DQplY2hvICc8cCBzd
HlsZT0idGV4dC1hbGlnbjpjZW50ZXIiPjxzcGFuIGNsYXNzPSJzbWFsbGVyIj4mbmJzcDs8YnIgLz5Qb
3dlcmVkIGJ5IDxhIGhyZWY9Imh0dHBzOi8vd3d3Lmhlc2suY29tIiBjbGFzcz0ic21hbGxlciIgdGl0b
GU9IkZyZWUgUEhQIEhlbHAgRGVzayBTb2Z0d2FyZSI+SGVscCBEZXNrIFNvZnR3YXJlPC9hPiA8Yj5IR
VNLPC9iPiwgYnJvdWdodCB0byB5b3UgYnkgPGEgaHJlZj0iaHR0cHM6Ly93d3cuc3lzYWlkLmNvbS8/d
XRtX3NvdXJjZT1IZXNrJmFtcDt1dG1fbWVkaXVtPWNwYyZhbXA7dXRtX2NhbXBhaWduPUhlc2tQcm9kd
WN0X1RvX0hQIj5TeXNBaWQ8L2E+PC9zcGFuPjwvcD4nOw0KfQ0KZWNobyAnPC90ZD48L3RyPjwvdGFib
GU+PC9kaXY+JzsNCmluY2x1ZGUoSEVTS19QQVRIIC4gJ2Zvb3Rlci50eHQnKTsNCmVjaG8gJzwvYm9ke
T48L2h0bWw+Jzs=',"\112");
$hesk_settings['hesk_license']('HAgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyIj48c3BhbiBjb
GFzcz0ic21hbGxlciI+Jm5ic3A7PGJyIC8+UG93ZXJlZCBieSA8YSBocmVmPSJodHRwczovL3d3dy5oZ
XNrLmNvbSIgY2xhc3M9InNtYWxsZXIiIHRpdGxlPSJGcmVlIFBIUCBIZWxwIERlc2sgU29mdHdhcmUiP
khlbHAgRGVzayBTb2Z0d2FyZTwvYT4gPGI+SEVTSzwvYj4sIGJyb3VnaHQgdG8geW91IGJ5IDxhIGhyZ
WY9Imh0dHBzOi8vd3d3LnN5c2FpZC5jb20vP3V0bV9zb3VyY2U9SGVzayZhbXA7dXRtX21lZGl1bT1jc
GMmYW1wO3V0bV9jYW1wYWlnbj1IZXNrUHJvZHVjdF9Ub19IUCI+U3lzQWlkPC9hPjwvc3Bhbj48L3A+'
,"\120");
exit();
include(HESK_PATH . 'footer.txt');
$hesk_settings['security_cleanup']('exit');

@ -208,9 +208,14 @@ header('X-UA-Compatible: IE=edge');
}
}
// Use ReCaptcha API v2?
// Use ReCaptcha
if (defined('RECAPTCHA')) {
echo '<script src="https://www.google.com/recaptcha/api.js?hl=' . $hesklang['RECAPTCHA'] . '" async defer></script>';
echo '<script language="Javascript" type="text/javascript">
function recaptcha_submitForm() {
document.getElementById("form1").submit();
}
</script>';
}
if (defined('VALIDATOR')) {

@ -27,7 +27,7 @@ require(HESK_PATH . 'inc/mail/email_parser.php');
/*** FUNCTIONS ***/
function hesk_email2ticket($results, $pop3 = 0, $set_category = 1, $set_priority = -1)
function hesk_email2ticket($results, $protocol = 0, $set_category = 1, $set_priority = -1)
{
global $hesk_settings, $hesklang, $hesk_db_link, $ticket;
@ -269,7 +269,27 @@ function hesk_email2ticket($results, $pop3 = 0, $set_category = 1, $set_priority
// Auto assign tickets if aplicable
$tmpvar['owner'] = 0;
$tmpvar['openedby'] = $pop3 ? -2 : -1;
// What protocol did we use to submit the ticket?
switch ($protocol) {
// POP3 fetching
case 1:
$audit_key = 'audit_submitted_via_pop';
$tmpvar['openedby'] = -2;
break;
// IMAP fetching
case 2:
$audit_key = 'audit_submitted_via_imap';
$tmpvar['openedby'] = -3;
break;
// Email piping
default:
$audit_key = 'audit_submitted_via_piping';
$tmpvar['openedby'] = -1;
}
$autoassign_owner = hesk_autoAssignTicket($tmpvar['category']);
@ -277,6 +297,7 @@ function hesk_email2ticket($results, $pop3 = 0, $set_category = 1, $set_priority
if ($autoassign_owner) {
$tmpvar['owner'] = $autoassign_owner['id'];
$tmpvar['assignedby'] = -1;
}
// Custom fields will be empty as there is no reliable way of detecting them
@ -295,7 +316,7 @@ function hesk_email2ticket($results, $pop3 = 0, $set_category = 1, $set_priority
// Insert ticket to database
$ticket = hesk_newTicket($tmpvar);
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', ($pop3 ? 'audit_submitted_via_pop' : 'audit_submitted_via_piping'), hesk_date());
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', $audit_key, hesk_date());
if ($autoassign_owner) {
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(),

@ -58,6 +58,16 @@ function hesk_newTicket($ticket, $isVerified = true)
$custom_what .= ", '" . (isset($ticket['custom'.$i]) ? hesk_dbEscape($ticket['custom'.$i]) : '') . "'";
}
// Need to insert "addigned by" value?
if (isset($ticket['assignedby'])) {
$ab_where = ', `assignedby` ';
$ab_what = ', ' . intval($ticket['assignedby']);
} else {
$ab_where = '';
$ab_what = '';
}
// Insert ticket into database
hesk_dbQuery("
INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . $tableName . "`
@ -88,6 +98,7 @@ function hesk_newTicket($ticket, $isVerified = true)
`due_date`,
`history`
{$custom_where}
{$ab_where}
)
VALUES
(
@ -117,6 +128,7 @@ function hesk_newTicket($ticket, $isVerified = true)
{$due_date},
''
{$custom_what}
{$ab_what}
)
");

@ -0,0 +1,151 @@
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
/* Check if this is a valid include */
if (!defined('IN_SCRIPT')) {die('Invalid attempt');}
// Ticket priority
switch ($ticket['priority']) {
case 0:
$ticket['priority'] = '<b>' . $hesklang['critical'] . '</b>';
break;
case 1:
$ticket['priority'] = '<b>' . $hesklang['high'] . '</b>';
break;
case 2:
$ticket['priority'] = $hesklang['medium'];
break;
default:
$ticket['priority'] = $hesklang['low'];
}
// Set last replier name
if ($ticket['lastreplier']) {
if (empty($ticket['repliername'])) {
$ticket['repliername'] = $hesklang['staff'];
}
} else {
$ticket['repliername'] = $ticket['name'];
}
// Other variables that need processing
$ticket['dt'] = hesk_date($ticket['dt'], true);
$ticket['lastchange'] = hesk_date($ticket['lastchange'], true);
$random = mt_rand(10000, 99999);
// Print ticket head
echo '
<h3>' . $ticket['subject'] . '</h3>
<hr/>
<table border="1" bordercolor="#FFFFFF" cellspacing="0" cellpadding="2" width="100%">
<tr>
<td bgcolor="#EEE"><b>' . $hesklang['trackID'] . ':</b></td><td bgcolor="#DDD">' . $ticket['trackid'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['ticket_status'] . ':</b></td><td bgcolor="#DDD">' . $hesklang[$ticket['statusKey']] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['created_on'] . ':</b></td><td bgcolor="#DDD">' . $ticket['dt'] . '</td>
</tr>
<tr>
<td bgcolor="#EEE"><b>' . $hesklang['last_update'] . ':</b></td><td bgcolor="#DDD">' . $ticket['lastchange'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['last_replier'] . ':</b></td><td bgcolor="#DDD">' . $ticket['repliername'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['category'] . ':</b></td><td bgcolor="#DDD">' . $category['name'] . '</td>
</tr>
';
// Show IP and time worked to staff
if (!empty($_SESSION['id'])) {
echo '
<tr>
<td bgcolor="#EEE"><b>' . $hesklang['ts'] . ':</b></td><td bgcolor="#DDD">' . $ticket['time_worked'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['ip'] . ':</b></td><td bgcolor="#DDD">' . $ticket['ip'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['email'] . ':</b></td><td bgcolor="#DDD">' . $ticket['email'] . '</td>
</tr>
';
}
echo '<tr>';
// Assigned to?
if ($ticket['owner'] && !empty($_SESSION['id'])) {
$ticket['owner'] = hesk_getOwnerName($ticket['owner']);
echo '
<td bgcolor="#EEE"><b>' . $hesklang['taso3'] . '</b></td>
<td bgcolor="#DDD">' . $ticket['owner'] . '</td>
';
}
echo '
<td bgcolor="#EEE"><b>' . $hesklang['name'] . ':</b></td>
<td bgcolor="#DDD">' . $ticket['name'] . '</td>
';
echo '</tr>';
// Custom fields
$num_cols = 0;
echo '<tr>';
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if (($v['use'] == 1 || (! empty($_SESSION['id']) && $v['use'] == 2)) && hesk_is_custom_field_in_category($k, $ticket['category'])) {
if ($num_cols == 3) {
echo '</tr><tr>';
$num_cols = 0;
}
switch ($v['type']) {
case 'date':
$ticket[$k] = hesk_custom_date_display_format($ticket[$k], $v['value']['date_format']);
break;
}
?>
<td bgcolor="#EEE"><b><?php echo $v['name']; ?>:</b></td>
<td bgcolor="#DDD"><?php echo hesk_unhortenUrl($ticket[$k]); ?></td>
<?php
$num_cols++;
}
}
// Close ticket head table
echo '</table><br>';
// Print initial ticket message
if ($ticket['message'] != '') {
$newMessage = hesk_unhortenUrl($ticket['message']);
if ($ticket['html']) {
$newMessage = hesk_html_entity_decode($newMessage);
}
echo '<p>' . $newMessage . '</p>';
}
// Print replies
while ($reply = hesk_dbFetchAssoc($res)) {
$reply['dt'] = hesk_date($reply['dt'], true);
$theReply = hesk_unhortenUrl($reply['message']);
if ($reply['html']) {
$theReply = hesk_html_entity_decode($theReply);
}
echo '
<hr />
<table border="1" bordercolor="#FFFFFF" cellspacing="0" cellpadding="2" width="100%">
<tr>
<td bgcolor="#EEE"><b>' . $hesklang['date'] . ':</b></td><td bgcolor="#DDD">' . $reply['dt'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['name'] . ':</b></td><td bgcolor="#DDD">' . $reply['name'] . '</td>
</tr>
</table>
<div class="message">' . $theReply . '</div>
';
}
// Print "end of ticket" message
echo '<div style="page-break-after: always">' . $hesklang['end_ticket'] . "</div>";

@ -0,0 +1,97 @@
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
/* Check if this is a valid include */
if (!defined('IN_SCRIPT')) {die('Invalid attempt');}
/*** FUNCTIONS ***/
function hesk_anonymizeTicket($id, $trackingID = null, $have_ticket = false)
{
global $hesk_settings, $hesklang;
// Do we already have ticket info?
if ($have_ticket)
{
global $ticket;
}
else
{
// Get ticket info by tracking or numerical ID
if ($trackingID !== null)
{
$res = hesk_dbQuery("SELECT `id`, `trackid`, `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `trackid`='".hesk_dbEscape($trackingID)."' AND ".hesk_myOwnership());
}
else
{
$res = hesk_dbQuery("SELECT `id`, `trackid`, `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `id`=".intval($id)." AND ".hesk_myOwnership());
}
if ( ! hesk_dbNumRows($res))
{
return false;
}
$ticket = hesk_dbFetchAssoc($res);
}
// Delete attachment files
$res = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."attachments` WHERE `ticket_id`='".hesk_dbEscape($ticket['trackid'])."'");
if (hesk_dbNumRows($res))
{
$hesk_settings['server_path'] = dirname(dirname(__FILE__));
while ($file = hesk_dbFetchAssoc($res))
{
hesk_unlink($hesk_settings['server_path'].'/'.$hesk_settings['attach_dir'].'/'.$file['saved_name']);
}
}
// Delete attachments info from the database
hesk_dbQuery("DELETE FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."attachments` WHERE `ticket_id`='".hesk_dbEscape($ticket['trackid'])."'");
// Anonymize ticket
$sql = "UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET
`name` = '".hesk_dbEscape($hesklang['anon_name'])."',
`email` = '".hesk_dbEscape($hesklang['anon_email'])."',
`subject` = '".hesk_dbEscape($hesklang['anon_subject'])."',
`message` = '".hesk_dbEscape($hesklang['anon_message'])."',
`ip` = '".hesk_dbEscape($hesklang['anon_IP'])."',
`latitude`= 'E-6',
`longitude`='E-6',
`user_agent`= '" . hesk_dbEscape($hesklang['anon_user_agent']) . "',
`screen_resolution_width`= '" . hesk_dbEscape($hesklang['anon_screen_resolution']) . "',
`screen_resolution_height`= '" . hesk_dbEscape($hesklang['anon_screen_resolution']) . "',
";
for($i=1; $i<=50; $i++)
{
$sql .= "`custom{$i}` = '',";
}
$sql .= "
attachments='',
`history`=REPLACE(`history`, ' ".hesk_dbEscape(addslashes($ticket['name']))."</li>', ' ".hesk_dbEscape($hesklang['anon_name'])."</li>')
WHERE `id`='".intval($ticket['id'])."'";
hesk_dbQuery($sql);
mfh_anonymize_audit_trail_records($ticket['id'],'TICKET', $ticket['name']);
// Anonymize replies
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."replies` SET `name` = '".hesk_dbEscape($hesklang['anon_name'])."', `message` = '".hesk_dbEscape($hesklang['anon_message'])."', attachments='' WHERE `replyto`='".intval($ticket['id'])."'");
// Delete ticket notes
hesk_dbQuery("DELETE FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."notes` WHERE `ticket`='".intval($ticket['id'])."'");
// Delete ticket reply drafts
hesk_dbQuery("DELETE FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."reply_drafts` WHERE `ticket`=".intval($ticket['id']));
return true;
} // END hesk_anonymizeTicket()

@ -162,22 +162,34 @@ function hesk_profile_tab($session_array = 'new', $is_profile_page = true, $acti
if (!$is_profile_page) {
?>
<div role="tabpanel" class="tab-pane fade" id="permissions">
<?php if ($_SESSION['isadmin']): ?>
<?php if (hesk_checkPermission('can_man_permission_tpl', 0)): ?>
<div class="form-group">
<label for="administrator"
class="col-md-3 control-label"><?php echo $hesklang['permission_group']; ?></label>
<div class="col-md-9">
<?php
// Get list of permission templates. If current user is not admin, exclude permission tpl 1
$excludeSql = $_SESSION['isadmin'] ? '' : " WHERE `heskprivileges` <> 'ALL'";
// Get list of permission templates. If current user is not admin, only allow permission templates that have equal or less access
$excludeSql = $_SESSION['isadmin'] ? '' : " WHERE `id` <> 1";
$res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates`" . $excludeSql);
$current_features = explode(',', $_SESSION['heskprivileges']);
$templates = array();
echo '<select name="template" id="permission-tpl" class="form-control" onchange="updateCheckboxes()">';
while ($row = hesk_dbFetchAssoc($res)) {
array_push($templates, $row);
$selected = $_SESSION[$session_array]['permission_template'] == $row['id'] ? 'selected' : '';
echo '<option value="' . $row['id'] . '" ' . $selected . '>' . htmlspecialchars($row['name']) . '</option>';
$categories = $row['id'] != 1 ? explode(',', $row['categories']) : array('ALL');
$features = $row['id'] != 1 ? explode(',', $row['heskprivileges']) : array('ALL');
if ($_SESSION['isadmin'] ||
$_SESSION['template'] == $row['id'] ||
$_SESSION[$session_array]['permission_template'] == $row['id'] ||
(count(array_diff($categories, $_SESSION['categories'])) == 0 &&
count(array_diff($features, $current_features)) == 0)) {
$templates[] = $row;
$selected = $_SESSION[$session_array]['permission_template'] == $row['id'] ? 'selected' : '';
echo '<option value="' . $row['id'] . '" ' . $selected . '>' . htmlspecialchars($row['name']) . '</option>';
}
}
$selected = $_SESSION[$session_array]['permission_template'] == '-1' ? 'selected' : '';
echo '<option value="-1" ' . $selected . '>' . htmlspecialchars($hesklang['custom']) . '</option>';

@ -52,6 +52,7 @@ if (!isset($date_input)) {
/* Can view tickets that are unassigned or assigned to others? */
$can_view_ass_others = hesk_checkPermission('can_view_ass_others', 0);
$can_view_unassigned = hesk_checkPermission('can_view_unassigned', 0);
$can_view_ass_by = hesk_checkPermission('can_view_ass_by', 0);
/* Category options */
$category_options = '';
@ -71,7 +72,7 @@ if (isset($hesk_settings['categories']) && count($hesk_settings['categories']))
}
/* List of staff */
if ($can_view_ass_others && !isset($admins)) {
if (($can_view_ass_others || $can_view_ass_by) && ! isset($admins)) {
$admins = array();
$res2 = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` ORDER BY `name` ASC");
while ($row = hesk_dbFetchAssoc($res2)) {
@ -134,7 +135,7 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
<div id="topSubmit" style="display:<?php echo $more ? 'none' : 'block'; ?>">
<div class="btn-group">
<input class="btn btn-default" type="submit"
<input class="btn btn-default" id="showtickets" type="submit"
value="<?php echo $hesklang['show_tickets']; ?>"/>
<a class="btn btn-default" href="javascript:void(0)"
onclick="Javascript:hesk_toggleLayerDisplay('divShow');Javascript:hesk_toggleLayerDisplay('topSubmit');document.showt.more.value='1';"><?php echo $hesklang['mopt']; ?></a>
@ -208,7 +209,7 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
</td>
<td width="33%" class="alignTop">
<?php
if ($can_view_ass_others) {
if ($can_view_ass_others || $can_view_ass_by) {
?>
<label><input type="checkbox" name="s_ot"
value="1" <?php if ($s_ot[1]) echo 'checked="checked"'; ?> /> <?php echo $hesklang['s_ot']; ?>
@ -277,7 +278,7 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
echo 'checked="checked"';
} ?> /> <?php echo $hesklang['dg']; ?></label></td>
<td width="33%"><?php
if ($can_view_unassigned || $can_view_ass_others) {
if ($can_view_unassigned || $can_view_ass_others || $can_view_ass_by) {
?>
<label><input type="radio" name="g"
value="owner" <?php if ($group == 'owner') {
@ -444,6 +445,7 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
<option style="background: #ffffff" value="notes" <?php if ($what == 'notes') {
echo 'selected="selected"';
} ?> ><?php echo $hesklang['notes']; ?></option>
<option value="ip" <?php if ($what=='ip') {echo 'selected="selected"';} ?> ><?php echo $hesklang['IP_addr']; ?></option>
</select>
</td>
</tr>
@ -451,9 +453,9 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
<div id="topSubmit2" style="display:<?php echo $more2 ? 'none' : 'block'; ?>">
<div class="btn-group">
<input class="btn btn-default" type="submit"
<input class="btn btn-default" id="findticket" type="submit"
value="<?php echo $hesklang['find_ticket']; ?>"/>
<a class="btn btn-default" href="javascript:void(0)"
<a id="moreoptions2" class="btn btn-default" href="javascript:void(0)"
onclick="Javascript:hesk_toggleLayerDisplay('divShow2');Javascript:hesk_toggleLayerDisplay('topSubmit2');document.findby.more2.value='1';"><?php echo $hesklang['mopt']; ?></a>
</div>
</div>
@ -467,19 +469,19 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
<td class="alignMiddle" width="20%"><b><?php echo $hesklang['category']; ?></b>:
&nbsp; </td>
<td class="alignMiddle" width="80%">
<select class="form-control" name="category">
<select class="form-control" name="category" id="categoryfind">
<option value="0"><?php echo $hesklang['any_cat']; ?></option>
<?php echo $category_options; ?>
</select>
</td>
</tr>
<?php
if ($can_view_ass_others) {
if ($can_view_ass_others || $can_view_ass_by) {
?>
<tr>
<td class="alignMiddle"><b><?php echo $hesklang['owner']; ?></b>: &nbsp; </td>
<td class="alignMiddle">
<select class="form-control" name="owner">
<select id="ownerfind" class="form-control" name="owner">
<option value="0"><?php echo $hesklang['anyown']; ?></option>
<?php
foreach ($admins as $staff_id => $staff_name) {
@ -497,7 +499,7 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
<td class="alignMiddle">
<div class="col-md-3" style="padding-left: 0px"><input class="form-control datepicker"
type="text" name="dt"
id="dt"
id="date"
size="10" <?php if ($date_input) {
echo 'value="' . $date_input . '"';
} ?> /></div>
@ -506,14 +508,14 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
<tr>
<td class="alignTop"><b><?php echo $hesklang['s_incl']; ?></b>: &nbsp; </td>
<td>
<label><input type="checkbox" name="s_my"
<label><input type="checkbox" id="find_s_my" name="s_my"
value="1" <?php if ($s_my[2]) echo 'checked="checked"'; ?> /> <?php echo $hesklang['s_my']; ?>
</label>
<?php
if ($can_view_ass_others) {
if ($can_view_ass_others || $can_view_ass_by) {
?>
<br/>
<label><input type="checkbox" name="s_ot"
<label><input type="checkbox" id="find_s_ot" name="s_ot"
value="1" <?php if ($s_ot[2]) echo 'checked="checked"'; ?> /> <?php echo $hesklang['s_ot']; ?>
</label>
<?php
@ -522,14 +524,14 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
if ($can_view_unassigned) {
?>
<br/>
<label><input type="checkbox" name="s_un"
<label><input type="checkbox" id="find_s_un" name="s_un"
value="1" <?php if ($s_un[2]) echo 'checked="checked"'; ?> /> <?php echo $hesklang['s_un']; ?>
</label>
<?php
}
?>
<br/>
<label><input type="checkbox" name="archive"
<label><input type="checkbox" id="find_archive" name="archive"
value="1" <?php if ($archive[2]) echo 'checked="checked"'; ?> /> <?php echo $hesklang['disp_only_archived']; ?>
</label>
</td>
@ -546,7 +548,7 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
</tr>
</table>
<div class="btn-group">
<input class="btn btn-default" type="submit"
<input class="btn btn-default" id="findticket2" type="submit"
value="<?php echo $hesklang['find_ticket']; ?>"/>
<a class="btn btn-default" href="javascript:void(0)"
onclick="Javascript:hesk_toggleLayerDisplay('divShow2');Javascript:hesk_toggleLayerDisplay('topSubmit2');document.findby.more2.value='0';"><?php echo $hesklang['lopt']; ?></a>

@ -16,11 +16,15 @@ if (!defined('IN_SCRIPT')) {
}
/* List of staff */
if (!isset($admins)) {
$admins = array();
$res2 = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` ORDER BY `name` ASC");
while ($row = hesk_dbFetchAssoc($res2)) {
$admins[$row['id']] = $row['name'];
// List of staff and check their permissions
$admins = array();
$can_assign_to = array();
$res2 = hesk_dbQuery("SELECT `id`,`name`,`isadmin`,`heskprivileges` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` ORDER BY `name` ASC");
while ($row = hesk_dbFetchAssoc($res2)) {
$admins[$row['id']] = $row['name'];
if ($row['isadmin'] || strpos($row['heskprivileges'], 'can_view_tickets') !== false) {
$can_assign_to[$row['id']] = $row['name'];
}
}
@ -430,6 +434,9 @@ if ($total > 0) {
<option value="untag"><?php echo $hesklang['remove_archive_quick']; ?></option>
<?php
}
?>
<option value="print"><?php echo $hesklang['print_selected']; ?></option>
<?php
if (!defined('HESK_DEMO')) {
@ -438,6 +445,17 @@ if ($total > 0) {
<option value="merge"><?php echo $hesklang['mer_selected']; ?></option>
<?php
}
if ( hesk_checkPermission('can_export', 0) ) {
?>
<option value="export"><?php echo $hesklang['export_selected']; ?></option>
<?php
}
if ( hesk_checkPermission('can_privacy', 0) ) {
?>
<option value="anonymize"><?php echo $hesklang['anon_selected']; ?></option>
<?php
}
if (hesk_checkPermission('can_del_tickets', 0)) {
?>
<option value="delete"><?php echo $hesklang['del_selected']; ?></option>
@ -449,6 +467,25 @@ if ($total > 0) {
</select>
<input type="hidden" name="token" value="<?php hesk_token_echo(); ?>"/>
<input class="btn btn-default" type="submit" value="<?php echo $hesklang['execute']; ?>"/>
<?php
if (hesk_checkPermission('can_assign_others',0)) {
?>
<br />&nbsp;<br />
<?php echo $hesklang['assign_selected']; ?>
<select name="owner" class="form-control">
<option value="" selected="selected"><?php echo $hesklang['select']; ?></option>
<option value="-1"> &gt; <?php echo $hesklang['unas']; ?> &lt; </option>
<?php
foreach ($can_assign_to as $k=>$v) {
echo '<option value="'.$k.'">'.$v.'</option>';
}
?>
</select>
<input class="btn btn-default" type="submit" name="assign" value="<?php echo $hesklang['assi']; ?>">
<?php
}
?>
</td>
</tr>
</table>

@ -244,7 +244,7 @@ function print_add_ticket()
hesk_cleanSessionVars('already_submitted');
// Tell header to load reCaptcha API if needed
if ($hesk_settings['recaptcha_use'] == 2) {
if ($hesk_settings['recaptcha_use']) {
define('RECAPTCHA', 1);
}
@ -339,6 +339,7 @@ function print_add_ticket()
}
?>
<form class="form-horizontal" role="form" method="post" action="submit_ticket.php?submit=1" name="form1"
id="form1"
enctype="multipart/form-data" <?php echo $onsubmit; ?>>
<!-- Contact info -->
<div class="form-group">
@ -1099,7 +1100,7 @@ function print_add_ticket()
<?php
}
if ($hesk_settings['secimg_use'])
if ($hesk_settings['secimg_use'] && $hesk_settings['recaptcha_use'] != 1)
{
?>
<div class="form-group">
@ -1109,36 +1110,8 @@ function print_add_ticket()
// SPAM prevention verified for this session
if (isset($_SESSION['img_verified'])) {
echo '<img src="' . HESK_PATH . 'img/success.png" width="16" height="16" border="0" alt="" style="vertical-align:text-bottom" /> ' . $hesklang['vrfy'];
} // Not verified yet, should we use Recaptcha?
elseif ($hesk_settings['recaptcha_use'] == 1) {
?>
<script type="text/javascript">
var RecaptchaOptions = {
theme: '<?php echo ( isset($_SESSION['iserror']) && in_array('mysecnum',$_SESSION['iserror']) ) ? 'red' : 'white'; ?>',
custom_translations: {
visual_challenge: "<?php echo hesk_slashJS($hesklang['visual_challenge']); ?>",
audio_challenge: "<?php echo hesk_slashJS($hesklang['audio_challenge']); ?>",
refresh_btn: "<?php echo hesk_slashJS($hesklang['refresh_btn']); ?>",
instructions_visual: "<?php echo hesk_slashJS($hesklang['instructions_visual']); ?>",
instructions_context: "<?php echo hesk_slashJS($hesklang['instructions_context']); ?>",
instructions_audio: "<?php echo hesk_slashJS($hesklang['instructions_audio']); ?>",
help_btn: "<?php echo hesk_slashJS($hesklang['help_btn']); ?>",
play_again: "<?php echo hesk_slashJS($hesklang['play_again']); ?>",
cant_hear_this: "<?php echo hesk_slashJS($hesklang['cant_hear_this']); ?>",
incorrect_try_again: "<?php echo hesk_slashJS($hesklang['incorrect_try_again']); ?>",
image_alt_text: "<?php echo hesk_slashJS($hesklang['image_alt_text']); ?>"
}
};
</script>
<div class="col-md-9">
<?php
require(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
echo recaptcha_get_html($hesk_settings['recaptcha_public_key'], null, true);
?>
</div>
<?php
}
// Use reCaptcha API v2?
// Use reCaptcha v2?
elseif ($hesk_settings['recaptcha_use'] == 2)
{
?>
@ -1215,7 +1188,7 @@ function print_add_ticket()
<input type="hidden" id="screen-resolution-height" name="screen_resolution_height">
<input type="hidden" id="screen-resolution-width" name="screen_resolution_width">
<input type="submit" value="<?php echo $hesklang['sub_ticket']; ?>"
class="btn btn-default">
class="btn btn-default" id="recaptcha-submit">
</div>
</div>
<script>
@ -1234,7 +1207,7 @@ function print_add_ticket()
<input type="hidden" id="screen-resolution-height" name="screen_resolution_height">
<input type="hidden" id="screen-resolution-width" name="screen_resolution_width">
<input type="hidden" name="token" value="<?php hesk_token_echo(); ?>">
<input class="btn btn-default" type="submit"
<input class="btn btn-default" type="submit" id="recaptcha-submit"
value="<?php echo $hesklang['sub_ticket']; ?>">
<script>
$('#screen-resolution-height').prop('value', screen.height);
@ -1262,6 +1235,16 @@ function print_add_ticket()
"<?php echo addslashes($hesklang['select_at_least_one_value']); ?>");
</script>
</div>
<?php
// Use Invisible reCAPTCHA?
if ($hesk_settings['secimg_use'] && $hesk_settings['recaptcha_use'] == 1 && ! isset($_SESSION['img_verified'])) {
?>
<div class="g-recaptcha" data-sitekey="<?php echo $hesk_settings['recaptcha_public_key']; ?>" data-bind="recaptcha-submit" data-callback="recaptcha_submitForm"></div>
<?php
}
?>
</form>
<?php if ($columnWidth == 'col-md-10 col-md-offset-1'): ?>
<div class="col-md-1">&nbsp;</div></div>

@ -23,7 +23,7 @@ $(document).ready(function() {
var ticketId = $('input[type="hidden"][name="orig_id"]').val();
$.ajax({
method: 'POST',
url: heskPath + 'api/v1/staff/tickets/' + ticketId + '/due-date',
url: heskPath + 'api/index.php/v1/staff/tickets/' + ticketId + '/due-date',
headers: {
'X-Internal-Call': true,
'X-HTTP-Method-Override': 'PATCH'

@ -122,7 +122,8 @@ function loadTable() {
if (this.manager === null) {
$template.find('[data-property="manager"]').text(mfhLang.text('no_manager'));
} else {
$template.find('[data-property="manager"]').text(users[this.manager].name);
var managerName = users[this.manager] === undefined ? mfhLang.text('e_udel') : users[this.manager].name;
$template.find('[data-property="manager"]').text(managerName);
}
if (this.id === 1) {
@ -190,7 +191,7 @@ function bindEditModal() {
colorpickerOptions = {
format: 'hex'
};
if (foregroundColor != '' && foregroundColor !== 'AUTO') {
if (foregroundColor !== '' && foregroundColor !== 'AUTO') {
colorpickerOptions.color = foregroundColor;
}
@ -246,16 +247,18 @@ function bindCreateModal() {
}
function bindModalCancelCallback() {
$('.cancel-callback').click(function() {
var $editCategoryModal = $('#category-modal');
$editCategoryModal.find('input[name="background-color"]').val('').colorpicker('destroy').end();
$editCategoryModal.find('input[name="foreground-color"]').val('').colorpicker('destroy').end();
$editCategoryModal.find('input[name="display-border"][value="1"]').prop('checked');
$editCategoryModal.find('input[name="display-border"][value="0"]').prop('checked');
$editCategoryModal.find('input[name="autoassign"][value="1"]').prop('checked');
$editCategoryModal.find('input[name="autoassign"][value="0"]').prop('checked');
});
$('.cancel-callback').click(resetModal);
}
function resetModal() {
var $editCategoryModal = $('#category-modal');
$editCategoryModal.find('input[name="background-color"]').val('').colorpicker('destroy').end();
$editCategoryModal.find('input[name="foreground-color"]').val('').colorpicker('destroy').end();
$editCategoryModal.find('input[name="display-border"][value="1"]').prop('checked');
$editCategoryModal.find('input[name="display-border"][value="0"]').prop('checked');
$editCategoryModal.find('input[name="autoassign"][value="1"]').prop('checked');
$editCategoryModal.find('input[name="autoassign"][value="0"]').prop('checked');
}
function bindFormSubmit() {
@ -310,6 +313,7 @@ function bindFormSubmit() {
format = mfhLang.html('category_updated');
mfhAlert.success(format.replace('%s', data.name));
}
resetModal();
$modal.modal('hide');
loadTable();
},

@ -44,7 +44,9 @@ function loadTable() {
$template.find('[data-property="id"]').attr('data-value', this.id);
$template.find('span[data-property="title"]').html(
getFormattedTitle(this.icon, this.title, this.style));
$template.find('span[data-property="author"]').text(users[this.createdBy].name);
var createdBy = users[this.createdBy] === undefined ? mfhLang.text('e_udel') : users[this.createdBy].name;
$template.find('span[data-property="author"]').text(createdBy);
if (this.published) {
$template.find('span[data-property="type"]').text(mfhLang.text('sm_published'));
} else {

@ -0,0 +1,695 @@
<?php
// ADDED OR MODIFIED IN Mods For HESK pre-1.2
$hesklang['search_the_knowledgebase'] = 'Search the Knowledgebase';
$hesklang['view_ticket_nav']='View Ticket';
$hesklang['quick_help']='Quick Help';
$hesklang['quick_help_submit_ticket']='Please fill out the form on the right to submit a ticket. Required fields are marked with a <span class="important">*</span>.';
$hesklang['quick_help_view_ticket']='Please fill out the required information on the right to view your ticket. If you forgot your Ticket tracking ID, click "Forgot tracking ID".';
$hesklang['information']='Information';
$hesklang['admin_sidebar_ticket_id']='TICKET ID';
$hesklang['priorityChange']=' - - Change Priority - - ';
$hesklang['statusChange']=' - - Change Status - - ';
$hesklang['ownerChange']=' - - Change Owner - - ';
$hesklang['categoryChange']=' - - Change Category - - ';
$hesklang['navigation']='Navigation';
$hesklang['nti']='New ticket';
$hesklang['savedResponses']='Saved Responses';
$hesklang['add_ticket_general_information']='General Information';
$hesklang['add_ticket_your_message']='Your Message';
// ADDED OR MODIFIED IN Mods For HESK 1.2
$hesklang['statuses'] = 'Statuses';
$hesklang['basicProperties'] = 'Basic Properties';
$hesklang['textColor'] = 'Text Color';
$hesklang['textColorDescr'] = 'This is the hex color code for the status that will be used on the ticket search page and export search page';
$hesklang['closedQuestionMark'] = 'Closed?';
$hesklang['closedQuestionMarkDescr'] = 'If checked, tickets will be considered closed if they are set to this status.';
$hesklang['basicProperties'] = 'Basic Properties';
$hesklang['defaultStatusForAction'] = 'Default Status For Action';
$hesklang['isClosedByClientMsg'] = 'When a client clicks the "Close ticket" link, change the status to';
$hesklang['isStaffClosedOptionMsg'] = 'When a staff member clicks the "Close ticket" link, change the status to';
$hesklang['isStaffReopenedStatusMsg'] = 'When a staff member clicks the "Open ticket" link, change the status to';
$hesklang['isDefaultStaffReplyStatusMsg'] = 'When a staff member replies to a ticket, change the status to';
$hesklang['lockedTicketStatusMsg'] = 'When a ticket is locked, change the status to';
$hesklang['textColorRequired'] = 'Text Color is required.';
$hesklang['addNew'] = 'Add New';
$hesklang['close_action']='Close Ticket'; // Close ACTION
$hesklang['whyCantIDeleteThisStatus'] = "Why Can't I Delete This Status?";
$hesklang['whyCantIDeleteThisStatusReason'] = 'This status cannot be deleted because it is being used as a default status for a particular action.';
$hesklang['isNewTicketMsg'] = 'When a new ticket is created, set its status to';
$hesklang['isRepliedByClientMsg'] = 'When a client replies to a ticket, set its status to';
$hesklang['close_this_ticket']='Close ticket';
$hesklang['closed']='closed';
$hesklang['resolved']='Resolved'; // Ticket has been RESOLVED
$hesklang['quick_help_ticket']='Here is the information on your ticket. You can add a reply to this ticket, close it, or re-open the ticket if applicable.';
// ADDED OR MODIFIED IN Mods For HESK 1.2.2
$hesklang['changeLanguage'] = 'Change language to';
// ADDED OR MODIFIED IN Mods For HESK 1.4.0
$hesklang['navbarBackgroundColor'] = 'Navbar Background Color';
$hesklang['navbarBackgroundColorHelp'] = 'The main color of the top navigation bar. This applies only to the client-side.';
$hesklang['navbarBrandColor'] = 'Navbar Brand Color';
$hesklang['navbarBrandColorHelp'] = 'The text color of the \'brand\' on the left (also the name of the Help Desk).';
$hesklang['navbarBrandHoverColor'] = 'Navbar Brand Hover Color';
$hesklang['navbarBrandHoverColorHelp'] = 'The text color of the \'brand\' on the left when the use moves their mouse over the text.';
$hesklang['navbarItemTextColor'] = 'Navbar Item Text Color';
$hesklang['navbarItemTextColorHelp'] = 'The text color of the navigation items on the navigation bar.';
$hesklang['navbarItemTextHoverColor'] = 'Navbar Item Text Hover Color';
$hesklang['navbarItemTextHoverColorHelp'] = 'The text color of the navigation items on the navigation bar when the user hovers over one of the items.';
$hesklang['navbarItemTextSelectedColor'] = 'Navbar Item Text Selected Color';
$hesklang['navbarItemTextSelectedColorHelp'] = 'The text color of the navigation items on the navigation bar when the user clicks on an item, and a dropdown menu appears (such as \'Ticket\').';
$hesklang['navbarItemSelectedBackgroundColor'] = 'Navbar Item Selected Background Color';
$hesklang['navbarItemSelectedBackgroundColorHelp'] = 'The background color of the navigation items on the navigation bar when the user clicks on an item, and a dropdown menu appears (such as \'Ticket\').';
$hesklang['dropdownItemTextColor'] = 'Dropdown Item Text Color';
$hesklang['dropdownItemTextColorHelp'] = 'The text color of a dropdown item.';
$hesklang['dropdownItemTextHoverColor'] = 'Dropdown Item Text Hover Color';
$hesklang['dropdownItemTextHoverColorHelp'] = 'The text color of a dropdown item when the mouse hovers over it.';
$hesklang['questionMarkColor'] = 'Question Mark Color';
$hesklang['questionMarkColorHelp'] = 'The text color for the question mark circle, as seen on the \'Settings\' page and on other various pages.';
$hesklang['dropdownItemTextHoverBackgroundColor'] = 'Dropdown Item Text Hover Background Color';
$hesklang['dropdownItemTextHoverBackgroundColorHelp'] = 'The background color of a dropdown item when the mouse hovers over it.';
$hesklang['uiColors'] = 'UI Colors';
$hesklang['displayRtl'] = 'Display site right-to-left';
$hesklang['displayRtlHelp'] = 'Check this to set the text direction to right-to-left.';
$hesklang['showIcons'] = 'Show Icons';
$hesklang['showIconsHelp'] = 'Check this box to show icons next to navigation bar items';
$hesklang['maintenanceMode'] = 'Maintenance Mode';
$hesklang['maintenanceModeHelp'] = 'Check this box to put the Help Desk in maintenance mode. Staff can still log into the backend, but the front end will be inaccessible.';
$hesklang['none'] = 'None';
$hesklang['autorefresh'] = 'Autorefresh:';
$hesklang['autorefresh_restrictions'] = 'Enter value in milliseconds. Value must be greater than 1000 to use this feature. No fractional values.';
// ADDED OR MODIFIED IN Mods For HESK 1.5.0
$hesklang['ticket_auto_refresh'] = 'Ticket Table Auto-Refresh:';
$hesklang['display_rtl'] = 'Display site right-to-left';
$hesklang['show_icons_navigation'] = 'Show icons on navigation bar';
$hesklang['enable_maintenance'] = 'Enable maintenance mode';
$hesklang['can_man_settings']='Can manage help desk settings';
$hesklang['disable_user'] = 'User is active (click to deactivate)';
$hesklang['enable_user'] = 'User is inactive (click to activate)';
$hesklang['user_activated'] = 'User has been activated';
$hesklang['user_deactivated'] = 'User has been deactivated';
$hesklang['active_user'] = 'Is active user';
$hesklang['self_deactivation'] = 'You cannot deactivate yourself!';
$hesklang['inactive_user'] = 'Your account is currently inactive. Contact an administrator for more information.';
$hesklang['cant_edit_admin'] = 'You cannot edit the God Admin (User ID = 1)';
$hesklang['notifications_disabled_info'] = 'Changing notifications settings has been disabled by your administrator.';
// ADDED OR MODIFIED IN Mods For HESK 1.6.0
$hesklang['notify_note_unassigned'] = 'Someone adds a note to a ticket not assigned to me';
$hesklang['can_change_notification_settings'] = 'Can change notification settings';
$hesklang['add_row'] = 'Add row';
$hesklang['addnote'] = 'Add note';
$hesklang['mods_for_hesk'] = 'Mods for HESK';
$hesklang['err_modsForHesk_settings'] = 'Can\'t open file <b>modsForHesk_settings.inc.php</b> for writing. Please CHMOD this file to 666 (rw-rw-rw-)';
$hesklang['mods_for_hesk_version'] = 'Mods for HESK Version';
// ADDED OR MODIFIED IN Mods For HESK 1.7.0
$hesklang['date_custom_field'] = 'Date';
$hesklang['date_custom_field_text'] = 'No options for this custom field type.';
$hesklang['multiple_select_custom_field'] = 'Multiple Select box';
$hesklang['multiple_select_custom_field_text'] = 'Options for this multi-select box, enter one option per line (each line will be a choice your customers can choose from). You need to enter at least two options!';
$hesklang['date_format'] = 'Date must be in YYYY-MM-DD format.';
$hesklang['custom_field_setting'] = 'Multilanguage support';
$hesklang['custom_field_setting_help'] = 'Enabling this setting will use the name of the custom field as the language
file\'s key, rather than the direct name itself. This allows the custom field to be translated into different languages.';
$hesklang['enable_custom_field_language'] = 'Enable multilanguage support';
$hesklang['custom_language_key'] = 'Field language file key';
$hesklang['ticket_reopen_assigned'] = '[#%%TRACK_ID%%] Assigned ticket reopened';
$hesklang['verify_email'] = 'Verify Email';
$hesklang['email_verified'] = 'The email address <b>%s</b> has been verified. Additionally, the following tickets have been created:'; //%s: email address
$hesklang['verify_no_records'] = 'No records were found for this activation key. Has this activation key already been used?';
$hesklang['activation_key'] = 'Activation Key';
$hesklang['no_tickets_created'] = 'No tickets created';
$hesklang['customer_email_verification'] = 'Customer Email Verifications';
$hesklang['customer_email_verification_help'] = 'Require customers to verify their email address via email. Once their
address has been verified, it does not need to be re-verified in the future. <br><br> <b>NOTE:</b> Enabling this will disable the
ability for the customer to provide multiple emails, as HESK will be unable to determine which email needs to be verified.';
$hesklang['require_customer_validate_email'] = 'Require customers to verify email';
$hesklang['multi_eml_disabled'] = 'This feature has been disabled because this help desk has been configured to require
customers to verify their email address';
$hesklang['feature_disabled'] = 'Feature Disabled';
$hesklang['verify_your_email'] = 'Your ticket has been created; however your email needs to be verified before your ticket can be addressed. An email has been sent to the email provided for verification.';
$hesklang['installation_information'] = 'Installation Information';
// ADDED OR MODIFIED IN Mods For HESK 2.0.0
$hesklang['saved_ticket_tpl'] = 'Saved Templates';
$hesklang['new_ticket_tpl']='Add or Edit a Ticket Template';
$hesklang['and_change_status_to'] = 'and change status to'; // Used in combination with $hesklang['submit_reply'] (Reads as "Submit reply and change status to")
$hesklang['closed_title'] = 'Closed';
$hesklang['image'] = 'Image';
$hesklang['close_modal'] = 'Close';
$hesklang['email_custom_field'] = 'Email Address';
$hesklang['email_custom_field_help'] = 'Allows the input of an email address. Similar to a text field, however the email address(es) will be added to all emails for this ticket, in the Cc or Bcc section, depending on the option selected.';
$hesklang['email_custom_field_label'] = 'Address Type';
$hesklang['cc'] = 'Cc:';
$hesklang['bcc'] = 'Bcc:';
$hesklang['mailgun'] = 'Mailgun';
$hesklang['mailgun_help'] = 'Send mail using the Mailgun API. For more information on Mailgun, visit https://www.mailgun.com';
$hesklang['mailgun_api_key'] = 'Mailgun API Key';
$hesklang['mailgun_api_key_help'] = 'Your API key for Mailgun.';
$hesklang['mailgun_domain'] = 'Mailgun Domain';
$hesklang['mailgun_domain_help'] = 'Your registered domain for Mailgun';
$hesklang['html_emails'] = 'HTML Emails';
$hesklang['html_emails_help'] = 'Send HTML-supported emails to staff and customers.<br><br>To use this feature, create a new folder called <b>html</b> in your
language\'s <b>emails</b> folder and create templates for each email file. Both the HTML and plaintext versions will be sent (recipient\'s email program will
properly display either the HTML or plaintext version, depending on their mail client\'s settings).';
$hesklang['html_emails_text'] = 'Enable HTML-formatted emails';
$hesklang['beta_text'] = 'BETA';
// ADDED OR MODIFIED IN Mods for HESK 2.1.0
$hesklang['e_mfh_settings'] = 'You will not be able to save your settings unless this file is writable by the script (CHMOD to 666)!';
$hesklang['mfh_up_to_date'] = 'Mods for HESK is up to date';
$hesklang['use_bootstrap_theme'] = 'Use Boostrap Theme CSS';
$hesklang['use_bootstrap_theme_help'] = 'Enable this to use the <code>bootstrap-theme.css</code> file. Use this for a more 3D look and feel, or disable it for a flatter look.';
// ADDED OR MODIFIED IN Mods for HESK 2.1.1
$hesklang['new_article_default_type'] = 'Default Type for New Articles';
$hesklang['new_article_default_type_help'] = 'Choose the default type for new knowledgebase articles.';
$hesklang['kb_draft3'] = 'The article is saved but not yet published. It can only be read by staff who has permission to
manage knowledgebase articles.'; // This is exactly the same as kb_draft2 with all HTML removed
$hesklang['file_name'] = 'File Name';
$hesklang['action'] = 'Action';
$hesklang['click_to_preview'] = 'Click to preview';
$hesklang['attachment_removed'] = 'This attachment has been removed and cannot be viewed / downloaded';
// ADDED OR MODIFIED IN Mods for HESK 2.2.0
$hesklang['email_templates'] = 'Email templates';
$hesklang['email_templates_intro'] = 'You can edit your plaintext and HTML email templates here.';
$hesklang['edit_plain_text_template'] = 'Edit plain text template';
$hesklang['edit_html_template'] = 'Edit HTML template';
$hesklang['editing_plain_text_template'] = 'Editing plain text template <code>%s</code>'; // %s: The name of the template file, then language name
$hesklang['editing_html_template'] = 'Editing HTML template <code>%s</code>'; // %s: The name of the template file, then language name
$hesklang['show_special_tags'] = 'Show Special Tags';
$hesklang['hide_special_tags'] = 'Hide Special Tags';
$hesklang['special_tag'] = 'Special Tag';
$hesklang['description'] = 'Description';
$hesklang['customer_name'] = 'Customer name';
$hesklang['customer_email'] = 'Customer email';
$hesklang['ticket_subject'] = 'Ticket subject';
$hesklang['ticket_message'] = 'Ticket/Reply message';
$hesklang['ticket_created'] = 'Date and time of ticket submission';
$hesklang['ticket_updated'] = 'Date and time of ticket last update';
$hesklang['ticket_url'] = 'Ticket URL address';
$hesklang['ticket_category'] = 'Ticket category';
$hesklang['ticket_owner'] = 'Staff member assigned to the ticket';
$hesklang['ticket_priority'] = 'Ticket priority';
$hesklang['custom_field_x'] = 'Custom field %s'; // %s: Custom field #1-20
$hesklang['email_template_saved'] = 'The email template <b>%s</b> has been saved.'; // %s: Template file name
$hesklang['error_saving_template'] = 'An error occurred when trying to save the email template!';
$hesklang['can_man_email_tpl'] = 'Edit email templates';
$hesklang['email_template_directory_not_writable'] = 'The email template <b>%s</b> is not writable by HESK. Please CHMOD it to 0666.'; // %s: template file name
$hesklang['closable_question'] = 'Closable?';
$hesklang['closable_description'] = '<b><i>This setting is ignored if the &quot;Closed?&quot; setting is set to &quot;Yes&quot; for this status</i></b>.
<br><br>Determines if the customer and/or staff is able to close a ticket in this status.
<br><br><b>Yes:</b> Both customers and staff can close a ticket in this status.
<br><b>Customers only:</b> Customers can close a ticket in this status, but staff cannot.
<br><b>Staff only:</b> Staff can close a ticket in this status, but customers cannot.
<br><b>No:</b> No one is allowed to close a ticket in this status.'; // &quot; = "
$hesklang['customers_only'] = 'Customers only';
$hesklang['staff_only'] = 'Staff only';
$hesklang['yes_title_case'] = 'Yes';
$hesklang['no_title_case'] = 'No';
$hesklang['autoclose_ticket_status'] = 'When a ticket is closed automatically, change the status to';
$hesklang['recent_tickets'] = 'Recent tickets';
$hesklang['current_status_colon'] = 'Current status: %s'; // %s: status name (i.e. "Resolved", "New", etc.)
$hesklang['email_attachments'] = 'Email attachments';
$hesklang['email_attachments_help'] = '<b>Show attachments as links:</b> Links to attachments will be appended at the end of the email.
<br><br><b>Attach directly to email:</b> Attachments will be embedded directly into emails.';
$hesklang['show_attachments_as_links'] = 'Show attachments as links';
$hesklang['attach_directly_to_email'] = 'Attach directly to email';
// ADDED OR MODIFIED IN Mods for HESK 2.2.1
$hesklang['popart_no_colon']='Top Knowledgebase Articles'; // same as $hesklang['popart'] but without a colon (:)
$hesklang['latart_no_colon']='Latest Knowledgebase Articles'; // same as $hesklang['latart'] but without a colon (:)
$hesklang['ac_no_colon']='Articles in this Category'; // same as $hesklang['ac'] but without a colon (:)
// ADDED OR MODIFIED IN Mods for HESK 2.3.0
$hesklang['sm_icon'] = 'Icon';
$hesklang['sm_icon_type'] = 'Icon Type';
$hesklang['sm_no_icon'] = 'No Icon';
$hesklang['sm_search_icon'] = 'Search Icon';
$hesklang['sm_iconpicker_footer_label'] = '{0} - {1} of {2}'; // {0}: lower bound of page, {1}: upper bound of page, {2}: total number of icons
$hesklang['mods_for_hesk_acronym'] = 'MFH'; // THIS SHOULD NOT BE TRANSLATED
$hesklang['added_in_mods_for_hesk'] = 'Added in Mods for HESK';
$hesklang['statuses_intro'] = 'Here you can add, remove, and modify ticket statuses, as well as changing the default status for particular actions.';
$hesklang['statuses_saved'] = 'Ticket statuses have been updated!';
$hesklang['email_template_not_saved'] = 'The email template <b>%s</b> was NOT saved due to an error. Enable debug mode to see if an error message appears, and ensure that your file has CHMOD 0666'; // %s: Template file name
$hesklang['language_key'] = 'Language Key';
$hesklang['language_key_description'] = 'This is the language file \'key\' that contains the text you want to display';
$hesklang['can_man_ticket_statuses'] = 'Can manage ticket statuses';
$hesklang['key_required'] = 'Keys are required for all statuses';
$hesklang['x_merged'] = '(+%s merged)'; // %s number of tickets merged
$hesklang['merged_tickets'] = 'Merged tickets: ';
$hesklang['show_number_merged'] = 'Show number of tickets merged';
$hesklang['show_number_merged_descr'] = 'Show number of tickets merged next to Tracking ID';
$hesklang['show_number_merged_help'] = 'If enabled, the user will be able to see which tickets were merged into the other on the ticket search screen.';
$hesklang['latest_top_on_home'] = 'Latest/Top articles on home page';
$hesklang['latest_top_on_home_help'] = 'Select YES to display the top and latest knowledgebase articles on the home page.
Otherwise, a link to the knowledgebase will appear on the home page.';
$hesklang['location_unavailable'] = "Location unavailable. Click for more information.";
$hesklang['click_for_map'] = "View map of user's location";
$hesklang['request_user_location'] = "Request Location";
$hesklang['request_user_location_help'] = "If enabled, the help desk will ask for the customer's location, allowing staff to
see a map of the customer's location when they created the ticket.";
$hesklang['users_location'] = "User's Location";
$hesklang['location_unavailable_0'] = "User's location is not available because the ticket was created before location tracking was enabled.";
$hesklang['location_unavailable_1'] = "User's location is not available because the user refused to share it.";
$hesklang['location_unavailable_2'] = "User's location is not available because the help desk was unable to determine the user's position.";
$hesklang['location_unavailable_3'] = "User's location is not available because the help desk was not able to determine the user's position in
a reasonable amount of time.";
$hesklang['location_unavailable_4'] = "An unknown error occurred when trying to obtain the user's location.";
$hesklang['location_unavailable_5'] = "User's location is not available because the user's browser did not meet the minimum
requirements for tracking their location when the ticket was submitted.";
$hesklang['save_location'] = 'Save Location';
$hesklang['close_modal_without_saving'] = 'Close without saving';
$hesklang['ticket_location_updated'] = 'Ticket location has been updated!';
$hesklang['location_colon'] = 'Location:';
$hesklang['your_current_location'] = 'Your location';
$hesklang['requesting_location_ellipsis'] = 'Requesting location...';
$hesklang['unable_to_determine_location'] = 'Unable to determine your location, or you declined to share it.';
$hesklang['save_to_see_updated_address'] = 'Save the new location to see the updated address';
$hesklang['manager'] = 'Manager';
$hesklang['manager_updated'] = 'Category manager has been updated.';
$hesklang['can_set_manager'] = 'Can set category managers';
$hesklang['no_manager'] = 'No manager';
$hesklang['number_of_users'] = 'Number of Users';
$hesklang['actions'] = 'Actions';
$hesklang['staff_cannot_be_admin'] = 'Staff permission group does not have admin access, and cannot be set as an admin';
$hesklang['admin_cannot_be_staff'] = 'Administrator permission group has admin access, and cannot be set as non-admin';
$hesklang['template_is_admin_cannot_change'] = 'The permission group currently has admin privileges, so you cannot set specific permissions here.';
$hesklang['you_must_select_a_category'] = 'You must select at least one category.';
$hesklang['you_must_select_a_feature'] = 'You must select at least one feature.';
$hesklang['custom'] = 'Custom';
// ADDED OR MODIFIED IN Mods for HESK 2.4.0
$hesklang['sort_by_user_defined_order'] = 'Sort by user-defined order';
$hesklang['sort_alphabetically'] = 'Sort alphabetically';
$hesklang['category_sort'] = 'Category Sorting';
$hesklang['category_sort_help'] = 'Determines if categories shown on the manage categories page and all dropdowns are sorted by the user-defined order (default), or
sorted alphabetically.';
$hesklang['quick_help_sections'] = 'Quick Help Sections';
$hesklang['quick_help_sections_help'] = 'Check the checkbox to show the "Quick Help" sections on the left-hand side, or uncheck to not show.';
$hesklang['create_ticket'] = 'Create ticket (customers)';
$hesklang['view_ticket_form'] = 'View ticket form';
$hesklang['knowledgebase'] = 'Knowledgebase section';
$hesklang['staff_create_ticket'] = 'Create ticket (staff)';
$hesklang['allow_rich_text_for_tickets'] = 'Allow rich text for tickets';
$hesklang['allow_rich_text_for_tickets_help'] = 'Allow staff and customers to use rich text formatting when writing ticket messages / replies.';
$hesklang['click_to_edit_name'] = 'Click to edit name';
$hesklang['new_status'] = 'New Status';
$hesklang['create_new_status_title'] = 'Create New Status';
$hesklang['status_name_title'] = 'Status Name';
$hesklang['status_name_title_help'] = 'The name of the status that should appear when viewing the ticket, for each language you have installed.';
$hesklang['properties'] = 'Properties';
$hesklang['closable'] = 'Closable'; // Same as $hesklang['closable_question'], but without punctuation
$hesklang['new_status_created'] = 'New status successfully created';
$hesklang['editing_status_x'] = 'Editing status <span style="color: %s; font-weight: bold">%s</span>'; // 1st %s: text color, 2nd %s: status name
$hesklang['status_not_in_database'] = 'The status text for this language was not found in the database, so a suggested translation has been filled for you.
Please click "Save Changes" to save this translation to the database and to remove this warning.';
$hesklang['ticket_status_updated'] = 'Ticket status successfully updated!';
$hesklang['ticket_status_deleted'] = 'Ticket status deleted!';
$hesklang['confirm_delete_status_question'] = 'Delete status?';
$hesklang['confirm_delete_status'] = 'Are you sure you want to delete this status? This cannot be undone!';
$hesklang['status_sort_updated'] = 'Ticket status sort updated!';
$hesklang['status_sort'] = 'Status Sorting';
$hesklang['status_sort_help'] = 'Determines if statuses shown on the manage statuses page and all dropdowns are sorted by the user-defined order (default), or sorted alphabetically.';
$hesklang['cannot_delete_status_tickets'] = 'This status cannot be deleted because there are tickets set to this status.';
$hesklang['default_statuses_updated'] = 'Default statuses have been updated!';
$hesklang['download_count'] = 'Download Count';
$hesklang['kb_attach_dir'] = 'Knowledgebase attachments folder';
$hesklang['kb_attach_dir_help'] = 'Name of the folder, where knowledgebase attachments will be stored.<br><br>The folder needs to exist within the main HESK folder and be writable by PHP. On most systems names are CaSe SeNSiTiVe.
<br><br>Allowed chars (other will be removed): a-z A-Z 0-9 _ -';
$hesklang['ticket_attach_dir'] = 'Ticket attachments folder';
$hesklang['cannot_edit_status_demo'] = 'You cannot edit statuses while in demo mode!';
// ADDED OR MODIFIED IN Mods for HESK 2.5.0
$hesklang['ticket_message_no_attachments'] = 'Ticket/Reply message, however attachments will not be included in the email';
$hesklang['click_for_device_information'] = 'Click for device information';
$hesklang['device_information'] = 'Device information';
$hesklang['operating_system'] = 'Operating System';
$hesklang['browser'] = 'Browser';
$hesklang['screen_resolution'] = 'Screen Resolution';
$hesklang['display_user_agent_information'] = 'Show user agent';
$hesklang['display_user_agent_information_help'] = 'When enabled, staff will be able to view the operating system, browser,
and screen resolution of the device used to create the ticket.';
$hesklang['value_colon'] = 'Value:';
$hesklang['hidden_custom_field'] = 'Hidden text field';
$hesklang['hidden_custom_field_help'] = 'This input is the same as a text field; however this value cannot be changed and will not be visible to the user.';
$hesklang['readonly_custom_field'] = 'Read-only text field';
$hesklang['readonly_custom_field_help'] = 'This input is the same as a text field; however this value cannot be changed, but will be visible to the user.';
$hesklang['navbar_title_url'] = 'Navbar Title URL';
$hesklang['navbar_title_url_help'] = 'Enter the URL you wish to use when a customer (or staff) clicks on the help desk title on the top-left corner of the screen. The URL must begin with http:// or https://.';
$hesklang['this_field_is_required'] = 'This field is required';
$hesklang['select_at_least_one_value'] = 'Please select at least one value';
// ADDED OR MODIFIED IN Mods for HESK 2.5.2
$hesklang['manage_statuses'] = 'Manage Statuses';
$hesklang['manage_service_messages'] = 'Manage Service Messages';
$hesklang['manage_banned_ips'] = 'Manage Banned IPs';
$hesklang['manage_banned_emails'] = 'Manage Banned Emails';
$hesklang['manage_email_templates'] = 'Manage Email Templates';
$hesklang['linked_tickets'] = 'Linked tickets';
$hesklang['add_ticket'] = 'Add Ticket';
$hesklang['cannot_link_ticket_to_itself'] = 'You cannot link a ticket to itself!';
$hesklang['linked_ticket_does_not_exist'] = '<strong>%s</strong> is not a valid Tracking ID!'; //%s: the child tracking ID
$hesklang['is_already_linked'] = '<strong>%s</strong> is already linked to this ticket.'; //%s: the child tracking ID
$hesklang['link_added'] = 'Successfully linked <strong>%s</strong> to this ticket.'; //%s: the child tracking ID
$hesklang['ticket_no_longer_linked'] = 'Ticket is no longer linked.';
$hesklang['unlink'] = 'Unlink';
// ADDED OR MODIFIED IN Mods for HESK 2.6.0
$hesklang['search_logs'] = 'Search Logs';
$hesklang['date_logged'] = 'Date Logged';
$hesklang['from_date'] = 'From Date';
$hesklang['to_date'] = 'To Date';
$hesklang['severity'] = 'Severity';
$hesklang['debug'] = 'Debug';
$hesklang['warning_title_case'] = 'Warning';
$hesklang['logs'] = 'Logs';
$hesklang['view_message_log'] = 'View Message Log';
$hesklang['can_view_logs'] = 'Can view message logs';
$hesklang['attachment_viewer_message'] = "Drag files here or click the 'Add File' button below to select files to upload.";
$hesklang['attachment_invalid_type_message'] = 'Sorry, but the file type you tried to upload is not allowed.';
$hesklang['attachment_upload_error'] = 'An error occurred when trying to upload. Please try again later.';
$hesklang['attachment_too_large'] = 'This attachment is larger than the max filesize permitted.';
$hesklang['attachment_cancel'] = 'Cancel';
$hesklang['attachment_confirm_cancel'] = 'Are you sure you want to cancel this upload?';
$hesklang['attachment_remove'] = 'Remove attachment';
$hesklang['due_date'] = 'Due Date';
$hesklang['category_updated'] = 'Changes to <i>%s</i> have been saved';
$hesklang['new_event'] = 'New Event';
$hesklang['create_event'] = 'Create Event';
$hesklang['event_title'] = 'Title';
$hesklang['event_title_tooltip'] = 'The title of the event';
$hesklang['event_location'] = 'Location';
$hesklang['event_location_tooltip'] = 'The location of the event';
$hesklang['event_category_tooltip'] = 'Category for the event';
$hesklang['event_start'] = 'Start';
$hesklang['event_start_tooltip'] = 'The starting date (and time) of the event';
$hesklang['event_start_date'] = 'Start Date';
$hesklang['event_start_time'] = 'Start Time';
$hesklang['event_all_day'] = 'All day';
$hesklang['event_end'] = 'End';
$hesklang['event_end_tooltip'] = 'The ending date (and time) of the event';
$hesklang['event_end_date'] = 'End Date';
$hesklang['event_end_time'] = 'End Time';
$hesklang['event_reminder'] = 'Reminder';
$hesklang['event_reminder_tooltip'] = 'Receive an e-mail reminder for this event. Only you will receive this reminder email.';
$hesklang['event_min_before_event'] = 'minutes before event';
$hesklang['event_hours_before_event'] = 'hours before event';
$hesklang['event_days_before_event'] = 'days before event';
$hesklang['event_weeks_before_event'] = 'weeks before event';
$hesklang['event_comments'] = 'Comments';
$hesklang['event_comments_tooltip'] = 'Additional comments about the event';
$hesklang['event_create_ticket'] = 'Create Ticket';
$hesklang['to_title_case'] = 'To';
$hesklang['clear_for_no_due_date'] = 'Clear for no due date';
$hesklang['ticket_due_date_updated'] = 'Ticket due date successfully updated';
$hesklang['error_updating_ticket_due_date'] = 'An error occurred when trying to update the ticket due date';
$hesklang['error_loading_events'] = 'An error occurred when trying to load events';
$hesklang['error_deleting_event'] = 'An error occurred when trying to delete the event';
$hesklang['event_deleted'] = 'Event successfully deleted';
$hesklang['event_created'] = 'Event successfully created';
$hesklang['error_creating_event'] = 'An error occurred when trying to create the event';
$hesklang['event_updated'] = 'Event successfully updated';
$hesklang['error_updating_event'] = 'An error occurred when trying to update the event';
$hesklang['calendar_title_case'] = 'Calendar';
$hesklang['calendar_categories'] = 'Categories';
$hesklang['can_man_calendar'] = 'Can manage calendar events';
$hesklang['calendar_reminder'] = 'Upcoming Event: %%TITLE%%';
$hesklang['overdue_ticket'] = '[%%TRACKID%%] Ticket Overdue!';
$hesklang['notify_overdue_unassigned'] = 'A ticket is overdue not assigned to me';
$hesklang['calendar_settings'] = 'Calendar Settings';
$hesklang['enable_calendar'] = 'Enable calendar';
$hesklang['enable_calendar_help'] = 'Setting to enable / disable the calendar. The calendar can be shown to everyone, staff only, or disable the calendar entirely.';
$hesklang['yes_enable_calendar'] = '<b>YES</b>, enable calendar';
$hesklang['yes_enable_calendar_staff_only'] = '<b>YES</b>, enable calendar, but only for staff';
$hesklang['no_disable_calendar'] = '<b>NO</b>, disable calendar';
$hesklang['first_day_of_week'] = 'First day of week';
$hesklang['first_day_of_week_help'] = 'This setting decides which day of the week to show first per week.';
$hesklang['calendar_disabled'] = 'The calendar is disabled';
$hesklang['default_view'] = 'Default Calendar View';
$hesklang['default_view_help'] = 'Decide which view will be shown to customers and staff by default when viewing the calendar. Staff can change this setting via their own profile.';
$hesklang['week'] = 'Week';
$hesklang['calendar_day'] = 'Day';
$hesklang['calendar_index'] = 'View upcoming events';
$hesklang['usage'] = 'Usage';
$hesklang['tickets_and_events'] = 'Tickets and events';
$hesklang['tickets_only'] = 'Tickets only';
$hesklang['events_only'] = 'Events only';
$hesklang['events'] = 'Events';
$hesklang['add_files'] = '<i class="fa fa-plus"></i> Add File';
$hesklang['select_all_title_case'] = 'Select All';
$hesklang['deselect_all_title_case'] = 'Deselect All';
$hesklang['event'] = 'Event';
$hesklang['overdue_ticket_legend'] = 'Overdue ticket';
$hesklang['attachment_max_exceeded'] = 'This file will not be uploaded becuase you have already uploaded the maximum number of files allowed.';
// ADDED OR MODIFIED IN Mods for HESK 3.0.0
$hesklang['you_have_x_messages'] = 'You have %s new %s'; // %s: Number of new messages, "message" or "messages", depending on #
$hesklang['message_lower_case'] = 'message';
$hesklang['messages_lower_case'] = 'messages';
$hesklang['deleted_user_title_case'] = 'Deleted User';
$hesklang['x_system_warnings'] = '%s System %s'; // %s: Number of warnings, $s: "Warning" or "Warnings", depending on #
$hesklang['warnings_title_case'] = 'Warnings';
$hesklang['articles_in_category_x'] = 'Articles in Category %s'; // %s: category name
$hesklang['private_category_star'] = 'Private categories indicated by *';
$hesklang['private_article_star'] = 'Private articles indicated by *';
$hesklang['ticket_details'] = 'Ticket Details';
$hesklang['more'] = 'More';
$hesklang['click_to_edit'] = 'Click to edit';
$hesklang['no_device_information'] = 'No device information';
$hesklang['message_colon'] = 'Message:';
$hesklang['original_message'] = 'Original message';
$hesklang['reply_by_customer'] = 'Reply by customer';
$hesklang['reply_by_staff'] = 'Reply by staff';
$hesklang['timeline_today'] = 'Today';
$hesklang['no_notes_for_this_ticket'] = 'No notes for this ticket';
$hesklang['private_message_header'] = 'Private Message';
$hesklang['date_colon'] = 'Date:';
$hesklang['api_information'] = 'API Information';
$hesklang['api_version'] = 'API Version';
$hesklang['external_api'] = 'External API';
$hesklang['external_api_help'] = 'Enable or Disable the external REST API';
$hesklang['disabled_title_case'] = 'Disabled';
$hesklang['enabled_title_case'] = 'Enabled';
$hesklang['api_settings'] = 'API Settings';
$hesklang['user_security'] = 'User Security';
$hesklang['api_documentation'] = 'API Documentation';
$hesklang['changes_saved'] = 'Changes saved!';
$hesklang['save_failed_check_logs'] = 'Saving changes failed. Check the logs for more information.';
$hesklang['number_of_tokens'] = 'Number of Tokens';
$hesklang['generate_new_token'] = 'Generate New Token';
$hesklang['revoke_all_tokens'] = 'Revoke All Tokens';
$hesklang['generated_token_colon'] = 'Generated Token:';
$hesklang['record_this_token_warning'] = 'Please record this token, as this is the only time you will be able to view it!';
$hesklang['all_tokens_revoked'] = 'All tokens for this user have been revoked';
$hesklang['staff_login_title'] = 'Staff Login';
$hesklang['manage_custom_fields'] = 'Manage Custom Fields';
$hesklang['value'] = 'Value';
$hesklang['readonly'] = 'Readonly';
$hesklang['copy_ticket'] = 'Copy Ticket';
$hesklang['canned_responses_dropdown_title'] = 'Canned Responses';
$hesklang['helpdesk_settings'] = 'Helpdesk Settings';
$hesklang['click_to_toggle'] = 'Click to toggle';
$hesklang['see_all_messages'] = 'See All Messages';
// ADDED OR MODIFIED IN Mods for HESK 3.1.0
$hesklang['stack_trace_header'] = 'Stack Trace';
$hesklang['ticket_message_contents_exist'] = 'The ticket message is not empty. Are you sure you want to leave this page?';
$hesklang['resend_email_notification'] = 'Re-send Email Notification';
$hesklang['email_notification_sent'] = 'Email notification sent!';
$hesklang['email_notification_resend_failed'] = 'Error occurred when trying to send notification email.';
$hesklang['edit_category'] = 'Edit Category';
$hesklang['custom_nav_menu_elements'] = 'Custom Nav Menu Elements';
$hesklang['create_new'] = 'Create New';
$hesklang['custom_nav_element_deleted'] = 'Custom Navigation Element Deleted!';
$hesklang['no_custom_nav_elements_found'] = 'No custom nav menu elements found';
$hesklang['alert_success'] = 'Success'; // Used for alert messages
$hesklang['alert_error'] = 'Error'; // Used for alert messages
$hesklang['failed_to_load_custom_nav_elements'] = 'Failed to load custom nav elements!';
$hesklang['custom_nav_element_deleted'] = 'Custom nav element deleted!';
$hesklang['error_deleting_custom_nav_element'] = 'Error deleting custom nav element!';
$hesklang['error_sorting_custom_nav_elements'] = 'Error sorting custom nav elements!';
$hesklang['custom_nav_element_created'] = 'Custom nav element created!';
$hesklang['custom_nav_element_saved'] = 'Custom nav element saved!';
$hesklang['homepage_block'] = 'Homepage - Block';
$hesklang['customer_navigation'] = 'Customer Navigation';
$hesklang['staff_navigation'] = 'Staff Navigation';
$hesklang['custom_nav_text'] = 'Text';
$hesklang['custom_nav_subtext'] = 'Subtext';
$hesklang['image_url_slash_font_icon'] = 'Image URL / Font Icon';
$hesklang['edit_custom_nav_element_title_case'] = 'Edit Custom Nav Element';
$hesklang['create_custom_nav_element_title_case'] = 'Create Custom Nav Element';
$hesklang['place'] = 'Place';
$hesklang['image_type'] = 'Image Type';
$hesklang['image_url'] = 'Image URL';
$hesklang['image_url_help'] = 'The URL of the image you wish to use. For customer/staff navigation, recommended size is <b>16x16px</b>. For the homepage blocks, recommended size is <b>32x32px</b>.';
$hesklang['font_icon'] = 'Font Icon';
$hesklang['error_saving_custom_nav_element'] = 'Error saving custom nav element!';
$hesklang['place_help'] = 'The location of the custom navigation element.';
$hesklang['url_help'] = 'The URL where the user should be taken to. Both relative and absolute URLs are supported.';
$hesklang['common_properties'] = 'Common Properties';
$hesklang['customer_view'] = 'Customer View';
$hesklang['admin_panel'] = 'Admin Panel';
$hesklang['manage_custom_nav_elements'] = 'Manage Custom Nav Elements';
$hesklang['can_man_custom_nav'] = 'Can manage custom nav elements';
$hesklang['category_background_color'] = 'Background Color';
$hesklang['category_foreground_color'] = 'Foreground Color';
$hesklang['category_background_color_help'] = 'The hex code for the background color to be used on the view ticket screen and calendar.';
$hesklang['category_foreground_color_help'] = 'The hex code for the foreground color to be used on the view ticket and calendar screens. Leave blank for automatic color based on background.';
$hesklang['category_display_border'] = 'Display Border';
$hesklang['category_display_border_help'] = 'Choose to decide whether or not to display a border around the category (uses foreground color). <b>
This is ignored if foreground color is set to automatic.</b>';
$hesklang['login_page'] = 'Login Page'; // Header on admin settings page
$hesklang['login_background'] = 'Login Background';
$hesklang['solid_color'] = 'Solid color';
$hesklang['login_background_color'] = 'Login Background Color'; // Input field information for screen-readers. Does not appear on-screen
$hesklang['login_background_image'] = 'Login Background Image'; // Input field information for screen-readers. Does not appear on-screen
$hesklang['login_box_header'] = 'Login Box Header';
$hesklang['login_header_image'] = 'Login Header Image'; // Input field information for screen-readers. Does not appear on-screen
$hesklang['background_color'] = 'Background Color';
$hesklang['background_color_help'] = 'The background color.';
$hesklang['text_color'] = 'Text Color';
$hesklang['text_color_help'] = 'The text color';
$hesklang['text_hover_color'] = 'Hover Color: Text';
$hesklang['text_hover_color_help'] = 'The text color when hovering over a link';
$hesklang['background_hover_color'] = 'Hover Color: Background';
$hesklang['background_hover_color_help'] = 'The background color when hovering over a link';
$hesklang['navbar'] = 'Navigation Bar';
$hesklang['navbar_brand'] = 'Navigation Brand';
$hesklang['sidebar'] = 'Sidebar';
$hesklang['sidebar_header'] = 'Sidebar Header';
$hesklang['font_weight'] = 'Font Weight';
$hesklang['font_weight_help'] = 'The font weight for text';
$hesklang['normal'] = 'Normal';
$hesklang['bold'] = 'Bold';
$hesklang['color_preset'] = 'Color Preset';
$hesklang['color_preset_help'] = 'Select a color preset for the backend, or define custom colors below.';
$hesklang['select_a_preset'] = '-- Select a Preset --';
$hesklang['preset_blue'] = 'Blue';
$hesklang['preset_blue_light'] = 'Blue (light)';
$hesklang['preset_yellow'] = 'Yellow';
$hesklang['preset_yellow_light'] = 'Yellow (light)';
$hesklang['preset_green'] = 'Green';
$hesklang['preset_green_light'] = 'Green (light)';
$hesklang['preset_purple'] = 'Purple';
$hesklang['preset_purple_light'] = 'Purple (light)';
$hesklang['preset_red'] = 'Red';
$hesklang['preset_red_light'] = 'Red (light)';
$hesklang['preset_black'] = 'Black';
$hesklang['preset_black_light'] = 'Black (light)';
$hesklang['url_rewrite'] = 'URL Rewrite';
$hesklang['url_rewrite_help'] = 'Remove the need to include /index.php in API URLs (i.e. /api/index.php/v1/... -> /api/v1/...). Rename htaccess.txt to .htaccess in the /api folder to use.';
$hesklang['url_rewrite_saved'] = 'URL rewrite setting saved!';
$hesklang['api_settings_saved'] = 'API settings saved!';
$hesklang['an_error_occurred'] = 'An error occurred. Check the logs for more information';
// Added or modified in Mods for HESK 3.2.0
$hesklang['error_deleting_category'] = 'An error occurred when trying to delete the category.';
$hesklang['cat_private'] = 'Private';
$hesklang['cat_public'] = 'Public';
$hesklang['cat_name_description'] = 'Name / Description';
$hesklang['error_sorting_categories'] = 'An error occurred sorting categories!';
$hesklang['error_retrieving_categories'] = 'An error occurred retrieving categories!';
$hesklang['error_saving_updating_category'] = 'An error occurred creating / saving the category!';
$hesklang['description_colon'] = 'Description:'; // Same as 'description', but with a colon (:) afterwards
$hesklang['copied_to_clipboard'] = 'Copied to clipboard';
// Language for the calendar pages
// Supported language codes: https://github.com/fullcalendar/fullcalendar/tree/v3.0.1/locale (do not include .js!)
// If your language is NOT in the supported langauges, leave 'en'
$hesklang['CALENDAR_LANGUAGE']='en';
$hesklang['manage_permission_groups'] = 'Manage Permission Groups';
$hesklang['manage_permission_groups_help'] = 'Here you can create and edit permission groups. These groups will appear when creating/editing a user.
When editing a permission group, all users assigned to this group will also have their permissions updated accordingly.';
$hesklang['view_permissions_for_this_group'] = 'View/edit permissions for this group';
$hesklang['permission'] = 'Permission';
$hesklang['permissions_for_group'] = 'Permissions for group <code>%s</code>'; // %s template name
$hesklang['permission_group_updated'] = 'Permission group has been updated!';
$hesklang['create_new_group'] = 'Create new permission group';
$hesklang['create_new_group_title'] = 'Create New Permission Group'; // same as create_new_template, but in Title Case
$hesklang['group_name'] = 'Group name';
$hesklang['group_name_required'] = 'Group name required.';
$hesklang['permission_group_error'] = 'The permission group could not be saved due to the following error(s): %s'; // %s: error list
$hesklang['group_created'] = 'Permission group successfully created!';
$hesklang['cannot_delete_admin_or_staff'] = 'The <b>Administrator</b> and <b>Staff</b> permission groups cannot be deleted!';
$hesklang['no_groups_were_deleted'] = 'No groups were deleted!';
$hesklang['permission_group_deleted'] = 'Permission group deleted!';
$hesklang['manange_permission_groups_menu'] = 'Permission groups'; // Menu link
$hesklang['permission_groups'] = 'Permission Groups';
$hesklang['can_man_permission_tpl'] = 'Can manage permission groups';
$hesklang['permission_group_colon'] = 'Permission Group:';
$hesklang['permission_group'] = 'Permission Group';
$hesklang['changing_permissions_will_reset_permission_group'] = 'Changing a user\'s categories / features will reset their permission group! Click "Discard Changes" to reset the user\'s categories / features.';
// --> Ticket audit trail
$hesklang['audit_moved_category']='%s moved ticket to category %s'; // %s = new category, user making change, thist1
$hesklang['audit_assigned']='%s assigned ticket to %s'; // %s = assigned user, user making change
$hesklang['audit_assigned_self'] = '%s self-assigned ticket';
$hesklang['audit_unassigned'] = '%s unassigned ticket';
$hesklang['audit_closed']='%s closed ticket'; // thist3
$hesklang['audit_automatically_closed'] ='Ticket automatically closed';
$hesklang['audit_opened']='%s opened ticket'; // thist4
$hesklang['audit_locked']='%s locked ticket'; // thist5
$hesklang['audit_automatically_locked'] = 'Ticket automatically locked';
$hesklang['audit_unlocked']='%s unlocked ticket'; // thist6
$hesklang['audit_created']='%s created ticket';
$hesklang['audit_priority']='%s changed priority to %s'; // %s = date,new priority, user making change, thist8
$hesklang['audit_status']='%s changed status to %s'; // %s = date, new status, user making change, thist9
$hesklang['audit_autoassigned']='%s automatically assigned to ticket'; //thist10
$hesklang['audit_submitted_via_piping']='Ticket submitted via e-mail piping'; // thist11
$hesklang['audit_attachment_deleted']='%s deleted attachment %s'; // %s = date, deleted attachment, user making change
$hesklang['audit_merged']='%s merged ticket %s with this ticket'; // %s = date, merged ticket ID, user making change, thist13
$hesklang['audit_time_worked']='%s updated time worked to %s'; // %s = date, new time worked, user making change
$hesklang['audit_submitted_by']='%s submitted ticket';
$hesklang['audit_submitted_via_pop']='Ticket submitted via POP3 fetching'; // thist16
$hesklang['audit_due_date_removed'] = '%s removed due date';
$hesklang['audit_due_date_changed'] = '%s changed due date to %s';
$hesklang['audit_linked_ticket'] = '%s linked ticket %s to this ticket';
$hesklang['audit_unlinked_ticket'] = '%s unlinked ticket %s';
// Added or modified in Mods for HESK 3.3.0
$hesklang['audit_event_created'] = '%s created event';
$hesklang['audit_event_updated'] = '%s updated event';
$hesklang['error_retrieving_sm'] = 'An error occurred retrieving service messages!';
$hesklang['error_saving_updating_sm'] = 'An error occurred creating / saving the service message!';
$hesklang['error_deleting_sm'] = 'An error occurred when trying to delete the service message.';
$hesklang['error_sorting_sm'] = 'An error occurred sorting service messages!';
$hesklang['sm_location'] = 'Location'; // Location for service messages
$hesklang['sm_customer_pages'] = 'Customer Pages';
$hesklang['sm_staff_pages'] = 'Staff Pages';
$hesklang['sm_homepage'] = 'Homepage';
$hesklang['sm_kb_home'] = 'Knowledgebase Home';
$hesklang['sm_view_kb_article'] = 'View Knowledgebase Article';
$hesklang['sm_submit_ticket'] = 'Submit Ticket';
$hesklang['sm_view_ticket'] = 'View Ticket';
$hesklang['sm_login_page'] = 'Login Page';
$hesklang['business_hours'] = 'Business Hours';
$hesklang['business_hours_help'] = 'Set business hours for the calendar. There is no functional change by setting this,
but times outside of the defined business hours will have a darker gray background for increased visibility.';
$hesklang['show_event_start_time'] = 'Show event start time in title';
$hesklang['show_event_start_time_help'] = 'Always show the start time on event titles (unless the event is an all-day event).';
$hesklang['highlight_ticket_rows_based_on_priority'] = 'Highlight ticket rows based on priority';
$hesklang['highlight_ticket_rows_based_on_priority_help'] = 'If enabled, each ticket on the tickets page will be highlighted based on priority. If disabled, only * Critical * and High priority tickets will be highlighted.';
$hesklang['highlight_ticket_rows_based_on_priority_descr'] = 'Highlight all ticket rows based on priority';
$hesklang['protected_group'] = 'This is a protected group; you cannot change accessible categories / features.';
$hesklang['emails_to_receive'] = 'Emails to receive';
$hesklang['emails_sent_to_staff'] = 'Emails sent to staff';
$hesklang['emails_sent_to_customer'] = 'Emails sent to customer';
// Added or modified in Mods for HESK 4.0.0
$hesklang['audit_anonymized'] = '%s anonymized ticket';
$hesklang['location_unavailable_6'] = "This ticket was anonymized, so location information has been removed.";
$hesklang['anon_user_agent'] = '[User Agent]';
$hesklang['anon_screen_resolution'] = '0';
$hesklang['audit_submitted_via_imap']='Ticket submitted via IMAP fetching';
$hesklang['thist'] = 'Audit Log'; // Overriding text.php's value
// DO NOT CHANGE BELOW
if (!defined('IN_SCRIPT')) die('PHP syntax OK!');

File diff suppressed because it is too large Load Diff

@ -125,141 +125,7 @@ $modsForHesk_settings = mfh_getSettings();
<?php
/* Ticket priority */
switch ($ticket['priority']) {
case 0:
$ticket['priority'] = '<b>' . $hesklang['critical'] . '</b>';
break;
case 1:
$ticket['priority'] = '<b>' . $hesklang['high'] . '</b>';
break;
case 2:
$ticket['priority'] = $hesklang['medium'];
break;
default:
$ticket['priority'] = $hesklang['low'];
}
/* Set last replier name */
if ($ticket['lastreplier']) {
if (empty($ticket['repliername'])) {
$ticket['repliername'] = $hesklang['staff'];
}
} else {
$ticket['repliername'] = $ticket['name'];
}
/* Other variables that need processing */
$ticket['dt'] = hesk_date($ticket['dt'], true);
$ticket['lastchange'] = hesk_date($ticket['lastchange'], true);
$random = mt_rand(10000, 99999);
// Print ticket head
echo '
<h3>' . $ticket['subject'] . '</h3>
<hr/>
<table border="1" bordercolor="#FFFFFF" cellspacing="0" cellpadding="2" width="100%">
<tr>
<td bgcolor="#EEE"><b>' . $hesklang['trackID'] . ':</b></td><td bgcolor="#DDD">' . $trackingID . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['ticket_status'] . ':</b></td><td bgcolor="#DDD">' . $hesklang[$ticket['statusKey']] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['created_on'] . ':</b></td><td bgcolor="#DDD">' . $ticket['dt'] . '</td>
</tr>
<tr>
<td bgcolor="#EEE"><b>' . $hesklang['last_update'] . ':</b></td><td bgcolor="#DDD">' . $ticket['lastchange'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['last_replier'] . ':</b></td><td bgcolor="#DDD">' . $ticket['repliername'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['category'] . ':</b></td><td bgcolor="#DDD">' . $category['name'] . '</td>
</tr>
';
// Show IP and time worked to staff
if (!empty($_SESSION['id'])) {
echo '
<tr>
<td bgcolor="#EEE"><b>' . $hesklang['ts'] . ':</b></td><td bgcolor="#DDD">' . $ticket['time_worked'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['ip'] . ':</b></td><td bgcolor="#DDD">' . $ticket['ip'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['email'] . ':</b></td><td bgcolor="#DDD">' . $ticket['email'] . '</td>
</tr>
';
}
echo '<tr>';
// Assigned to?
if ($ticket['owner'] && !empty($_SESSION['id'])) {
$ticket['owner'] = hesk_getOwnerName($ticket['owner']);
echo '
<td bgcolor="#EEE"><b>' . $hesklang['taso3'] . '</b></td>
<td bgcolor="#DDD">' . $ticket['owner'] . '</td>
';
}
echo '
<td bgcolor="#EEE"><b>' . $hesklang['name'] . ':</b></td>
<td bgcolor="#DDD">' . $ticket['name'] . '</td>
';
echo '</tr>';
// Custom fields
$num_cols = 0;
echo '<tr>';
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if (($v['use'] == 1 || (! empty($_SESSION['id']) && $v['use'] == 2)) && hesk_is_custom_field_in_category($k, $ticket['category'])) {
if ($num_cols == 3) {
echo '</tr><tr>';
$num_cols = 0;
}
switch ($v['type']) {
case 'date':
$ticket[$k] = hesk_custom_date_display_format($ticket[$k], $v['value']['date_format']);
break;
}
?>
<td bgcolor="#EEE"><b><?php echo $v['name']; ?>:</b></td>
<td bgcolor="#DDD"><?php echo hesk_unhortenUrl($ticket[$k]); ?></td>
<?php
$num_cols++;
}
}
// Close ticket head table
echo '</table><br>';
// Print initial ticket message
if ($ticket['message'] != '') {
$newMessage = hesk_unhortenUrl($ticket['message']);
if ($ticket['html']) {
$newMessage = hesk_html_entity_decode($newMessage);
}
echo '<p>' . $newMessage . '</p>';
}
// Print replies
while ($reply = hesk_dbFetchAssoc($res)) {
$reply['dt'] = hesk_date($reply['dt'], true);
$theReply = hesk_unhortenUrl($reply['message']);
if ($reply['html']) {
$theReply = hesk_html_entity_decode($theReply);
}
echo '
<hr />
<table border="1" bordercolor="#FFFFFF" cellspacing="0" cellpadding="2" width="100%">
<tr>
<td bgcolor="#EEE"><b>' . $hesklang['date'] . ':</b></td><td bgcolor="#DDD">' . $reply['dt'] . '</td>
<td bgcolor="#EEE"><b>' . $hesklang['name'] . ':</b></td><td bgcolor="#DDD">' . $reply['name'] . '</td>
</tr>
</table>
<div class="message">' . $theReply . '</div>
';
}
// Print "end of ticket" message
echo $hesklang['end_ticket'];
require_once(HESK_PATH . 'inc/print_template.inc.php');
?>
</body>

@ -82,23 +82,8 @@ if ($hesk_settings['question_use']) {
// Check anti-SPAM image
if ($hesk_settings['secimg_use'] && !isset($_SESSION['img_verified'])) {
// Using ReCaptcha?
if ($hesk_settings['recaptcha_use'] == 1) {
require(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
$resp = recaptcha_check_answer($hesk_settings['recaptcha_private_key'],
hesk_getClientIP(),
hesk_POST('recaptcha_challenge_field', ''),
hesk_POST('recaptcha_response_field', '')
);
if ($resp->is_valid) {
$_SESSION['img_verified'] = true;
} else {
$hesk_error_buffer['mysecnum'] = $hesklang['recaptcha_error'];
}
} // Using ReCaptcha API v2?
elseif ($hesk_settings['recaptcha_use'] == 2) {
// Using reCAPTCHA?
if ($hesk_settings['recaptcha_use']) {
require(HESK_PATH . 'inc/recaptcha/recaptchalib_v2.php');
$resp = null;
@ -410,6 +395,7 @@ $tmpvar['owner'] = 0;
$autoassign_owner = hesk_autoAssignTicket($tmpvar['category']);
if ($autoassign_owner) {
$tmpvar['owner'] = $autoassign_owner['id'];
$tmpvar['assignedby'] = -1;
}
// Insert attachments
@ -462,7 +448,7 @@ if ($createTicket) {
$ticket = hesk_newTicket($tmpvar);
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_submitted_by', hesk_date(),
array(0 => $tmpvar['name']));
array(0 => $hesklang['customer']));
if ($autoassign_owner) {
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(),

@ -781,7 +781,7 @@ function hesk_getCustomerButtons($white = 1)
$style = 'class="option' . $tmp . 'OFF" onmouseover="this.className=\'option' . $tmp . 'ON\'" onmouseout="this.className=\'option' . $tmp . 'OFF\'"';
/* Print ticket button */
$options .= '<a href="print.php?track=' . $trackingID . $hesk_settings['e_query'] . '" title="' . $hesklang['printer_friendly'] . '"><span class="glyphicon glyphicon-print"></span> ' . $hesklang['printer_friendly'] . ' </a> ';
$options .= '<a class="btn btn-default" href="print.php?track=' . $trackingID . $hesk_settings['e_query'] . '" title="' . $hesklang['printer_friendly'] . '"><span class="fa fa-print"></span> ' . $hesklang['btn_print'] . ' </a> ';
/* Return generated HTML */
return $options;

Loading…
Cancel
Save