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

Mods for HESK 3.3.0 Update

Closes #599

See merge request mike-koch/Mods-for-HESK!95
master
Mike Koch 6 years ago
commit e56ef4d608

92
.gitignore vendored

@ -197,52 +197,52 @@ inc/tabs/tabber-minimized.js
inc/tabs/tabber.css
inc/timer/hesk_timer.js
inc/timer/index.htm
inc/tiny_mce/3.5.11/langs/en.js
inc/tiny_mce/3.5.11/license.txt
inc/tiny_mce/3.5.11/themes/advanced/about.htm
inc/tiny_mce/3.5.11/themes/advanced/anchor.htm
inc/tiny_mce/3.5.11/themes/advanced/charmap.htm
inc/tiny_mce/3.5.11/themes/advanced/color_picker.htm
inc/tiny_mce/3.5.11/themes/advanced/editor_template.js
inc/tiny_mce/3.5.11/themes/advanced/image.htm
inc/tiny_mce/3.5.11/themes/advanced/img/colorpicker.jpg
inc/tiny_mce/3.5.11/themes/advanced/img/flash.gif
inc/tiny_mce/3.5.11/themes/advanced/img/icons.gif
inc/tiny_mce/3.5.11/themes/advanced/img/iframe.gif
inc/tiny_mce/3.5.11/themes/advanced/img/pagebreak.gif
inc/tiny_mce/3.5.11/themes/advanced/img/quicktime.gif
inc/tiny_mce/3.5.11/themes/advanced/img/realmedia.gif
inc/tiny_mce/3.5.11/themes/advanced/img/shockwave.gif
inc/tiny_mce/3.5.11/themes/advanced/img/trans.gif
inc/tiny_mce/3.5.11/themes/advanced/img/video.gif
inc/tiny_mce/3.5.11/themes/advanced/img/windowsmedia.gif
inc/tiny_mce/3.5.11/themes/advanced/js/about.js
inc/tiny_mce/3.5.11/themes/advanced/js/anchor.js
inc/tiny_mce/3.5.11/themes/advanced/js/charmap.js
inc/tiny_mce/3.5.11/themes/advanced/js/color_picker.js
inc/tiny_mce/3.5.11/themes/advanced/js/image.js
inc/tiny_mce/3.5.11/themes/advanced/js/link.js
inc/tiny_mce/3.5.11/themes/advanced/js/source_editor.js
inc/tiny_mce/3.5.11/themes/advanced/langs/en.js
inc/tiny_mce/3.5.11/themes/advanced/langs/en_dlg.js
inc/tiny_mce/3.5.11/themes/advanced/link.htm
inc/tiny_mce/3.5.11/themes/advanced/shortcuts.htm
inc/tiny_mce/3.5.11/themes/advanced/skins/default/content.css
inc/tiny_mce/3.5.11/themes/advanced/skins/default/dialog.css
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/buttons.png
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/items.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/menu_arrow.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/menu_check.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/progress.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/tabs.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/ui.css
inc/tiny_mce/3.5.11/themes/advanced/source_editor.htm
inc/tiny_mce/3.5.11/tiny_mce.js
inc/tiny_mce/3.5.11/tiny_mce_popup.js
inc/tiny_mce/3.5.11/utils/editable_selects.js
inc/tiny_mce/3.5.11/utils/form_utils.js
inc/tiny_mce/3.5.11/utils/mctabs.js
inc/tiny_mce/3.5.11/utils/validate.js
inc/tiny_mce/3.5.12/langs/en.js
inc/tiny_mce/3.5.12/license.txt
inc/tiny_mce/3.5.12/themes/advanced/about.htm
inc/tiny_mce/3.5.12/themes/advanced/anchor.htm
inc/tiny_mce/3.5.12/themes/advanced/charmap.htm
inc/tiny_mce/3.5.12/themes/advanced/color_picker.htm
inc/tiny_mce/3.5.12/themes/advanced/editor_template.js
inc/tiny_mce/3.5.12/themes/advanced/image.htm
inc/tiny_mce/3.5.12/themes/advanced/img/colorpicker.jpg
inc/tiny_mce/3.5.12/themes/advanced/img/flash.gif
inc/tiny_mce/3.5.12/themes/advanced/img/icons.gif
inc/tiny_mce/3.5.12/themes/advanced/img/iframe.gif
inc/tiny_mce/3.5.12/themes/advanced/img/pagebreak.gif
inc/tiny_mce/3.5.12/themes/advanced/img/quicktime.gif
inc/tiny_mce/3.5.12/themes/advanced/img/realmedia.gif
inc/tiny_mce/3.5.12/themes/advanced/img/shockwave.gif
inc/tiny_mce/3.5.12/themes/advanced/img/trans.gif
inc/tiny_mce/3.5.12/themes/advanced/img/video.gif
inc/tiny_mce/3.5.12/themes/advanced/img/windowsmedia.gif
inc/tiny_mce/3.5.12/themes/advanced/js/about.js
inc/tiny_mce/3.5.12/themes/advanced/js/anchor.js
inc/tiny_mce/3.5.12/themes/advanced/js/charmap.js
inc/tiny_mce/3.5.12/themes/advanced/js/color_picker.js
inc/tiny_mce/3.5.12/themes/advanced/js/image.js
inc/tiny_mce/3.5.12/themes/advanced/js/link.js
inc/tiny_mce/3.5.12/themes/advanced/js/source_editor.js
inc/tiny_mce/3.5.12/themes/advanced/langs/en.js
inc/tiny_mce/3.5.12/themes/advanced/langs/en_dlg.js
inc/tiny_mce/3.5.12/themes/advanced/link.htm
inc/tiny_mce/3.5.12/themes/advanced/shortcuts.htm
inc/tiny_mce/3.5.12/themes/advanced/skins/default/content.css
inc/tiny_mce/3.5.12/themes/advanced/skins/default/dialog.css
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/buttons.png
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/items.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/menu_arrow.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/menu_check.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/progress.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/tabs.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/ui.css
inc/tiny_mce/3.5.12/themes/advanced/source_editor.htm
inc/tiny_mce/3.5.12/tiny_mce.js
inc/tiny_mce/3.5.12/tiny_mce_popup.js
inc/tiny_mce/3.5.12/utils/editable_selects.js
inc/tiny_mce/3.5.12/utils/form_utils.js
inc/tiny_mce/3.5.12/utils/mctabs.js
inc/tiny_mce/3.5.12/utils/validate.js
inc/treemenu/TreeMenu.php
inc/treemenu/index.htm
inc/zip/Zip.php

@ -6,6 +6,12 @@ stages:
before_script:
- bash ci/docker_install.sh > /dev/null
validate:7.2:
image: php:7.2
stage: validate
script:
- bash ci/php_lint.sh ./
validate:7.1:
image: php:7.1
stage: validate
@ -55,8 +61,8 @@ test:7.1:
- cd Tests
- phpunit
test:7.0:
image: php:7.0
test:7.2:
image: php:7.2
stage: test
script:
- cd api

@ -54,7 +54,15 @@ else {
?>
<div class="content-wrapper">
<section class="content">
<?php hesk_handle_messages(); ?>
<?php
// Service messages
$service_messages = mfh_get_service_messages('STAFF_HOME');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
hesk_handle_messages();
?>
<div class="box">
<div class="box-header with-border">
<h1 class="box-title">

@ -93,19 +93,20 @@ if ($hesk_settings['attachments']['use'] && !defined('HESK_DEMO')) {
$tmp = @ini_get('upload_max_filesize');
if ($tmp) {
$last = strtoupper(substr($tmp, -1));
$number = substr($tmp, 0, -1);
switch ($last) {
case 'K':
$tmp = $tmp * 1024;
$tmp = $number * 1024;
break;
case 'M':
$tmp = $tmp * 1048576;
$tmp = $number * 1048576;
break;
case 'G':
$tmp = $tmp * 1073741824;
$tmp = $number * 1073741824;
break;
default:
$tmp = $tmp;
$tmp = $number;
}
if ($tmp < $hesk_settings['attachments']['max_size']) {
@ -117,19 +118,20 @@ if ($hesk_settings['attachments']['use'] && !defined('HESK_DEMO')) {
$tmp = @ini_get('post_max_size');
if ($tmp) {
$last = strtoupper(substr($tmp, -1));
$number = substr($tmp, 0, -1);
switch ($last) {
case 'K':
$tmp = $tmp * 1024;
$tmp = $number * 1024;
break;
case 'M':
$tmp = $tmp * 1048576;
$tmp = $number * 1048576;
break;
case 'G':
$tmp = $tmp * 1073741824;
$tmp = $number * 1073741824;
break;
default:
$tmp = $tmp;
$tmp = $number;
}
if ($tmp < ($hesk_settings['attachments']['max_size'] * $hesk_settings['attachments']['max_number'] + 524288)) {
@ -2220,6 +2222,106 @@ $modsForHesk_settings = mfh_getSettings();
</select>
</div>
</div>
<div class="form-group">
<label for="show-start-time" class="col-sm-4 col-xs-12 control-label">
<?php echo $hesklang['show_event_start_time']; ?>
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
title="<?php echo $hesklang['show_event_start_time']; ?>"
data-content="<?php echo $hesklang['show_event_start_time_help']; ?>"></i>
</label>
<div class="col-sm-8 form-inline">
<?php
$on = $modsForHesk_settings['calendar_show_start_time'] == 'true' ? 'checked="checked"' : '';
$off = $modsForHesk_settings['calendar_show_start_time'] == 'false' ? 'checked="checked"' : '';
echo '
<div class="radio"><label><input type="radio" name="calendar-show-start-time" value="true" ' . $on . ' /> ' . $hesklang['yes'] . '</label></div><br>
<div class="radio"><label><input type="radio" name="calendar-show-start-time" value="false" ' . $off . ' /> ' . $hesklang['no'] . '</label></div><br>'; ?>
</div>
</div>
<h4 class="bold">
<?php echo $hesklang['business_hours']; ?>
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
title="<?php echo $hesklang['business_hours']; ?>"
data-content="<?php echo $hesklang['business_hours_help']; ?>"></i>
</h4>
<?php
$rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`");
$business_hours = array();
while ($row = hesk_dbFetchAssoc($rs)) {
$business_hours[intval($row['day_of_week'])]['start'] = $row['start_time'];
$business_hours[intval($row['day_of_week'])]['end'] = $row['end_time'];
}
?>
<div class="form-group">
<label for="business-hours-sunday" class="col-sm-4 col-xs-12 control-label">
<?php echo $hesklang['d0']; ?>
</label>
<div class="col-sm-8 col-xs-12 form-inline">
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-sunday[0]" value="<?php echo $business_hours[0]['start']; ?>">
<?php echo $hesklang['to']; ?>
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-sunday[1]" value="<?php echo $business_hours[0]['end']; ?>">
</div>
</div>
<div class="form-group">
<label for="business-hours-monday" class="col-sm-4 col-xs-12 control-label">
<?php echo $hesklang['d1']; ?>
</label>
<div class="col-sm-8 col-xs-12 form-inline">
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-monday[0]" value="<?php echo $business_hours[1]['start']; ?>">
<?php echo $hesklang['to']; ?>
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-monday[1]" value="<?php echo $business_hours[1]['end']; ?>">
</div>
</div>
<div class="form-group">
<label for="business-hours-tuesday" class="col-sm-4 col-xs-12 control-label">
<?php echo $hesklang['d2']; ?>
</label>
<div class="col-sm-8 col-xs-12 form-inline">
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-tuesday[0]" value="<?php echo $business_hours[2]['start']; ?>">
<?php echo $hesklang['to']; ?>
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-tuesday[1]" value="<?php echo $business_hours[2]['end']; ?>">
</div>
</div>
<div class="form-group">
<label for="business-hours-wednesday" class="col-sm-4 col-xs-12 control-label">
<?php echo $hesklang['d3']; ?>
</label>
<div class="col-sm-8 col-xs-12 form-inline">
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-wednesday[0]" value="<?php echo $business_hours[3]['start']; ?>">
<?php echo $hesklang['to']; ?>
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-wednesday[1]" value="<?php echo $business_hours[3]['end']; ?>">
</div>
</div>
<div class="form-group">
<label for="business-hours-thursday" class="col-sm-4 col-xs-12 control-label">
<?php echo $hesklang['d4']; ?>
</label>
<div class="col-sm-8 col-xs-12 form-inline">
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-thursday[0]" value="<?php echo $business_hours[4]['start']; ?>">
<?php echo $hesklang['to']; ?>
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-thursday[1]" value="<?php echo $business_hours[4]['end']; ?>">
</div>
</div>
<div class="form-group">
<label for="business-hours-friday" class="col-sm-4 col-xs-12 control-label">
<?php echo $hesklang['d5']; ?>
</label>
<div class="col-sm-8 col-xs-12 form-inline">
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-friday[0]" value="<?php echo $business_hours[5]['start']; ?>">
<?php echo $hesklang['to']; ?>
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-friday[1]" value="<?php echo $business_hours[5]['end']; ?>">
</div>
</div>
<div class="form-group">
<label for="business-hours-saturday" class="col-sm-4 col-xs-12 control-label">
<?php echo $hesklang['d6']; ?>
</label>
<div class="col-sm-8 col-xs-12 form-inline">
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-saturday[0]" value="<?php echo $business_hours[6]['start']; ?>">
<?php echo $hesklang['to']; ?>
<input type="text" class="form-control clockpicker" data-autoclose="true" name="business-hours-saturday[1]" value="<?php echo $business_hours[6]['end']; ?>">
</div>
</div>
</div>
</div>
@ -3272,6 +3374,27 @@ $modsForHesk_settings = mfh_getSettings();
</div>
</div>
</div>
<div class="form-group">
<label for="show_number_merged" class="col-sm-4 control-label">
<span class="label label-primary"
data-toggle="tooltip"
title="<?php echo $hesklang['added_in_mods_for_hesk'] ?>"><?php echo $hesklang['mods_for_hesk_acronym']; ?></span>
<?php echo $hesklang['highlight_ticket_rows_based_on_priority']; ?>
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
title="<?php echo $hesklang['highlight_ticket_rows_based_on_priority']; ?>"
data-content="<?php echo $hesklang['highlight_ticket_rows_based_on_priority_help']; ?>"></i>
</label>
<div class="col-sm-8">
<div class="checkbox">
<label>
<input type="checkbox"
name="highlight_ticket_rows_based_on_priority" <?php if ($modsForHesk_settings['highlight_ticket_rows_based_on_priority']) {
echo 'checked';
} ?>> <?php echo $hesklang['highlight_ticket_rows_based_on_priority_descr']; ?>
</label>
</div>
</div>
</div>
<div class="form-group">
<label for="s_submittedformat" class="col-sm-4 control-label"><?php echo $hesklang['sdf']; ?> <a
href="Javascript:void(0)"
@ -3387,13 +3510,13 @@ $modsForHesk_settings = mfh_getSettings();
<h4 class="bold"><?php echo $hesklang['other']; ?></h4>
<div class="form-group">
<label for="s_ip_whois" class="col-sm-4 control-label"><?php echo $hesklang['ip_whois']; ?> <a
<label for="s_ip_whois_url" class="col-sm-4 control-label"><?php echo $hesklang['ip_whois']; ?> <a
href="Javascript:void(0)"
onclick="Javascript:hesk_window('<?php echo $help_folder; ?>misc.html#61','400','500')"><i
class="fa fa-question-circle settingsquestionmark"></i></a></label>
<div class="col-sm-8">
<input type="text" class="form-control" name="s_ip_whois" size="40" maxlength="255"
<input type="text" class="form-control" name="s_ip_whois_url" size="40" maxlength="255"
value="<?php echo $hesk_settings['ip_whois']; ?>"/>
</div>
</div>

@ -425,7 +425,7 @@ $set['daylight'] = empty($_POST['s_daylight']) ? 0 : 1;
$set['timeformat'] = hesk_input(hesk_POST('s_timeformat')) or $set['timeformat'] = 'Y-m-d H:i:s';
/* --> Other */
$set['ip_whois'] = hesk_input(hesk_POST('s_ip_whois', 'http://whois.domaintools.com/{IP}'));
$set['ip_whois'] = hesk_input(hesk_POST('s_ip_whois_url', 'http://whois.domaintools.com/{IP}'));
// If no {IP} tag append it to the end
if (strlen($set['ip_whois']) == 0) {
@ -458,6 +458,7 @@ $set['use_bootstrap_theme'] = empty($_POST['use_bootstrap_theme']) ? 0 : 1;
$set['new_kb_article_visibility'] = hesk_checkMinMax(intval(hesk_POST('new_kb_article_visibility')), 0, 2, 2);
$set['mfh_attachments'] = empty($_POST['email_attachments']) ? 0 : 1;
$set['show_number_merged'] = empty($_POST['show_number_merged']) ? 0 : 1;
$set['highlight_ticket_rows_based_on_priority'] = empty($_POST['highlight_ticket_rows_based_on_priority']) ? 0 : 1;
$set['request_location'] = empty($_POST['request_location']) ? 0 : 1;
$set['category_order_column'] = empty($_POST['category_order_column']) ? 'cat_order' : 'name';
@ -480,6 +481,7 @@ $set['navbar_title_url'] = hesk_POST('navbar_title_url');
$set['enable_calendar'] = hesk_checkMinMax(intval(hesk_POST('enable_calendar')), 0, 2, 2);
$set['first_day_of_week'] = hesk_POST('first-day-of-week', 0);
$set['default_view'] = hesk_POST('default-view', 'month');
$set['calendar_show_start_time'] = hesk_POST('calendar-show-start-time', 'true');
if ($set['customer-email-verification-required']) {
//-- Don't allow multiple emails if verification is required
@ -514,6 +516,13 @@ $set['admin_sidebar_text_hover'] = hesk_input(hesk_POST('admin-sidebar-text-hove
$set['login_background_type'] = hesk_input(hesk_POST('login-background'));
$set['login_box_header'] = hesk_input(hesk_POST('login-box-header'));
$set['business_hours_sunday'] = hesk_POST_array('business-hours-sunday');
$set['business_hours_monday'] = hesk_POST_array('business-hours-monday');
$set['business_hours_tuesday'] = hesk_POST_array('business-hours-tuesday');
$set['business_hours_wednesday'] = hesk_POST_array('business-hours-wednesday');
$set['business_hours_thursday'] = hesk_POST_array('business-hours-thursday');
$set['business_hours_friday'] = hesk_POST_array('business-hours-friday');
$set['business_hours_saturday'] = hesk_POST_array('business-hours-saturday');
$changedBackground = false;
$loadedAttachmentFuncs = false;
@ -613,6 +622,7 @@ mfh_updateSetting('use_bootstrap_theme', $set['use_bootstrap_theme']);
mfh_updateSetting('new_kb_article_visibility', $set['new_kb_article_visibility']);
mfh_updateSetting('attachments', $set['mfh_attachments']);
mfh_updateSetting('show_number_merged', $set['show_number_merged']);
mfh_updateSetting('highlight_ticket_rows_based_on_priority', $set['highlight_ticket_rows_based_on_priority']);
mfh_updateSetting('request_location', $set['request_location']);
mfh_updateSetting('category_order_column', $set['category_order_column'], true);
mfh_updateSetting('rich_text_for_tickets', $set['rich_text_for_tickets']);
@ -655,6 +665,7 @@ mfh_updateSetting('use_mailgun', $set['use_mailgun'], false);
mfh_updateSetting('enable_calendar', $set['enable_calendar'], false);
mfh_updateSetting('first_day_of_week', $set['first_day_of_week'], false);
mfh_updateSetting('default_calendar_view', $set['default_view'], true);
mfh_updateSetting('calendar_show_start_time', $set['calendar_show_start_time'], true);
mfh_updateSetting('admin_color_scheme', $set['admin_color_scheme'], true);
mfh_updateSetting('login_background_type', $set['login_background_type'], true);
@ -667,6 +678,29 @@ if ($changedLoginImage) {
mfh_updateSetting('login_box_header_image', $set['login_box_header_image'], true);
}
// Update business hours
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_sunday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_sunday'][1]) . "' WHERE `day_of_week` = " . intval(0));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_monday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_monday'][1]) . "' WHERE `day_of_week` = " . intval(1));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_tuesday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_tuesday'][1]) . "' WHERE `day_of_week` = " . intval(2));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_wednesday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_wednesday'][1]) . "' WHERE `day_of_week` = " . intval(3));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_thursday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_thursday'][1]) . "' WHERE `day_of_week` = " . intval(4));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_friday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_friday'][1]) . "' WHERE `day_of_week` = " . intval(5));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_saturday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_saturday'][1]) . "' WHERE `day_of_week` = " . intval(6));
// Prepare settings file and save it
$settings_file_content = '<?php
// Settings file for HESK ' . $set['hesk_version'] . '

@ -939,6 +939,11 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
/* This will handle error, success and notice messages */
hesk_handle_messages();
$service_messages = mfh_get_service_messages('STAFF_VIEW_TICKET');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
// Prepare special custom fields
foreach ($hesk_settings['custom_fields'] as $k=>$v) {
if ($v['use'] && hesk_is_custom_field_in_category($k, $ticket['category']) ) {
@ -1188,9 +1193,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
echo '
<a href="../download_attachment.php?att_id=' . $att_id . '&amp;track=' . $trackingID . '">
<i class="fa fa-paperclip" style="font-size:16px;" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['dnl'] . ' ' . $att_name . '"></i>
<i class="fa fa-paperclip" style="font-size:16px;" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['dnl'] . '"></i>
</a>
<a href="../download_attachment.php?att_id=' . $att_id . '&amp;track=' . $trackingID . '">' . $att_name . '</a><br />
<a href="../download_attachment.php?att_id=' . $att_id . '&amp;track=' . $trackingID . '">' . $att_name . ' (' . mfh_getAttachmentFileSize($att_id) . ')' . '</a><br />
';
}
}

@ -282,10 +282,10 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
<div class="col-sm-4">
<select name="reminder-unit" class="form-control">
<option value="0"><?php echo $hesklang['event_min_before_event']; ?></option>
<option value="1"><?php echo $hesklang['event_hours_before_event']; ?></option>
<option value="2"><?php echo $hesklang['event_days_before_event']; ?></option>
<option value="3"><?php echo $hesklang['event_weeks_before_event']; ?></option>
<option value="MINUTE"><?php echo $hesklang['event_min_before_event']; ?></option>
<option value="HOUR"><?php echo $hesklang['event_hours_before_event']; ?></option>
<option value="DAY"><?php echo $hesklang['event_days_before_event']; ?></option>
<option value="WEEK"><?php echo $hesklang['event_weeks_before_event']; ?></option>
</select>
</div>
</div>
@ -334,147 +334,168 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
<form id="edit-form" class="form-horizontal" data-toggle="validator">
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="name" class="col-sm-3 control-label">
<?php echo $hesklang['event_title']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_title_tooltip']); ?>"></i></label>
<div class="col-sm-9">
<input type="text" name="name" class="form-control"
placeholder="<?php echo htmlspecialchars($hesklang['event_title']); ?>"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<div class="help-block with-errors"></div>
</div>
</div>
<div class="form-group">
<label for="location" class="col-sm-3 control-label">
<?php echo $hesklang['event_location']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_location_tooltip']); ?>"></i>
</label>
<div class="col-sm-9">
<input type="text" name="location" class="form-control"
placeholder="<?php echo htmlspecialchars($hesklang['event_location']); ?>">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="form-group">
<label for="category" class="col-sm-3 control-label">
<?php echo $hesklang['category']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_category_tooltip']); ?>"></i>
</label>
<div class="col-sm-9">
<select name="category" class="form-control"
pattern="[0-9]+"
data-error="<?php echo htmlspecialchars($hesklang['sel_app_cat']); ?>" required>
<?php
if ($hesk_settings['select_cat']) {
echo '<option value="">'.$hesklang['select'].'</option>';
}
foreach ($categories as $category): ?>
<option value="<?php echo $category['id']; ?>" data-background-color="<?php echo htmlspecialchars($category['background_color']); ?>"
data-foreground-color="<?php echo htmlspecialchars($category['foreground_color']); ?>"
data-display-border="<?php echo htmlspecialchars($category['display_border_outline']); ?>">
<?php echo $category['name']; ?>
</option>
<?php endforeach; ?>
</select>
<div class="help-block with-errors"></div>
<ul class="nav nav-tabs" role="tablist" id="edit-modal-tabs">
<li role="presentation" class="active"><a href="#edit-contents" aria-controls="home" role="tab" data-toggle="tab"><?php echo $hesklang['information']; ?></a></li>
<li role="presentation"><a href="#edit-history" aria-controls="profile" role="tab" data-toggle="tab"><?php echo $hesklang['thist']; ?></a></li>
</ul>
<div class="tab-content" id="information-tab">
<div role="tabpanel" class="tab-pane active" id="edit-contents">
<br>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="name" class="col-sm-3 control-label">
<?php echo $hesklang['event_title']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_title_tooltip']); ?>"></i></label>
<div class="col-sm-9">
<input type="text" name="name" class="form-control"
placeholder="<?php echo htmlspecialchars($hesklang['event_title']); ?>"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<div class="help-block with-errors"></div>
</div>
</div>
<div class="form-group">
<label for="location" class="col-sm-3 control-label">
<?php echo $hesklang['event_location']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_location_tooltip']); ?>"></i>
</label>
<div class="col-sm-9">
<input type="text" name="location" class="form-control"
placeholder="<?php echo htmlspecialchars($hesklang['event_location']); ?>">
<div class="help-block with-errors"></div>
</div>
</div>
<div class="form-group">
<label for="category" class="col-sm-3 control-label">
<?php echo $hesklang['category']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_category_tooltip']); ?>"></i>
</label>
<div class="col-sm-9">
<select name="category" class="form-control"
pattern="[0-9]+"
data-error="<?php echo htmlspecialchars($hesklang['sel_app_cat']); ?>" required>
<?php
if ($hesk_settings['select_cat']) {
echo '<option value="">'.$hesklang['select'].'</option>';
}
foreach ($categories as $category): ?>
<option value="<?php echo $category['id']; ?>" data-background-color="<?php echo htmlspecialchars($category['background_color']); ?>"
data-foreground-color="<?php echo htmlspecialchars($category['foreground_color']); ?>"
data-display-border="<?php echo htmlspecialchars($category['display_border_outline']); ?>">
<?php echo $category['name']; ?>
</option>
<?php endforeach; ?>
</select>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="start-date" class="col-sm-6 control-label">
<?php echo $hesklang['event_start']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_start_tooltip']); ?>"></i>
</label>
<div class="col-sm-6">
<input type="text" name="start-date" class="form-control datepicker"
placeholder="<?php echo htmlspecialchars($hesklang['event_start_date']); ?>"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<input type="text" name="start-time" class="form-control clockpicker"
placeholder="<?php echo htmlspecialchars($hesklang['event_start_time']); ?>"
data-placement="left" data-align="top" data-autoclose="true">
<div class="help-block with-errors"></div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="start-date" class="col-sm-6 control-label">
<?php echo $hesklang['event_start']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_start_tooltip']); ?>"></i>
</label>
<div class="col-sm-6">
<input type="text" name="start-date" class="form-control datepicker"
placeholder="<?php echo htmlspecialchars($hesklang['event_start_date']); ?>"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<input type="text" name="start-time" class="form-control clockpicker"
placeholder="<?php echo htmlspecialchars($hesklang['event_start_time']); ?>"
data-placement="left" data-align="top" data-autoclose="true">
<div class="help-block with-errors"></div>
<div class="checkbox">
<label>
<input type="checkbox" name="all-day"> <?php echo $hesklang['event_all_day']; ?>
<div class="checkbox">
<label>
<input type="checkbox" name="all-day"> <?php echo $hesklang['event_all_day']; ?>
</label>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="end-date" class="col-sm-6 control-label">
<?php echo $hesklang['event_end']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_end_tooltip']); ?>"></i>
</label>
<div class="col-sm-6">
<input type="text" name="end-date" class="form-control datepicker"
placeholder="<?php echo htmlspecialchars($hesklang['event_end_date']); ?>"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<input type="text" name="end-time" class="form-control clockpicker"
data-placement="left" data-align="top" data-autoclose="true"
placeholder="<?php echo htmlspecialchars($hesklang['event_end_time']); ?>">
<div class="help-block with-errors"></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="end-date" class="col-sm-6 control-label">
<?php echo $hesklang['event_end']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_end_tooltip']); ?>"></i>
</label>
<div class="col-sm-6">
<input type="text" name="end-date" class="form-control datepicker"
placeholder="<?php echo htmlspecialchars($hesklang['event_end_date']); ?>"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<input type="text" name="end-time" class="form-control clockpicker"
data-placement="left" data-align="top" data-autoclose="true"
placeholder="<?php echo htmlspecialchars($hesklang['event_end_time']); ?>">
<div class="help-block with-errors"></div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="reminder" class="col-sm-3 control-label">
<?php echo $hesklang['event_reminder']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_reminder_tooltip']); ?>"></i>
</label>
<div class="col-sm-2">
<input type="text" name="reminder-value" class="form-control" placeholder="#">
</div>
<div class="col-sm-4">
<select name="reminder-unit" class="form-control">
<option value="MINUTE"><?php echo $hesklang['event_min_before_event']; ?></option>
<option value="HOUR"><?php echo $hesklang['event_hours_before_event']; ?></option>
<option value="DAY"><?php echo $hesklang['event_days_before_event']; ?></option>
<option value="WEEK"><?php echo $hesklang['event_weeks_before_event']; ?></option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="reminder" class="col-sm-3 control-label">
<?php echo $hesklang['event_reminder']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_reminder_tooltip']); ?>"></i>
</label>
<div class="col-sm-2">
<input type="text" name="reminder-value" class="form-control" placeholder="#">
</div>
<div class="col-sm-4">
<select name="reminder-unit" class="form-control">
<option value="0"><?php echo $hesklang['event_min_before_event']; ?></option>
<option value="1"><?php echo $hesklang['event_hours_before_event']; ?></option>
<option value="2"><?php echo $hesklang['event_days_before_event']; ?></option>
<option value="3"><?php echo $hesklang['event_weeks_before_event']; ?></option>
</select>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="comments" class="col-sm-3 control-label">
<?php echo $hesklang['event_comments']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_comments_tooltip']); ?>"></i>
</label>
<div class="col-sm-9">
<textarea name="comments" class="form-control" placeholder="<?php echo htmlspecialchars($hesklang['event_comments']); ?>"></textarea>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="comments" class="col-sm-3 control-label">
<?php echo $hesklang['event_comments']; ?>
<i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_comments_tooltip']); ?>"></i>
</label>
<div class="col-sm-9">
<textarea name="comments" class="form-control" placeholder="<?php echo htmlspecialchars($hesklang['event_comments']); ?>"></textarea>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="edit-history">
<br>
<table class="table table-striped">
<thead>
<tr>
<th><?php echo $hesklang['date']; ?></th>
<th><?php echo $hesklang['description']; ?></th>
</tr>
</thead>
<tbody id="history-table"></tbody>
</table>
</div>
</div>
</div>
@ -545,22 +566,34 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<strong><?php echo $hesklang['category']; ?></strong>
<span></span>
</div>
<div class="popover-status">
<strong><?php echo $hesklang['status']; ?></strong>
<span></span>
</div>
<div class="popover-priority">
<strong><?php echo $hesklang['priority']; ?></strong>
<span></span>
</div>
</div>
</div>
<?php
echo mfh_get_hidden_fields_for_language(array('error_loading_events',
'error_deleting_event',
'event_deleted',
'event_created',
'error_creating_event',
'event_updated',
'error_updating_event',
'ticket_due_date_updated',
'error_updating_ticket_due_date',
'critical',
'high',
'medium',
'low',
'audit_event_created',
'audit_event_updated'));
?>
<div style="display: none">
<p id="lang_error_loading_events"><?php echo $hesklang['error_loading_events']; ?></p>
<p id="lang_error_deleting_event"><?php echo $hesklang['error_deleting_event']; ?></p>
<p id="lang_event_deleted"><?php echo $hesklang['event_deleted']; ?></p>
<p id="lang_event_created"><?php echo $hesklang['event_created']; ?></p>
<p id="lang_error_creating_event"><?php echo $hesklang['error_creating_event']; ?></p>
<p id="lang_event_updated"><?php echo $hesklang['event_updated']; ?></p>
<p id="lang_error_updating_event"><?php echo $hesklang['error_updating_event']; ?></p>
<p id="lang_ticket_due_date_updated"><?php echo $hesklang['ticket_due_date_updated']; ?></p>
<p id="lang_error_updating_ticket_due_date"><?php echo $hesklang['error_updating_ticket_due_date']; ?></p>
<p id="setting_first_day_of_week"><?php echo $modsForHesk_settings['first_day_of_week']; ?></p>
<p id="setting_default_view">
<?php
@ -572,7 +605,21 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
echo $view_array[$_SESSION['default_calendar_view']];
?>
</p>
<p id="setting_show_start_time"><?php echo $modsForHesk_settings['calendar_show_start_time']; ?></p>
<?php
$businessHoursRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`");
while ($row = hesk_dbFetchAssoc($businessHoursRs)):
?>
<p id="business_hours_<?php echo $row['day_of_week']; ?>_start"><?php echo $row['start_time']; ?></p>
<p id="business_hours_<?php echo $row['day_of_week']; ?>_end"><?php echo $row['end_time']; ?></p>
<?php endwhile; ?>
</div>
<script type="text/html" id="audit-trail-template">
<tr>
<td data-property="date"></td>
<td data-property="description"></td>
</tr>
</script>
<?php
require_once(HESK_PATH . 'inc/footer.inc.php');

@ -519,7 +519,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<?php echo $hesklang['email_custom_field_label']; ?>
</label>
<div class="col-sm-8">
<?php $address_type = empty($value['email_type']) ? 'none' : $value['email_type']; ?>
<?php
$address_type = empty($value['email_type']) ? 'none' : $value['email_type'];
?>
<div class="radio">
<label>
<input type="radio" name="email_type" value="none"

@ -577,9 +577,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
case 'hidden':
case 'readonly':
default:
if (strlen($k_value) != 0) {
$v['value']['default_value'] = $k_value;
}
$k_value = hesk_msgToPlain($k_value,0,0);
$cls = in_array($k, $_SESSION['iserror']) ? ' isError' : '';
@ -587,7 +585,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<div class="form-group' . $cls . '">
<label for="' . $k . '" class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="' . $k . '" size="40" maxlength="' . intval($v['value']['max_length']) . '" value="' . $v['value']['default_value'] . '" ' . $required_attribute . '>';
<input type="text" class="form-control" name="' . $k . '" size="40" maxlength="' . intval($v['value']['max_length']) . '" value="' . $k_value . '" ' . $required_attribute . '>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
@ -646,16 +644,20 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
}
?>
</div>
<div class="form-group" style="text-align: center">
<?php
$html = $ticket['html'] ? 1 : 0;
?>
<input type="hidden" name="html" value="<?php echo $html; ?>">
<input type="submit" value="<?php echo $hesklang['save_changes']; ?>" class="btn btn-default">
<?php if (isset($_REQUEST['isManager']) && $_REQUEST['isManager']): ?>
<input type="hidden" name="isManager" value="1">
<?php endif; ?>
<a class="btn btn-default" href="javascript:history.go(-1)"><?php echo $hesklang['back']; ?></a>
<div class="form-group">
<div class="col-md-9 col-md-offset-3">
<?php
$html = $ticket['html'] ? 1 : 0;
?>
<input type="hidden" name="html" value="<?php echo $html; ?>">
<div class="btn-group">
<input type="submit" value="<?php echo $hesklang['save_changes']; ?>" class="btn btn-primary">
<a class="btn btn-default" href="javascript:history.go(-1)"><?php echo $hesklang['back']; ?></a>
</div>
<?php if (isset($_REQUEST['isManager']) && $_REQUEST['isManager']): ?>
<input type="hidden" name="isManager" value="1">
<?php endif; ?>
</div>
</div>
</form>
</div>

@ -291,7 +291,7 @@ $orderBy = $modsForHesk_settings['category_order_column'];
$res2 = hesk_dbQuery("SELECT `id`, `name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE " . hesk_myCategories('id') . " ORDER BY `" . $orderBy . "` ASC");
while ($row = hesk_dbFetchAssoc($res2)) {
$my_cat[$row['id']] = hesk_msgToPlain($row['name'], 1);
$row['name'] = (strlen($row['name']) > 50) ? substr($row['name'], 0, 50) . '...' : $row['name'];
$row['name'] = (hesk_mb_strlen($row['name']) > 50) ? hesk_mb_substr($row['name'],0,50) . '...' : $row['name'];
$cat_selected = ($row['id'] == $category) ? 'selected="selected"' : '';
$category_options .= '<option value="' . $row['id'] . '" ' . $cat_selected . '>' . $row['name'] . '</option>';
}

@ -278,6 +278,12 @@ function print_login()
<?php
/* This will handle error, success and notice messages */
hesk_handle_messages();
// Service messages
$service_messages = mfh_get_service_messages('STAFF_LOGIN');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
?>
</div>
<div class="login-logo">
@ -469,6 +475,9 @@ function print_login()
</div>
</div>
</form>
<a class="btn btn-default" href="<?php echo $hesk_settings['hesk_url']; ?>">
<i class="fa fa-chevron-left"></i> <?php echo $hesklang['back']; ?>
</a>
</div>
</div>
</div>

@ -121,7 +121,9 @@ function hesk_kb_header($kb_link, $catid=1)
</ol>
<?php
show_subnav('view', $catid);
echo '<div style="margin-left:40px;margin-right:40px">';
hesk_kbSearchLarge(1);
echo '</div>';
} // END hesk_kb_header()
@ -214,7 +216,15 @@ function hesk_show_kb_article($artid)
?>
<div class="content-wrapper">
<?php hesk_kb_header($hesk_settings['kb_link'], $article['catid']); ?>
<?php
hesk_kb_header($hesk_settings['kb_link'], $article['catid']);
echo '<div style="margin-left:40px;margin-right:40px">';
$service_messages = mfh_get_service_messages('STAFF_VIEW_KB_ARTICLE');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
echo '</div>';
?>
<section class="content">
<div class="box">
<div class="box-header with-border">
@ -397,6 +407,13 @@ function hesk_show_kb_category($catid, $is_search = 0) {
{
/* Print header */
hesk_kb_header($hesk_settings['kb_link'], $catid);
echo '<div style="margin-left:40px;margin-right:40px">';
$service_messages = mfh_get_service_messages('STAFF_KB_HOME');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
echo '</div>';
} ?>
<section class="content">
<?php if ($thiscat['parent']): ?>

@ -32,7 +32,7 @@ $modsForHesk_settings = mfh_getSettings();
/* List of staff */
$admins = array();
$res = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` ORDER BY `name` ASC");
$res = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` WHERE `active` = '1' ORDER BY `name` ASC");
while ($row = hesk_dbFetchAssoc($res)) {
$admins[$row['id']] = $row['name'];
}

@ -212,7 +212,8 @@ while (count($kb_cat) > 0)
if (isset($node[$up]))
{
$node[$my] = &$node[$up]->addItem(new HTML_TreeNode(array('hesk_selected' => $selected, 'text' => $text, 'text_short' => $text_short, 'menu_icons' => $menu_icons, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true)));
$HTML_TreeNode[$my] = new HTML_TreeNode(array('hesk_selected' => $selected, 'text' => $text, 'text_short' => $text_short, 'menu_icons' => $menu_icons, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true));
$node[$my] = &$node[$up]->addItem($HTML_TreeNode[$my]);
}
else
{
@ -242,8 +243,11 @@ while (count($kb_cat) > 0)
$menu->addItem($node[1]);
// Create the presentation class
$treeMenu = & ref_new(new HTML_TreeMenu_DHTML($menu, array('images' => '../img', 'defaultClass' => 'treeMenuDefault', 'isDynamic' => true)));
$listBox = & ref_new(new HTML_TreeMenu_Listbox($menu));
$HTML_TreeMenu_DHTML = new HTML_TreeMenu_DHTML($menu, array('images' => '../img', 'defaultClass' => 'treeMenuDefault', 'isDynamic' => true));
$treeMenu = & ref_new($HTML_TreeMenu_DHTML);
$HTML_TreeMenu_Listbox = new HTML_TreeMenu_Listbox($menu);
$listBox = & ref_new($HTML_TreeMenu_Listbox);
/* Hide new article and new category forms by default */
if (!isset($_SESSION['hide']))
@ -270,6 +274,12 @@ if (!isset($_SESSION['hide']['treemenu']))
<?php
show_subnav();
// Service messages
$service_messages = mfh_get_service_messages('STAFF_KB_HOME');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
// Show a notice if total public articles is less than 5
if ($total_articles < 5)
{
@ -1347,7 +1357,8 @@ function edit_article()
if (isset($node[$up]))
{
$node[$my] = &$node[$up]->addItem(new HTML_TreeNode(array('hesk_parent' => $this_cat['parent'], 'text' => 'Text', 'text_short' => $text_short, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true)));
$HTML_TreeNode[$my] = new HTML_TreeNode(array('hesk_parent' => $this_cat['parent'], 'text' => 'Text', 'text_short' => $text_short, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true));
$node[$my] = &$node[$up]->addItem($HTML_TreeNode[$my]);
}
else
{
@ -1377,7 +1388,8 @@ function edit_article()
$menu->addItem($node[1]);
// Create the presentation class
$listBox = & ref_new(new HTML_TreeMenu_Listbox($menu));
$HTML_TreeMenu_Listbox = new HTML_TreeMenu_Listbox($menu);
$listBox = & ref_new($HTML_TreeMenu_Listbox);
/* Print header */
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
@ -1604,6 +1616,9 @@ function manage_category() {
foreach ($kb_cat as $k=>$cat)
{
if ($cat['id'] == $catid) {
continue;
}
if (in_array($cat['parent'],$thislevel))
{
@ -1616,7 +1631,8 @@ function manage_category() {
if (isset($node[$up]))
{
$node[$my] = &$node[$up]->addItem(new HTML_TreeNode(array('hesk_parent' => $this_cat['parent'], 'text' => 'Text', 'text_short' => $text_short, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true)));
$HTML_TreeNode[$my] = new HTML_TreeNode(array('hesk_parent' => $this_cat['parent'], 'text' => 'Text', 'text_short' => $text_short, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true));
$node[$my] = &$node[$up]->addItem($HTML_TreeNode[$my]);
}
else
{
@ -1646,7 +1662,8 @@ function manage_category() {
$menu->addItem($node[1]);
// Create the presentation class
$listBox = & ref_new(new HTML_TreeMenu_Listbox($menu));
$HTML_TreeMenu_Listbox = new HTML_TreeMenu_Listbox($menu);
$listBox = & ref_new($HTML_TreeMenu_Listbox);
/* Print header */
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');

@ -80,14 +80,19 @@ while ($row = hesk_dbFetchAssoc($res)) {
</div>
</div>
<div class="box-body">
<a href="#" data-toggle="modal" data-target="#modal-template-new" class="btn btn-success nu-floatRight">
<i class="fa fa-plus-circle"></i> <?php echo $hesklang['create_new_group']; ?>
</a>
<div class="text-right">
<a href="#" data-toggle="modal" data-target="#modal-template-new" class="btn btn-success nu-floatRight">
<i class="fa fa-plus-circle"></i> <?php echo $hesklang['create_new']; ?>
</a>
</div>
<table class="table table-striped">
<thead>
<th><?php echo $hesklang['name']; ?></th>
<th><?php echo $hesklang['number_of_users']; ?></th>
<th><?php echo $hesklang['actions']; ?></th>
<tr>
<th><?php echo $hesklang['name']; ?></th>
<th><?php echo $hesklang['number_of_users']; ?></th>
<th><?php echo $hesklang['actions']; ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($templates as $row): ?>
@ -96,13 +101,13 @@ while ($row = hesk_dbFetchAssoc($res)) {
<td><?php echo getNumberOfUsersWithPermissionGroup($row['id']); ?></td>
<td>
<a href="#" data-toggle="modal" data-target="#modal-template-<?php echo $row['id'] ?>">
<i class="fa fa-pencil icon-link" data-toggle="tooltip"
<i class="fa fa-fw fa-pencil icon-link orange" data-toggle="tooltip"
title="<?php echo $hesklang['view_permissions_for_this_group'] ?>"></i></a>
<?php
if ($row['id'] != 1 && $row['id'] != 2):
?>
<a href="manage_permission_groups.php?a=delete&amp;id=<?php echo $row['id']; ?>">
<i class="fa fa-times icon-link red" data-toggle="tooltip"
<i class="fa fa-fw fa-times icon-link red" data-toggle="tooltip"
title="<?php echo $hesklang['delete']; ?>"></i></a>
<?php endif; ?>
</td>
@ -137,11 +142,9 @@ function createEditModal($template, $features, $categories)
{
global $hesklang;
$disabled = 'checked="checked" disabled';
$enabledFeatures = array();
$enabledCategories = array();
if ($template['heskprivileges'] != 'ALL') {
$disabled = '';
if ($template['heskprivileges'] !== 'ALL') {
$enabledFeatures = explode(',', $template['heskprivileges']);
$enabledCategories = explode(',', $template['categories']);
}
@ -157,6 +160,12 @@ function createEditModal($template, $features, $categories)
<h4 class="modal-title"><?php echo sprintf($hesklang['permissions_for_group'], $template['name']); ?></h4>
</div>
<div class="modal-body">
<?php if ($template['id'] == 1): ?>
<div class="alert alert-info">
<i class="fa fa-info-circle"></i>
<?php echo $hesklang['protected_group']; ?>
</div>
<?php endif; ?>
<div class="row">
<div class="form-group">
<div class="col-sm-2">
@ -179,20 +188,32 @@ function createEditModal($template, $features, $categories)
<div class="footerWithBorder blankSpace"></div>
<div class="form-group">
<?php foreach ($categories as $category): ?>
<?php
foreach ($categories as $category): ?>
<?php
$checked = '';
$disabled = '';
if (in_array($category['id'], $enabledCategories) ||
$template['categories'] == 'ALL') {
$checked = 'checked ';
}
if ((!hesk_SESSION('isadmin') &&
!in_array($category['id'], $_SESSION['categories'])) ||
$template['categories'] === 'ALL') {
$disabled = ' disabled';
}?>
<?php if ($_SESSION['isadmin'] || in_array($category['id'], $_SESSION['categories']) || $checked): ?>
<div class="checkbox">
<label>
<?php
$checked = '';
if (in_array($category['id'], $enabledCategories)) {
$checked = 'checked';
} ?>
<input type="checkbox" name="categories[]"
value="<?php echo $category['id']; ?>" <?php echo $checked . $disabled; ?>>
value="<?php echo $category['id']; ?>" <?php echo $checked . ' ' . $disabled; ?>>
<?php echo $category['name']; ?>
</label>
</div>
<?php endforeach; ?>
<?php
endif;
endforeach; ?>
<div class="help-block with-errors"></div>
</div>
</div>
@ -201,19 +222,30 @@ function createEditModal($template, $features, $categories)
<div class="footerWithBorder blankSpace"></div>
<div class="form-group">
<?php foreach ($features as $feature): ?>
<?php
foreach ($features as $feature): ?>
<?php
$checked = '';
$disabled = '';
if (in_array($feature, $enabledFeatures) ||
$template['heskprivileges'] === 'ALL') {
$checked = 'checked ';
}
if ((!hesk_SESSION('isadmin') &&
strpos($_SESSION['heskprivileges'], $feature) === false) ||
$template['heskprivileges'] === 'ALL') {
$disabled = ' disabled';
}
if ($_SESSION['isadmin'] || strpos($_SESSION['heskprivileges'], $feature) !== false || $checked): ?>
<div class="checkbox">
<label><?php
$checked = '';
if (in_array($feature, $enabledFeatures)) {
$checked = 'checked';
} ?>
<label>
<input type="checkbox" name="features[]"
value="<?php echo $feature; ?>" <?php echo $checked . $disabled; ?>>
<?php echo $hesklang[$feature]; ?>
</label>
</div>
<?php endforeach; ?>
<?php endif;
endforeach; ?>
<div class="help-block with-errors"></div>
</div>
</div>
@ -270,7 +302,9 @@ function buildCreateModal($features, $categories)
<div class="footerWithBorder blankSpace"></div>
<div class="form-group">
<?php foreach ($categories as $category): ?>
<?php
foreach ($categories as $category):
if (hesk_SESSION('isadmin') || in_array($category['id'], $_SESSION['categories'])): ?>
<div class="checkbox">
<label>
<input type="checkbox" name="categories[]"
@ -280,7 +314,7 @@ function buildCreateModal($features, $categories)
<?php echo $category['name']; ?>
</label>
</div>
<?php endforeach; ?>
<?php endif; endforeach; ?>
<div class="help-block with-errors"></div>
</div>
</div>
@ -289,7 +323,9 @@ function buildCreateModal($features, $categories)
<div class="footerWithBorder blankSpace"></div>
<div class="form-group">
<?php foreach ($features as $feature): ?>
<?php foreach ($features as $feature):
if (strpos($_SESSION['heskprivileges'], $feature) !== false || hesk_SESSION('isadmin')):
?>
<div class="checkbox">
<label>
<input type="checkbox" name="features[]"
@ -299,7 +335,7 @@ function buildCreateModal($features, $categories)
<?php echo $hesklang[$feature]; ?>
</label>
</div>
<?php endforeach; ?>
<?php endif; endforeach; ?>
<div class="help-block with-errors"></div>
</div>
</div>
@ -334,7 +370,6 @@ function save()
WHERE `id` = " . intval($templateId));
$row = hesk_dbFetchAssoc($res);
// Add 'can ban emails' if 'can unban emails' is set (but not added). Same with 'can ban ips'
$catArray = hesk_POST_array('categories');
$featArray = hesk_POST_array('features');
@ -349,6 +384,41 @@ function save()
$features = implode(',', $featArray);
$name = hesk_POST('name');
// Only allow users to add what they are allowed to add
// Admins can handle anything
if (!$_SESSION['isadmin']) {
// Update categories based on user visibility
$originalCategories = explode(',', $row['categories']);
$newCategories = array();
foreach ($originalCategories as $innerCategory) {
if (in_array($innerCategory, $catArray) && in_array($innerCategory, $_SESSION['categories'])) {
$newCategories[] = $innerCategory;
} elseif (!in_array($innerCategory, $catArray) && !in_array($innerCategory, $_SESSION['categories'])) {
// The user can't modify this, so keep it in
$newCategories[] = $innerCategory;
}
// If neither, the user removed it.
}
// Update features based on user visibility
$originalFeatures = explode(',', $row['heskprivileges']);
$newFeatures = array();
foreach ($originalFeatures as $innerFeature) {
if (in_array($innerFeature, $featArray) && strpos($_SESSION['heskprivileges'], $innerFeature) !== false) {
$newFeatures[] = $innerFeature;
} elseif (!in_array($innerFeature, $featArray) && strpos($_SESSION['heskprivileges'], $innerFeature) === false) {
// The user can't modify this, so keep it in
$newFeatures[] = $innerFeature;
}
// If neither, the user removed it.
}
$categories = implode(',', $newCategories);
$features = implode(',', $newFeatures);
}
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates`
SET `categories` = '" . hesk_dbEscape($categories) . "', `heskprivileges` = '" . hesk_dbEscape($features) . "',
`name` = '" . hesk_dbEscape($name) . "'

@ -736,7 +736,7 @@ function hesk_validateUserInfo($pass_required = 1, $redirect_to = './manage_user
}
}
if (strlen($myuser['signature']) > 1000) {
if (hesk_mb_strlen($myuser['signature']) > 1000) {
$hesk_error_buffer .= '<li>' . $hesklang['signature_long'] . '</li>';
}

@ -157,6 +157,11 @@ $show_quick_help = $show['show'];
/* This will handle error, success and notice messages */
hesk_handle_messages();
$service_messages = mfh_get_service_messages('STAFF_SUBMIT_TICKET');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
if ($show_quick_help): ?>
<div class="box">
<div class="box-header with-border">

@ -170,7 +170,7 @@ function update_profile()
$_SESSION['new']['signature'] = hesk_input(hesk_POST('signature'));
/* Signature */
if (strlen($_SESSION['new']['signature']) > 1000) {
if (hesk_mb_strlen($_SESSION['new']['signature']) > 1000) {
$hesk_error_buffer .= '<li>' . $hesklang['signature_long'] . '</li>';
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,22 @@
<?php
namespace BusinessLogic\Calendar;
class AbstractEvent {
public $id;
public $startTime;
public $title;
public $categoryId;
public $categoryName;
public $backgroundColor;
public $foregroundColor;
public $displayBorder;
}

@ -0,0 +1,15 @@
<?php
namespace BusinessLogic\Calendar;
class BusinessHours {
/* @var $dayOfWeek int */
public $dayOfWeek;
/* @var $startTime string */
public $startTime;
/* @var $endTime string */
public $endTime;
}

@ -0,0 +1,26 @@
<?php
namespace BusinessLogic\Calendar;
use BusinessLogic\Tickets\AuditTrail;
class CalendarEvent extends AbstractEvent {
public $type = 'CALENDAR';
public $endTime;
/* @var $allDay bool */
public $allDay;
public $location;
public $comments;
public $reminderValue;
public $reminderUnits;
/* @var $auditTrail AuditTrail[] */
public $auditTrail = array();
}

@ -0,0 +1,96 @@
<?php
namespace BusinessLogic\Calendar;
use BusinessLogic\DateTimeHelpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Tickets\AuditTrailEntityType;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\Calendar\CalendarGateway;
class CalendarHandler extends \BaseClass {
private $calendarGateway;
private $auditTrailGateway;
public function __construct(CalendarGateway $calendarGateway,
AuditTrailGateway $auditTrailGateway) {
$this->calendarGateway = $calendarGateway;
$this->auditTrailGateway = $auditTrailGateway;
}
public function getEventsForStaff($searchEventsFilter, $heskSettings) {
return $this->calendarGateway->getEventsForStaff($searchEventsFilter, $heskSettings);
}
/**
* @param $calendarEvent CalendarEvent
* @param $userContext UserContext
* @param $heskSettings array
* @return CalendarEvent
* @throws \Exception If more than one event is returned for the given ID
*/
public function updateEvent($calendarEvent, $userContext, $heskSettings) {
$this->calendarGateway->updateEvent($calendarEvent, $userContext, $heskSettings);
$this->auditTrailGateway->insertAuditTrailRecord($calendarEvent->id,
AuditTrailEntityType::CALENDAR_EVENT,
'audit_event_updated',
DateTimeHelpers::heskDate($heskSettings),
array(0 => $userContext->name . ' (' . $userContext->username . ')'), $heskSettings);
$eventFilter = new SearchEventsFilter();
$eventFilter->eventId = $calendarEvent->id;
$eventFilter->reminderUserId = $userContext->id;
$events = $this->calendarGateway->getEventsForStaff($eventFilter, $heskSettings);
if (count($events) !== 1) {
throw new \Exception("Expected exactly 1 event, found: " . count($events));
}
$event = $events[0];
return $event;
}
/**
* @param $calendarEvent CalendarEvent
* @param $userContext UserContext
* @param $heskSettings array
* @return AbstractEvent
* @throws \Exception
*/
public function createEvent($calendarEvent, $userContext, $heskSettings) {
$this->calendarGateway->createEvent($calendarEvent, $userContext, $heskSettings);
$eventFilter = new SearchEventsFilter();
$eventFilter->eventId = $calendarEvent->id;
$eventFilter->reminderUserId = $userContext->id;
$events = $this->calendarGateway->getEventsForStaff($eventFilter, $heskSettings);
if (count($events) !== 1) {
throw new \Exception("Expected exactly 1 event, found: " . count($events));
}
$event = $events[0];
$this->auditTrailGateway->insertAuditTrailRecord($event->id,
AuditTrailEntityType::CALENDAR_EVENT,
'audit_event_created',
DateTimeHelpers::heskDate($heskSettings),
array(0 => $userContext->name . ' (' . $userContext->username . ')'), $heskSettings);
return $event;
}
public function deleteEvent($id, $userContext, $heskSettings) {
$this->calendarGateway->deleteEvent($id, $userContext, $heskSettings);
}
public function getBusinessHours($heskSettings) {
return $this->calendarGateway->getBusinessHours($heskSettings);
}
}

@ -0,0 +1,41 @@
<?php
namespace BusinessLogic\Calendar;
class ReminderUnit {
const MINUTE = 0;
const HOUR = 1;
const DAY = 2;
const WEEK = 3;
static function getByValue($value) {
switch ($value) {
case 0:
return 'MINUTE';
case 1:
return 'HOUR';
case 2:
return 'DAY';
case 3:
return 'WEEK';
default:
return 'UNKNOWN';
}
}
static function getByName($name) {
switch ($name) {
case 'MINUTE':
return self::MINUTE;
case 'HOUR':
return self::HOUR;
case 'DAY':
return self::DAY;
case 'WEEK':
return self::WEEK;
default:
return null;
}
}
}

@ -0,0 +1,30 @@
<?php
namespace BusinessLogic\Calendar;
class SearchEventsFilter {
/* @var $startTime int|null */
public $startTime;
/* @var $endTime int|null */
public $endTime;
/* @var $id int|null */
public $eventId;
/* @var $categories int[]|null */
public $categories;
/* @var $reminderUserId int|null */
public $reminderUserId;
/* @var $includeTickets bool */
public $includeTickets;
/* @var $includeUnassignedTickets bool */
public $includeUnassignedTickets;
/* @var $includeTicketsAssignedToOthers bool */
public $includeTicketsAssignedToOthers;
}

@ -0,0 +1,20 @@
<?php
namespace BusinessLogic\Calendar;
class TicketEvent extends AbstractEvent {
public $type = 'TICKET';
public $trackingId;
public $subject;
public $url;
public $owner;
public $priority;
public $status;
}

@ -22,7 +22,7 @@ class Category extends \BaseClass {
public $autoAssign;
/**
* @var int The type of Categories (1 = Private, 2 = Public)
* @var int The type of Categories (1 = Private, 0 = Public)
*/
public $type;

@ -187,4 +187,17 @@ class CategoryHandler extends \BaseClass {
$this->categoryGateway->updateCategory($category, $heskSettings);
$this->categoryGateway->resortAllCategories($heskSettings);
}
function getPublicCategories($heskSettings) {
$allCategories = $this->categoryGateway->getAllCategories($heskSettings, $this->modsForHeskSettingsGateway->getAllSettings($heskSettings));
$publicCategories = array();
foreach ($allCategories as $category) {
if ($category->type === 0) {
$publicCategories[] = $category;
}
}
return $publicCategories;
}
}

@ -12,10 +12,10 @@ class Addressees extends \BaseClass {
/**
* @var $cc string[]|null
*/
public $cc;
public $cc = array();
/**
* @var $bcc string[]|null
*/
public $bcc;
public $bcc = array();
}

@ -5,10 +5,12 @@ namespace BusinessLogic\Emails;
use BusinessLogic\Exceptions\EmailTemplateNotFoundException;
use BusinessLogic\Exceptions\InvalidEmailTemplateException;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Statuses\DefaultStatusForAction;
use BusinessLogic\Tickets\Ticket;
use Core\Constants\Priority;
use DataAccess\Categories\CategoryGateway;
use DataAccess\Logging\LoggingGateway;
use DataAccess\Security\UserGateway;
use DataAccess\Statuses\StatusGateway;
@ -34,14 +36,21 @@ class EmailTemplateParser extends \BaseClass {
*/
private $emailTemplateRetriever;
/**
* @var $logger LoggingGateway
*/
private $logger;
function __construct(StatusGateway $statusGateway,
CategoryGateway $categoryGateway,
UserGateway $userGateway,
EmailTemplateRetriever $emailTemplateRetriever) {
EmailTemplateRetriever $emailTemplateRetriever,
LoggingGateway $loggingGateway) {
$this->statusGateway = $statusGateway;
$this->categoryGateway = $categoryGateway;
$this->userGateway = $userGateway;
$this->emailTemplateRetriever = $emailTemplateRetriever;
$this->logger = $loggingGateway;
}
/**
@ -129,7 +138,17 @@ class EmailTemplateParser extends \BaseClass {
// Status name and category name
$defaultStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings);
$statusName = $defaultStatus->localizedNames[$language];
if (key_exists($language, $defaultStatus->localizedNames)) {
$statusName = $defaultStatus->localizedNames[$language];
} elseif (key_exists('English', $defaultStatus->localizedNames)) {
$statusName = $defaultStatus->localizedNames['English'];
$this->logger->logWarning('EmailTemplateParser', "No localized status found for status '{$defaultStatus->id}' and language '{$language}'. Defaulted to English.", "", new UserContext(), $heskSettings);
} else {
$statusName = "[ERROR: No localized status found for status '{$defaultStatus->id}']";
$this->logger->logError('EmailTemplateParser', "No localized status found for status '{$defaultStatus->id}'", "", new UserContext(), $heskSettings);
}
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
$category = null;
foreach ($categories as $innerCategory) {

@ -4,8 +4,8 @@ namespace BusinessLogic\Exceptions;
class MissingAuthenticationTokenException extends ApiFriendlyException {
function __construct() {
parent::__construct("An 'X-Auth-Token' is required for all requests",
parent::__construct("An 'X-Auth-Token' is required for this request",
'Security Exception',
400);
401);
}
}

@ -30,4 +30,8 @@ class Helpers extends \BaseClass {
static function boolval($val) {
return $val == true;
}
static function heskHtmlSpecialCharsDecode($in) {
return str_replace(array('&amp;', '&lt;', '&gt;', '&quot;'), array('&', '<', '>', '"'), $in);
}
}

@ -57,6 +57,10 @@ class UserContext extends \BaseClass {
/* @var $active bool */
public $active;
function isAnonymousUser() {
return $this->id === -1;
}
static function buildAnonymousUser() {
$userContext = new UserContext();
$userContext->id = -1;

@ -15,4 +15,7 @@ class UserPrivilege extends \BaseClass {
const CAN_EDIT_TICKETS = 'can_edit_tickets';
const CAN_DELETE_TICKETS = 'can_del_tickets';
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_MANAGE_SERVICE_MESSAGES = 'can_service_msg';
}

@ -0,0 +1,12 @@
<?php
namespace BusinessLogic\ServiceMessages;
class GetServiceMessagesFilter {
/* @var $includeStaffServiceMessages bool */
public $includeStaffServiceMessages = true;
/* @var $includeDrafts bool */
public $includeDrafts = true;
}

@ -0,0 +1,39 @@
<?php
namespace BusinessLogic\ServiceMessages;
class ServiceMessage extends \BaseClass {
/* @var $id int */
public $id;
/* @var $dateCreated string */
public $dateCreated;
/* @var $createdBy int */
public $createdBy;
/* @var $title string */
public $title;
/* @var $message string */
public $message;
/* @var $style string */
public $style;
/* @var $published bool */
public $published;
/* @var $order int */
public $order;
/* @var $icon string */
public $icon;
/* @var $locations string[] */
public $locations;
/* @var $language string */
public $language;
}

@ -0,0 +1,164 @@
<?php
namespace BusinessLogic\ServiceMessages;
// TODO Test
use BusinessLogic\Exceptions\ValidationException;
use BusinessLogic\Navigation\Direction;
use BusinessLogic\ValidationModel;
use DataAccess\ServiceMessages\ServiceMessagesGateway;
class ServiceMessageHandler extends \BaseClass {
/* @var $serviceMessageGateway ServiceMessagesGateway */
private $serviceMessageGateway;
function __construct(ServiceMessagesGateway $serviceMessagesGateway) {
$this->serviceMessageGateway = $serviceMessagesGateway;
}
function createServiceMessage($serviceMessage, $heskSettings) {
$this->validate($serviceMessage, $heskSettings);
if ($serviceMessage->icon === null) {
switch ($serviceMessage->style) {
case ServiceMessageStyle::NONE:
$serviceMessage->icon = '';
break;
case ServiceMessageStyle::INFO:
$serviceMessage->icon = 'fa fa-comment';
break;
case ServiceMessageStyle::NOTICE:
$serviceMessage->icon = 'fa fa-exclamation-triangle';
break;
case ServiceMessageStyle::ERROR:
$serviceMessage->icon = 'fa fa-times-circle';
break;
case ServiceMessageStyle::SUCCESS:
$serviceMessage->icon = 'fa fa-check-circle';
break;
}
}
return $this->serviceMessageGateway->createServiceMessage($serviceMessage, $heskSettings);
}
function getServiceMessages($heskSettings, $searchFilter) {
return $this->serviceMessageGateway->getServiceMessages($heskSettings, $searchFilter);
}
function editServiceMessage($serviceMessage, $heskSettings) {
$this->validate($serviceMessage, $heskSettings, false);
if ($serviceMessage->icon === null) {
switch ($serviceMessage->style) {
case ServiceMessageStyle::NONE:
$serviceMessage->icon = '';
break;
case ServiceMessageStyle::INFO:
$serviceMessage->icon = 'fa fa-comment';
break;
case ServiceMessageStyle::NOTICE:
$serviceMessage->icon = 'fa fa-exclamation-triangle';
break;
case ServiceMessageStyle::ERROR:
$serviceMessage->icon = 'fa fa-times-circle';
break;
case ServiceMessageStyle::SUCCESS:
$serviceMessage->icon = 'fa fa-check-circle';
break;
}
}
return $this->serviceMessageGateway->updateServiceMessage($serviceMessage, $heskSettings);
}
function deleteServiceMessage($id, $heskSettings) {
$this->serviceMessageGateway->deleteServiceMessage($id, $heskSettings);
}
function sortServiceMessage($id, $direction, $heskSettings) {
$serviceMessages = $this->serviceMessageGateway->getServiceMessages($heskSettings, new GetServiceMessagesFilter());
$serviceMessage = null;
foreach ($serviceMessages as $innerServiceMessage) {
if (intval($innerServiceMessage->id) === intval($id)) {
$serviceMessage = $innerServiceMessage;
break;
}
}
if ($serviceMessage === null) {
throw new \BaseException("Could not find service message with ID {$id}!");
}
if ($direction === Direction::UP) {
$serviceMessage->order -= 15;
} else {
$serviceMessage->order += 15;
}
$this->serviceMessageGateway->updateServiceMessage($serviceMessage, $heskSettings);
$this->serviceMessageGateway->resortAllServiceMessages($heskSettings);
}
/**
* @param $serviceMessage ServiceMessage
* @param bool $isNew
* @throws ValidationException
*/
private function validate($serviceMessage, $heskSettings, $isNew = true) {
$validationModel = new ValidationModel();
if ($isNew && $serviceMessage->createdBy < 1) {
$validationModel->errorKeys[] = 'MISSING_CREATOR';
}
if ($serviceMessage->message === null || trim($serviceMessage->message) === '') {
$validationModel->errorKeys[] = 'MISSING_MESSAGE';
} else {
$htmlPurifier = new \HeskHTMLPurifier($heskSettings['cache_dir']);
$serviceMessage->message = $htmlPurifier->heskPurify($serviceMessage->message);
}
if ($serviceMessage->language === null || trim($serviceMessage->language) === '') {
$validationModel->errorKeys[] = 'MISSING_LANGUAGE';
}
$languageFound = false;
foreach ($heskSettings['languages'] as $key => $value) {
if ($value['folder'] === $serviceMessage->language || $serviceMessage->language === 'ALL') {
$languageFound = true;
break;
}
}
if (!$languageFound && !in_array('MISSING_LANGUAGE', $validationModel->errorKeys)) {
$validationModel->errorKeys[] = 'LANGUAGE_NOT_INSTALLED';
}
if ($serviceMessage->title === null || trim($serviceMessage->title) === '') {
$validationModel->errorKeys[] = 'MISSING_TITLE';
}
if ($serviceMessage->style === null || trim($serviceMessage->style) === '') {
$validationModel->errorKeys[] = 'MISSING_STYLE';
}
try {
ServiceMessageStyle::getIdForStyle($serviceMessage->style);
} catch (\Exception $e) {
$validationModel->errorKeys[] = 'INVALID_STYLE';
}
if ($serviceMessage->locations === null || count($serviceMessage->locations) === 0) {
$validationModel->errorKeys[] = 'MISSING_LOCATIONS';
} else {
$locations = ServiceMessageLocation::getAll();
foreach ($serviceMessage->locations as $location) {
if (!in_array($location, $locations)) {
$validationModel->errorKeys[] = 'INVALID_LOCATION';
break;
}
}
}
if (count($validationModel->errorKeys) > 0) {
// Validation failed
throw new ValidationException($validationModel);
}
}
}

@ -0,0 +1,34 @@
<?php
namespace BusinessLogic\ServiceMessages;
class ServiceMessageLocation {
const CUSTOMER_HOME = 'CUSTOMER_HOME';
const CUSTOMER_KB_HOME = 'CUSTOMER_KB_HOME';
const CUSTOMER_VIEW_KB_ARTICLE = 'CUSTOMER_VIEW_KB_ARTICLE';
const CUSTOMER_SUBMIT_TICKET = 'CUSTOMER_SUBMIT_TICKET';
const CUSTOMER_VIEW_TICKET = 'CUSTOMER_VIEW_TICKET';
const STAFF_LOGIN = 'STAFF_LOGIN';
const STAFF_HOME = 'STAFF_HOME';
const STAFF_KB_HOME = 'STAFF_KB_HOME';
const STAFF_VIEW_KB_ARTICLE = 'STAFF_VIEW_KB_ARTICLE';
const STAFF_SUBMIT_TICKET = 'STAFF_SUBMIT_TICKET';
const STAFF_VIEW_TICKET = 'STAFF_VIEW_TICKET';
static function getAll() {
return array(
self::CUSTOMER_HOME,
self::CUSTOMER_KB_HOME,
self::CUSTOMER_VIEW_KB_ARTICLE,
self::CUSTOMER_SUBMIT_TICKET,
self::CUSTOMER_VIEW_TICKET,
self::STAFF_LOGIN,
self::STAFF_HOME,
self::STAFF_KB_HOME,
self::STAFF_VIEW_KB_ARTICLE,
self::STAFF_SUBMIT_TICKET,
self::STAFF_VIEW_TICKET,
);
}
}

@ -0,0 +1,44 @@
<?php
namespace BusinessLogic\ServiceMessages;
class ServiceMessageStyle {
const NONE = 'NONE'; // 0
const SUCCESS = 'SUCCESS'; // 1
const INFO = 'INFO'; // 2
const NOTICE = 'NOTICE'; // 3
const ERROR = 'ERROR'; // 4
static function getStyleById($id) {
$styles = array(
0 => self::NONE,
1 => self::SUCCESS,
2 => self::INFO,
3 => self::NOTICE,
4 => self::ERROR
);
if (!isset($styles[$id])) {
throw new \Exception("Style {$id} is not a valid service message style.");
}
return $styles[$id];
}
static function getIdForStyle($style) {
$styles = array(
self::NONE => 0,
self::SUCCESS => 1,
self::INFO => 2,
self::NOTICE => 3,
self::ERROR => 4
);
if (!isset($styles[$style])) {
throw new \Exception("Style {$style} is not a valid service message style.");
}
return $styles[$style];
}
}

@ -5,4 +5,5 @@ namespace BusinessLogic\Tickets;
class AuditTrailEntityType extends \BaseClass {
const TICKET = 'TICKET';
const CALENDAR_EVENT = 'CALENDAR_EVENT';
}

@ -0,0 +1,9 @@
<?php
namespace BusinessLogic\Tickets;
class AuditTrailEvent extends \BaseClass {
const DUE_DATE_REMOVED = 'audit_due_date_removed';
const DUE_DATE_CHANGED = 'audit_due_date_changed';
}

@ -0,0 +1,17 @@
<?php
namespace BusinessLogic\Tickets\CustomFields;
class CustomField {
/* @var $id int */
public $id;
/* @var $name string */
public $name;
/* @var $type string */
public $type;
/* @var $properties array */
public $properties;
}

@ -9,6 +9,7 @@ use BusinessLogic\Emails\EmailTemplateRetriever;
use BusinessLogic\Exceptions\ValidationException;
use BusinessLogic\Statuses\DefaultStatusForAction;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\CustomFields\CustomFieldsGateway;
use DataAccess\Security\UserGateway;
use DataAccess\Settings\ModsForHeskSettingsGateway;
use DataAccess\Statuses\StatusGateway;
@ -61,6 +62,9 @@ class TicketCreator extends \BaseClass {
/* @var $auditTrailGateway AuditTrailGateway */
private $auditTrailGateway;
/* @var $customFieldsGateway CustomFieldsGateway */
private $customFieldsGateway;
function __construct(NewTicketValidator $newTicketValidator,
TrackingIdGenerator $trackingIdGenerator,
Autoassigner $autoassigner,
@ -70,7 +74,8 @@ class TicketCreator extends \BaseClass {
EmailSenderHelper $emailSenderHelper,
UserGateway $userGateway,
ModsForHeskSettingsGateway $modsForHeskSettingsGateway,
AuditTrailGateway $auditTrailGateway) {
AuditTrailGateway $auditTrailGateway,
CustomFieldsGateway $customFieldsGateway) {
$this->newTicketValidator = $newTicketValidator;
$this->trackingIdGenerator = $trackingIdGenerator;
$this->autoassigner = $autoassigner;
@ -81,6 +86,7 @@ class TicketCreator extends \BaseClass {
$this->userGateway = $userGateway;
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
$this->auditTrailGateway = $auditTrailGateway;
$this->customFieldsGateway = $customFieldsGateway;
}
/**
@ -162,6 +168,19 @@ class TicketCreator extends \BaseClass {
$addressees = new Addressees();
$addressees->to = $ticket->email;
foreach ($ticket->customFields as $key => $value) {
$customField = $this->customFieldsGateway->getCustomField($key, $heskSettings);
if ($customField !== null &&
$customField->type === 'email' &&
$customField->properties['email_type'] !== 'none') {
if ($customField->properties['email_type'] === 'cc') {
$addressees->cc[] = $value;
} elseif ($customField->properties['email_type'] === 'bcc') {
$addressees->bcc[] = $value;
}
}
}
if ($ticketRequest->sendEmailToCustomer && $emailVerified) {
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_TICKET, $ticketRequest->language, $addressees, $ticket, $heskSettings, $modsForHeskSettings);
} else if ($modsForHeskSettings['customer_email_verification_required'] && !$emailVerified) {

@ -3,6 +3,7 @@
namespace BusinessLogic\Tickets;
use BusinessLogic\DateTimeHelpers;
use BusinessLogic\Exceptions\AccessViolationException;
use BusinessLogic\Exceptions\ApiFriendlyException;
use BusinessLogic\Exceptions\ValidationException;
@ -13,6 +14,7 @@ use BusinessLogic\Tickets\CustomFields\CustomFieldValidator;
use BusinessLogic\ValidationModel;
use BusinessLogic\Validators;
use Core\Constants\CustomField;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\Tickets\TicketGateway;
class TicketEditor extends \BaseClass {
@ -22,10 +24,15 @@ class TicketEditor extends \BaseClass {
/* @var $userToTicketChecker UserToTicketChecker */
private $userToTicketChecker;
/* @var $auditTrailGateway AuditTrailGateway */
private $auditTrailGateway;
function __construct(TicketGateway $ticketGateway,
UserToTicketChecker $userToTicketChecker) {
UserToTicketChecker $userToTicketChecker,
AuditTrailGateway $auditTrailGateway) {
$this->ticketGateway = $ticketGateway;
$this->userToTicketChecker = $userToTicketChecker;
$this->auditTrailGateway = $auditTrailGateway;
}
@ -135,4 +142,67 @@ class TicketEditor extends \BaseClass {
throw new ValidationException($validationModel);
}
}
/**
* @param $id int
* @param $dueDate string
* @param $userContext UserContext
* @param $heskSettings array
* @return Ticket The updated ticket
*/
function updateDueDate($id, $dueDate, $userContext, $heskSettings) {
$ticket = $this->ticketGateway->getTicketById($id, $heskSettings);
$this->validateDueDate($ticket, $dueDate, $userContext, $heskSettings);
$this->ticketGateway->updateTicketDueDate($ticket->id, $dueDate, $heskSettings);
$event = AuditTrailEvent::DUE_DATE_REMOVED;
$replacementValues = array(0 => $userContext->name . ' (' . $userContext->username . ')');
if ($dueDate !== null) {
$event = AuditTrailEvent::DUE_DATE_CHANGED;
$replacementValues = array(
0 => $userContext->name . ' (' . $userContext->username . ')',
1 => date('Y-m-d H:i:s', strtotime($dueDate))
);
}
$this->auditTrailGateway->insertAuditTrailRecord($ticket->id,
AuditTrailEntityType::TICKET,
$event,
DateTimeHelpers::heskDate($heskSettings),
$replacementValues,
$heskSettings);
$ticket->dueDate = $dueDate;
return $ticket;
}
/**
* @param $ticket Ticket
* @param $dueDate string
* @param $userContext UserContext
* @param $heskSettings array
* @throws ValidationException When validation fails
*/
private function validateDueDate($ticket, $dueDate, $userContext, $heskSettings) {
$validationModel = new ValidationModel();
if ($ticket === null) {
$validationModel->errorKeys[] = 'TICKET_MUST_EXIST_FOR_ID';
}
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings, array(UserPrivilege::CAN_EDIT_TICKETS))) {
$validationModel->errorKeys[] = 'TICKET_MUST_BE_ACCESSIBLE_TO_USER';
}
if ($dueDate === false) {
$validationModel->errorKeys[] = 'DUE_DATE_MUST_BE_IN_VALID_FORMAT';
}
if (count($validationModel->errorKeys) > 0) {
throw new ValidationException($validationModel);
}
}
}

@ -19,7 +19,7 @@ class Validators extends \BaseClass {
$address = str_replace(';', ',', $address);
/* Check if addresses are valid */
$all = explode(',', $address);
$all = array_unique(explode(',',$address));
foreach ($all as $k => $v) {
if (!self::isValidEmail($v)) {
unset($all[$k]);

@ -0,0 +1,135 @@
<?php
namespace Controllers\Calendar;
use BusinessLogic\Calendar\CalendarEvent;
use BusinessLogic\Calendar\CalendarHandler;
use BusinessLogic\Calendar\RecurringRule;
use BusinessLogic\Calendar\ReminderUnit;
use BusinessLogic\Calendar\SearchEventsFilter;
use BusinessLogic\Categories\CategoryHandler;
use BusinessLogic\Exceptions\ValidationException;
use BusinessLogic\Helpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Security\UserPrivilege;
use BusinessLogic\ValidationModel;
use Controllers\JsonRetriever;
use DataAccess\Settings\ModsForHeskSettingsGateway;
use RRule\RRule;
use RRule\RSet;
class CalendarController extends \BaseClass {
function get() {
/* @var $userContext UserContext */
global $applicationContext, $hesk_settings, $userContext;
if (!isset($_GET['start']) || !isset($_GET['end'])) {
$validationModel = new ValidationModel();
$validationModel->errorKeys = array('START_AND_END_TIMES_REQUIRED');
throw new ValidationException($validationModel);
}
$startTime = $_GET['start'];
$endTime = $_GET['end'];
/* @var $calendarHandler CalendarHandler */
$calendarHandler = $applicationContext->get(CalendarHandler::clazz());
$searchEventsFilter = new SearchEventsFilter();
$searchEventsFilter->startTime = $startTime;
$searchEventsFilter->endTime = $endTime;
$searchEventsFilter->reminderUserId = $userContext->id;
if ($userContext->isAnonymousUser()) {
$searchEventsFilter->includeTicketsAssignedToOthers = false;
$searchEventsFilter->includeUnassignedTickets = false;
$searchEventsFilter->includeTickets = false;
/* @var $categoryHandler CategoryHandler */
$categoryHandler = $applicationContext->get(CategoryHandler::clazz());
$publicCategories = $categoryHandler->getPublicCategories($hesk_settings);
$ids = array();
foreach ($publicCategories as $category) {
$ids[] = $category->id;
}
$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->includeTickets = true;
$searchEventsFilter->categories = $userContext->admin ? null : $userContext->categories;
}
$events = $calendarHandler->getEventsForStaff($searchEventsFilter, $hesk_settings);
return output($events);
}
function post() {
/* @var $userContext UserContext */
/* @var $hesk_settings array */
global $applicationContext, $hesk_settings, $userContext;
$json = JsonRetriever::getJsonData();
$event = $this->transformJson($json);
/* @var $calendarHandler CalendarHandler */
$calendarHandler = $applicationContext->get(CalendarHandler::clazz());
return output($calendarHandler->createEvent($event, $userContext, $hesk_settings), 201);
}
function put($id) {
/* @var $userContext UserContext */
global $applicationContext, $hesk_settings, $userContext;
$json = JsonRetriever::getJsonData();
$event = $this->transformJson($json, $id);
/* @var $calendarHandler CalendarHandler */
$calendarHandler = $applicationContext->get(CalendarHandler::clazz());
return output($calendarHandler->updateEvent($event, $userContext, $hesk_settings));
}
function delete($id) {
/* @var $userContext UserContext */
global $applicationContext, $hesk_settings, $userContext;
/* @var $calendarHandler CalendarHandler */
$calendarHandler = $applicationContext->get(CalendarHandler::clazz());
$calendarHandler->deleteEvent($id, $userContext, $hesk_settings);
return http_response_code(204);
}
private function transformJson($json, $id = null) {
$event = new CalendarEvent();
$event->id = $id;
$event->startTime = date('Y-m-d H:i:s', strtotime(Helpers::safeArrayGet($json, 'startTime')));
$event->endTime = date('Y-m-d H:i:s', strtotime(Helpers::safeArrayGet($json, 'endTime')));
$event->allDay = Helpers::safeArrayGet($json, 'allDay');
$event->title = Helpers::safeArrayGet($json, 'title');
$event->location = Helpers::safeArrayGet($json, 'location');
$event->comments = Helpers::safeArrayGet($json, 'comments');
$event->categoryId = Helpers::safeArrayGet($json, 'categoryId');
$event->reminderValue = Helpers::safeArrayGet($json, 'reminderValue');
$event->reminderUnits = ReminderUnit::getByName(Helpers::safeArrayGet($json, 'reminderUnits'));
return $event;
}
static function getBusinessHours() {
global $applicationContext, $hesk_settings;
$calendarHandler = $applicationContext->get(CalendarHandler::clazz());
return output($calendarHandler->getBusinessHours($hesk_settings));
}
}

@ -0,0 +1,139 @@
<?php
namespace Controllers\ServiceMessages;
use BusinessLogic\Exceptions\ApiFriendlyException;
use BusinessLogic\Helpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Security\UserPrivilege;
use BusinessLogic\ServiceMessages\GetServiceMessagesFilter;
use BusinessLogic\ServiceMessages\ServiceMessage;
use BusinessLogic\ServiceMessages\ServiceMessageHandler;
use Controllers\ControllerWithSecurity;
use Controllers\JsonRetriever;
class ServiceMessagesController extends \BaseClass {
/**
* @param $userContext UserContext
* @throws ApiFriendlyException
*/
function checkSecurity($userContext) {
if (!$userContext->admin && !in_array(UserPrivilege::CAN_MANAGE_SERVICE_MESSAGES, $userContext->permissions)) {
throw new ApiFriendlyException("User does not have permission to access the following URI: " . $_SERVER['REQUEST_URI'], "Access Forbidden", 403);
}
}
static function staticCheckSecurity($userContext) {
if (!$userContext->admin && !in_array(UserPrivilege::CAN_MANAGE_SERVICE_MESSAGES, $userContext->permissions)) {
throw new ApiFriendlyException("User does not have permission to access the following URI: " . $_SERVER['REQUEST_URI'], "Access Forbidden", 403);
}
}
function get() {
/* @var $userContext UserContext */
/* @var $hesk_settings array */
global $applicationContext, $hesk_settings, $userContext;
$searchFilter = new GetServiceMessagesFilter();
if ($userContext->isAnonymousUser()) {
$searchFilter->includeDrafts = false;
$searchFilter->includeStaffServiceMessages = false;
} elseif (!$userContext->admin && !in_array(UserPrivilege::CAN_MANAGE_SERVICE_MESSAGES, $userContext->permissions)) {
$searchFilter->includeDrafts = false;
}
/* @var $handler ServiceMessageHandler */
$handler = $applicationContext->get(ServiceMessageHandler::clazz());
return output($handler->getServiceMessages($hesk_settings, $searchFilter));
}
function post() {
global $applicationContext, $userContext, $hesk_settings;
$this->checkSecurity($userContext);
/* @var $handler ServiceMessageHandler */
$handler = $applicationContext->get(ServiceMessageHandler::clazz());
$data = JsonRetriever::getJsonData();
$element = $handler->createServiceMessage($this->buildElementModel($data, $userContext), $hesk_settings);
return output($element, 201);
}
function put($id) {
global $applicationContext, $hesk_settings, $userContext;
$this->checkSecurity($userContext);
/* @var $handler ServiceMessageHandler */
$handler = $applicationContext->get(ServiceMessageHandler::clazz());
$data = JsonRetriever::getJsonData();
$serviceMessage = $this->buildElementModel($data, null, false);
$serviceMessage->id = $id;
$element = $handler->editServiceMessage($serviceMessage, $hesk_settings);
return output($element);
}
function delete($id) {
global $applicationContext, $hesk_settings, $userContext;
$this->checkSecurity($userContext);
/* @var $handler ServiceMessageHandler */
$handler = $applicationContext->get(ServiceMessageHandler::clazz());
$handler->deleteServiceMessage($id, $hesk_settings);
return http_response_code(204);
}
/**
* @param $data array
* @param $userContext UserContext
* @return ServiceMessage
*/
private function buildElementModel($data, $userContext, $creating = true) {
$serviceMessage = new ServiceMessage();
if (!$creating) {
$serviceMessage->order = Helpers::safeArrayGet($data, 'order');
}
if ($creating) {
$serviceMessage->createdBy = $userContext->id;
}
$serviceMessage->title = Helpers::safeArrayGet($data, 'title');
$serviceMessage->icon = Helpers::safeArrayGet($data, 'icon');
$serviceMessage->message = Helpers::safeArrayGet($data, 'message');
$serviceMessage->published = Helpers::safeArrayGet($data, 'published');
$serviceMessage->style = Helpers::safeArrayGet($data, 'style');
$serviceMessage->language = Helpers::safeArrayGet($data, 'language');
$jsonLocations = Helpers::safeArrayGet($data, 'locations');
if ($jsonLocations !== null && !empty($jsonLocations)) {
foreach ($jsonLocations as $key => $value) {
$serviceMessage->locations[] = $value;
}
}
return $serviceMessage;
}
static function sort($id, $direction) {
/* @var $userContext UserContext */
global $applicationContext, $hesk_settings, $userContext;
self::staticCheckSecurity($userContext);
/* @var $handler ServiceMessageHandler */
$handler = $applicationContext->get(ServiceMessageHandler::clazz());
$handler->sortServiceMessage(intval($id), $direction, $hesk_settings);
}
}

@ -4,6 +4,7 @@ namespace Controllers\Tickets;
use BusinessLogic\Helpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Tickets\EditTicketModel;
use BusinessLogic\Tickets\TicketDeleter;
use BusinessLogic\Tickets\TicketEditor;
@ -45,6 +46,20 @@ class StaffTicketController extends \BaseClass {
return;
}
static function updateDueDate($id) {
/* @var $userContext UserContext */
global $applicationContext, $userContext, $hesk_settings;
/* @var $ticketEditor TicketEditor */
$ticketEditor = $applicationContext->get(TicketEditor::clazz());
$json = JsonRetriever::getJsonData();
$dueDate = date('Y-m-d H:i:s', strtotime(Helpers::safeArrayGet($json, 'dueDate')));
$ticketEditor->updateDueDate($id, $dueDate, $userContext, $hesk_settings);
}
private function getEditTicketModel($id, $jsonRequest) {
$editTicketModel = new EditTicketModel();
$editTicketModel->id = $id;

@ -8,4 +8,19 @@ class Priority extends \BaseClass {
const HIGH = 1;
const MEDIUM = 2;
const LOW = 3;
static function getByValue($value) {
switch ($value) {
case self::CRITICAL:
return 'CRITICAL';
case self::HIGH:
return 'HIGH';
case self::MEDIUM:
return 'MEDIUM';
case self::LOW:
return 'LOW';
default:
return 'UNKNOWN';
}
}
}

@ -7,7 +7,11 @@ function print_error($title, $message, $logId = null, $response_code = 500) {
$error['type'] = 'ERROR';
$error['title'] = $title;
$error['message'] = $message;
$error['logId'] = $logId;
if ($logId !== null) {
$error['logId'] = $logId;
}
print output($error, $response_code);
return;

@ -0,0 +1,266 @@
<?php
namespace DataAccess\Calendar;
use BusinessLogic\Calendar\AbstractEvent;
use BusinessLogic\Calendar\BusinessHours;
use BusinessLogic\Calendar\CalendarEvent;
use BusinessLogic\Calendar\ReminderUnit;
use BusinessLogic\Calendar\SearchEventsFilter;
use BusinessLogic\Calendar\TicketEvent;
use BusinessLogic\Helpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Tickets\AuditTrail;
use BusinessLogic\Tickets\AuditTrailEntityType;
use Core\Constants\Priority;
use DataAccess\CommonDao;
class CalendarGateway extends CommonDao {
/**
* @param $searchEventsFilter SearchEventsFilter
* @param $heskSettings array
* @return AbstractEvent[]
*/
public function getEventsForStaff($searchEventsFilter, $heskSettings) {
$this->init();
$events = array();
// EVENTS
$sql = "SELECT `events`.*, `categories`.`name` AS `category_name`, `categories`.`background_color` AS `background_color`,
`categories`.`foreground_color` AS `foreground_color`, `categories`.`display_border_outline` AS `display_border`,
`reminders`.`amount` AS `reminder_value`, `reminders`.`unit` AS `reminder_unit`
FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "calendar_event` AS `events`
INNER JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "categories` AS `categories`
ON `events`.`category` = `categories`.`id`
LEFT JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "calendar_event_reminder` AS `reminders`
ON `reminders`.`user_id` = " . intval($searchEventsFilter->reminderUserId) . "
AND `reminders`.`event_id` = `events`.`id`
WHERE 1=1";
if ($searchEventsFilter->startTime !== null && $searchEventsFilter->endTime !== null) {
$startTimeSql = "CONVERT_TZ(FROM_UNIXTIME(" . hesk_dbEscape($searchEventsFilter->startTime) . " / 1000), @@session.time_zone, '+00:00')";
$endTimeSql = "CONVERT_TZ(FROM_UNIXTIME(" . hesk_dbEscape($searchEventsFilter->endTime) . " / 1000), @@session.time_zone, '+00:00')";
$sql .= " AND NOT (`end` < {$startTimeSql} OR `start` > {$endTimeSql})
AND `categories`.`usage` <> 1";
}
if ($searchEventsFilter->eventId !== null) {
$sql .= " AND `events`.`id` = " . intval($searchEventsFilter->eventId);
}
if (!empty($searchEventsFilter->categories)) {
$categoriesAsString = implode(',', $searchEventsFilter->categories);
$sql .= " AND `events`.`category` IN (" . $categoriesAsString . ")";
}
$rs = hesk_dbQuery($sql);
while ($row = hesk_dbFetchAssoc($rs)) {
$event = new CalendarEvent();
$event->id = intval($row['id']);
$event->startTime = $row['start'];
$event->endTime = $row['end'];
$event->allDay = Helpers::boolval($row['all_day']);
$event->title = $row['name'];
$event->location = $row['location'];
$event->comments = $row['comments'];
$event->categoryId = intval($row['category']);
$event->categoryName = Helpers::heskHtmlSpecialCharsDecode($row['category_name']);
$event->backgroundColor = $row['background_color'];
$event->foregroundColor = $row['foreground_color'];
$event->displayBorder = Helpers::boolval($row['display_border']);
$event->reminderValue = $row['reminder_value'] === null ? null : floatval($row['reminder_value']);
$event->reminderUnits = $row['reminder_unit'] === null ? null : ReminderUnit::getByValue($row['reminder_unit']);
$auditTrailSql = "SELECT `at`.`id` AS `id`, `at`.`entity_id`, `at`.`language_key`, `at`.`date`,
`values`.`replacement_index`, `values`.`replacement_value`
FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "audit_trail` AS `at`
INNER JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "audit_trail_to_replacement_values` AS `values`
ON `at`.`id` = `values`.`audit_trail_id`
WHERE `entity_id` = " . intval($event->id) . "
AND `entity_type` = '" . AuditTrailEntityType::CALENDAR_EVENT . "'";
$auditTrailRs = hesk_dbQuery($auditTrailSql);
/* @var $auditTrailEntry AuditTrail */
$auditTrailEntry = null;
while ($row = hesk_dbFetchAssoc($auditTrailRs)) {
if ($auditTrailEntry == null || intval($auditTrailEntry->id) !== intval($row['id'])) {
if ($auditTrailEntry !== null) {
$event->auditTrail[] = $auditTrailEntry;
}
$auditTrailEntry = new AuditTrail();
$auditTrailEntry->id = intval($row['id']);
$auditTrailEntry->entityId = intval($row['entity_id']);
$auditTrailEntry->entityType = AuditTrailEntityType::CALENDAR_EVENT;
$auditTrailEntry->languageKey = $row['language_key'];
$auditTrailEntry->date = $row['date'];
$auditTrailEntry->replacementValues = array();
}
$auditTrailEntry->replacementValues[intval($row['replacement_index'])] = $row['replacement_value'];
}
if ($auditTrailEntry !== null) {
$event->auditTrail[] = $auditTrailEntry;
}
$events[] = $event;
}
// TICKETS
if ($searchEventsFilter->includeTickets) {
$oldTimeSetting = $heskSettings['timeformat'];
$heskSettings['timeformat'] = 'Y-m-d';
$currentDate = hesk_date();
$heskSettings['timeformat'] = $oldTimeSetting;
$sql = "SELECT `tickets`.`id` AS `id`, `trackid`, `subject`, `due_date`, `category`, `categories`.`name` AS `category_name`, `categories`.`background_color` AS `background_color`,
`categories`.`foreground_color` AS `foreground_color`, `categories`.`display_border_outline` AS `display_border`,
CASE WHEN `due_date` < '{$currentDate}' THEN 1 ELSE 0 END AS `overdue`, `owner`.`name` AS `owner_name`, `tickets`.`owner` AS `owner_id`,
`tickets`.`priority` AS `priority`, `text_to_status_xref`.`text` AS `status_name`
FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "tickets` AS `tickets`
INNER JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "categories` AS `categories`
ON `categories`.`id` = `tickets`.`category`
AND `categories`.`usage` <> 2
LEFT JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "users` AS `owner`
ON `tickets`.`owner` = `owner`.`id`
LEFT JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "text_to_status_xref` AS `text_to_status_xref`
ON `tickets`.`status` = `text_to_status_xref`.`status_id`
AND `text_to_status_xref`.`language` = '" . hesk_dbEscape($heskSettings['language']) . "'
WHERE `due_date` >= {$startTimeSql}
AND `due_date` <= {$endTimeSql}
AND `status` IN (SELECT `id` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "statuses` WHERE `IsClosed` = 0)
AND (`owner` = " . $searchEventsFilter->reminderUserId;
if ($searchEventsFilter->includeUnassignedTickets) {
$sql .= " OR `owner` = 0 ";
}
if ($searchEventsFilter->includeTicketsAssignedToOthers) {
$sql .= " OR `owner` NOT IN (0, " . $searchEventsFilter->reminderUserId . ") ";
}
$sql .= ")";
if (!empty($searchEventsFilter->categories)) {
$categoriesAsString = implode(',', $searchEventsFilter->categories);
$sql .= " AND `tickets`.`category` IN (" . $categoriesAsString . ")";
}
$rs = hesk_dbQuery($sql);
while ($row = hesk_dbFetchAssoc($rs)) {
$event = new TicketEvent();
$event->id = intval($row['id']);
$event->trackingId = $row['trackid'];
$event->subject = $row['subject'];
$event->title = $row['subject'];
$event->startTime = $row['due_date'];
$event->url = $heskSettings['hesk_url'] . '/' . $heskSettings['admin_dir'] . '/admin_ticket.php?track=' . $event->trackingId;
$event->categoryId = intval($row['category']);
$event->categoryName = Helpers::heskHtmlSpecialCharsDecode($row['category_name']);
$event->backgroundColor = $row['background_color'];
$event->foregroundColor = $row['foreground_color'];
$event->displayBorder = Helpers::boolval($row['display_border']);
$event->owner = $row['owner_name'];
$event->priority = Priority::getByValue($row['priority']);
$event->status = $row['status_name'];
$events[] = $event;
}
}
$this->close();
return $events;
}
/**
* @param $event CalendarEvent
* @param $userContext UserContext
* @param $heskSettings array
* @return CalendarEvent
*/
public function createEvent($event, $userContext, $heskSettings) {
$this->init();
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "calendar_event` (`start`, `end`, `all_day`, `name`,
`location`, `comments`, `category`) VALUES ('" . hesk_dbEscape($event->startTime) . "', '" . hesk_dbEscape($event->endTime) . "',
'" . ($event->allDay ? 1 : 0) . "', '" . hesk_dbEscape(addslashes($event->title)) . "',
'" . hesk_dbEscape(addslashes($event->location)) . "', '". hesk_dbEscape(addslashes($event->comments)) . "', " . intval($event->categoryId) . ")");
$event->id = hesk_dbInsertID();
if ($event->reminderValue !== null) {
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "calendar_event_reminder` (`user_id`, `event_id`,
`amount`, `unit`) VALUES (" . intval($userContext->id) . ", " . intval($event->id) . ", " . intval($event->reminderValue) . ",
" . intval($event->reminderUnits) . ")");
}
$this->close();
}
/**
* @param $event CalendarEvent
* @param $userContext UserContext
* @param $heskSettings array
*/
public function updateEvent($event, $userContext, $heskSettings) {
$this->init();
$sql = "UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "calendar_event` SET `start` = '" . hesk_dbEscape($event->startTime)
. "', `end` = '" . hesk_dbEscape($event->endTime) . "', `all_day` = '" . ($event->allDay ? 1 : 0) . "', `name` = '"
. hesk_dbEscape(addslashes($event->title)) . "', `location` = '" . hesk_dbEscape(addslashes($event->location)) . "', `comments` = '"
. hesk_dbEscape(addslashes($event->comments)) . "', `category` = " . intval($event->categoryId) . " WHERE `id` = " . intval($event->id);
if ($event->reminderValue !== null) {
$delete_sql = "DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "calendar_event_reminder` WHERE `event_id` = " . intval($event->id)
. " AND `user_id` = " . intval($userContext->id);
hesk_dbQuery($delete_sql);
$insert_sql = "INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "calendar_event_reminder` (`user_id`, `event_id`,
`amount`, `unit`) VALUES (" . intval($userContext->id) . ", " . intval($event->id) . ", " . intval($event->reminderValue) . ",
" . intval($event->reminderUnits) . ")";
hesk_dbQuery($insert_sql);
}
hesk_dbQuery($sql);
$this->close();
}
/**
* @param $id int
* @param $userContext UserContext
* @param $heskSettings array
*/
public function deleteEvent($id, $userContext, $heskSettings) {
$this->init();
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "calendar_event_reminder`
WHERE `event_id` = " . intval($id) . " AND `user_id` = " . intval($userContext->id));
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "calendar_event`
WHERE `id` = " . intval($id));
$this->close();
}
public function getBusinessHours($heskSettings) {
$this->init();
$rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "mfh_calendar_business_hours`");
$businessHours = array();
while ($row = hesk_dbFetchAssoc($rs)) {
$businessHour = new BusinessHours();
$businessHour->dayOfWeek = intval($row['day_of_week']);
$businessHour->startTime = $row['start_time'];
$businessHour->endTime = $row['end_time'];
$businessHours[] = $businessHour;
}
$this->close();
return $businessHours;
}
}

@ -11,7 +11,7 @@ class CommonDao extends \BaseClass {
*/
function init() {
if (!function_exists('hesk_dbConnect')) {
throw new Exception('Database not loaded!');
throw new \BaseException('Database not loaded!');
}
hesk_dbConnect();
}

@ -0,0 +1,26 @@
<?php
namespace DataAccess\CustomFields;
use BusinessLogic\Tickets\CustomFields\CustomField;
use DataAccess\CommonDao;
class CustomFieldsGateway extends CommonDao {
public function getCustomField($id, $heskSettings) {
$this->init();
$rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "custom_fields` WHERE `id` = " . intval($id));
if ($row = hesk_dbFetchAssoc($rs)) {
$customField = new CustomField();
$customField->id = $row['id'];
$names = json_decode($row['name'], true);
$customField->name = (isset($names[$heskSettings['language']])) ? $names[$heskSettings['language']] : reset($names);
$customField->type = $row['type'];
$customField->properties = json_decode($row['value'], true);
return $customField;
} else {
return null;
}
}
}

@ -0,0 +1,182 @@
<?php
namespace DataAccess\ServiceMessages;
use BusinessLogic\ServiceMessages\GetServiceMessagesFilter;
use BusinessLogic\ServiceMessages\ServiceMessage;
use BusinessLogic\ServiceMessages\ServiceMessageLocation;
use BusinessLogic\ServiceMessages\ServiceMessageStyle;
use DataAccess\CommonDao;
class ServiceMessagesGateway extends CommonDao {
/**
* @param $serviceMessage ServiceMessage
* @return ServiceMessage
*/
function createServiceMessage($serviceMessage, $heskSettings) {
$this->init();
// Get the latest service message order
$res = hesk_dbQuery("SELECT `order` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` ORDER BY `order` DESC LIMIT 1");
$row = hesk_dbFetchRow($res);
$myOrder = intval($row[0]) + 10;
$style = ServiceMessageStyle::getIdForStyle($serviceMessage->style);
$type = $serviceMessage->published ? 0 : 1;
// Insert service message into database
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` (`author`,`title`,`message`,`style`,`type`,`order`, `icon`, `mfh_language`) VALUES (
'" . intval($serviceMessage->createdBy) . "',
'" . hesk_dbEscape($serviceMessage->title) . "',
'" . hesk_dbEscape($serviceMessage->message) . "',
'" . hesk_dbEscape($style) . "',
'{$type}',
'{$myOrder}',
'" . hesk_dbEscape($serviceMessage->icon) . "',
'" . hesk_dbEscape($serviceMessage->language) . "'
)");
$serviceMessage->id = hesk_dbInsertID();
foreach ($serviceMessage->locations as $location) {
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "mfh_service_message_to_location`
(`service_message_id`, `location`) VALUES (" . intval($serviceMessage->id) . ", '" . hesk_dbEscape($location) . "')");
}
// Get the autogenerated fields
$rs = hesk_dbQuery("SELECT `dt`, `order` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages`
WHERE `id` = " . intval($serviceMessage->id));
$row = hesk_dbFetchAssoc($rs);
$serviceMessage->dateCreated = $row['dt'];
$serviceMessage->order = intval($row['order']);
$this->close();
return $serviceMessage;
}
/**
* @param $heskSettings
* @param $searchFilter GetServiceMessagesFilter
* @return ServiceMessage[]
*/
function getServiceMessages($heskSettings, $searchFilter) {
$this->init();
$serviceMessages = array();
$sql = "SELECT DISTINCT `service_messages`.* FROM `". hesk_dbEscape($heskSettings['db_pfix']) . "service_messages` AS `service_messages` ";
if (!$searchFilter->includeStaffServiceMessages) {
$sql .= "INNER JOIN `" . hesk_dbEscape($heskSettings['db_pfix']) . "mfh_service_message_to_location` AS `location`
ON `location`.`service_message_id` = `service_messages`.`id` AND `location`.`location` LIKE 'CUSTOMER%' ";
}
if (!$searchFilter->includeDrafts) {
$sql .= "WHERE `type` = '0' ";
}
$sql .= "ORDER BY `order`";
$rs = hesk_dbQuery($sql);
while ($row = hesk_dbFetchAssoc($rs)) {
$serviceMessage = new ServiceMessage();
$serviceMessage->id = $row['id'];
$serviceMessage->published = intval($row['type']) !== 1;
$serviceMessage->createdBy = intval($row['author']);
$serviceMessage->order = intval($row['order']);
$serviceMessage->dateCreated = $row['dt'];
$serviceMessage->title = $row['title'];
$serviceMessage->message = $row['message'];
$serviceMessage->style = ServiceMessageStyle::getStyleById($row['style']);
$serviceMessage->icon = $row['icon'];
$serviceMessage->language = $row['mfh_language'];
$serviceMessage->locations = array();
$locationSql = "SELECT `location` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "mfh_service_message_to_location`
WHERE `service_message_id` = " . intval($serviceMessage->id);
if (!$searchFilter->includeStaffServiceMessages) {
$locationSql .= " AND `location` LIKE 'CUSTOMER%'";
}
$locationsRs = hesk_dbQuery($locationSql);
while ($innerRow = hesk_dbFetchAssoc($locationsRs)) {
$serviceMessage->locations[] = $innerRow['location'];
}
$serviceMessages[] = $serviceMessage;
}
$this->close();
return $serviceMessages;
}
function updateServiceMessage($serviceMessage, $heskSettings) {
$this->init();
$style = ServiceMessageStyle::getIdForStyle($serviceMessage->style);
$type = $serviceMessage->published ? 0 : 1;
hesk_dbQuery("UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages`
SET `title` = '" . hesk_dbEscape($serviceMessage->title) . "',
`message` = '" . hesk_dbEscape($serviceMessage->message) . "',
`style` = '" . intval($style) . "',
`type` = '{$type}',
`icon` = '" . hesk_dbEscape($serviceMessage->icon) . "',
`order` = " . intval($serviceMessage->order) . ",
`mfh_language` = '" . hesk_dbEscape($serviceMessage->language) . "'
WHERE `id` = " . intval($serviceMessage->id));
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "mfh_service_message_to_location`
WHERE `service_message_id` = " . intval($serviceMessage->id));
foreach ($serviceMessage->locations as $location) {
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "mfh_service_message_to_location`
(`service_message_id`, `location`) VALUES (" . intval($serviceMessage->id) . ", '" . hesk_dbEscape($location) . "')");
}
$otherFieldsRs = hesk_dbQuery("SELECT `dt`, `author`, `order` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages`
WHERE `id` = " . intval($serviceMessage->id));
$otherFields = hesk_dbFetchAssoc($otherFieldsRs);
$serviceMessage->createdBy = intval($otherFields['author']);
$serviceMessage->dateCreated = $otherFields['dt'];
$this->close();
return $serviceMessage;
}
function deleteServiceMessage($id, $heskSettings) {
$this->init();
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "mfh_service_message_to_location`
WHERE `service_message_id` = " . intval($id));
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages`
WHERE `id` = " . intval($id));
$this->close();
}
function resortAllServiceMessages($heskSettings) {
$this->init();
$rs = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages`
ORDER BY `order` ASC");
$sortValue = 10;
while ($row = hesk_dbFetchAssoc($rs)) {
hesk_dbQuery("UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "service_messages`
SET `order` = " . intval($sortValue) . "
WHERE `id` = " . intval($row['id']));
$sortValue += 10;
}
$this->close();
}
}

@ -440,4 +440,18 @@ class TicketGateway extends CommonDao {
$this->close();
}
function updateTicketDueDate($id, $dueDate, $heskSettings) {
$this->init();
$sqlDueDate = 'NULL';
if ($dueDate != NULL) {
$sqlDueDate = "'" . date('Y-m-d H:i:s', strtotime($dueDate)) . "'";
}
hesk_dbQuery("UPDATE `" . hesk_dbEscape($heskSettings['db_pfix']) . "tickets` SET `due_date` = {$sqlDueDate}
WHERE `id` = " . intval($id));
$this->close();
}
}

@ -19,6 +19,7 @@ use BusinessLogic\Tickets\VerifiedEmailChecker;
use BusinessLogic\ValidationModel;
use Core\Constants\Priority;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\CustomFields\CustomFieldsGateway;
use DataAccess\Security\UserGateway;
use DataAccess\Settings\ModsForHeskSettingsGateway;
use DataAccess\Statuses\StatusGateway;
@ -101,6 +102,9 @@ class CreateTicketTest extends TestCase {
/* @var $auditTrailGateway \PHPUnit_Framework_MockObject_MockObject|AuditTrailGateway */
private $auditTrailGateway;
/* @var $customFieldsGateway \PHPUnit_Framework_MockObject_MockObject|CustomFieldsGateway */
private $customFieldsGateway;
protected function setUp() {
$this->ticketGateway = $this->createMock(TicketGateway::clazz());
$this->newTicketValidator = $this->createMock(NewTicketValidator::clazz());
@ -112,10 +116,11 @@ class CreateTicketTest extends TestCase {
$this->userGateway = $this->createMock(UserGateway::clazz());
$this->modsForHeskSettingsGateway = $this->createMock(ModsForHeskSettingsGateway::clazz());
$this->auditTrailGateway = $this->createMock(AuditTrailGateway::clazz());
$this->customFieldsGateway = $this->createMock(CustomFieldsGateway::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->emailSenderHelper, $this->userGateway, $this->modsForHeskSettingsGateway, $this->auditTrailGateway, $this->customFieldsGateway);
$this->ticketRequest = new CreateTicketByCustomerModel();
$this->ticketRequest->name = 'Name';

@ -12,6 +12,7 @@ require_once(__DIR__ . '/Core/output.php');
require_once(__DIR__ . '/../hesk_settings.inc.php');
require_once(__DIR__ . '/http_response_code.php');
require_once(__DIR__ . '/../inc/admin_functions.inc.php');
require_once(__DIR__ . '/../inc/htmlpurifier/HeskHTMLPurifier.php');
hesk_load_api_database_functions();

101
api/composer.lock generated

@ -692,16 +692,16 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v2.8.28",
"version": "v2.8.33",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "7fe089232554357efb8d4af65ce209fc6e5a2186"
"reference": "d64be24fc1eba62f9daace8a8918f797fc8e87cc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7fe089232554357efb8d4af65ce209fc6e5a2186",
"reference": "7fe089232554357efb8d4af65ce209fc6e5a2186",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d64be24fc1eba62f9daace8a8918f797fc8e87cc",
"reference": "d64be24fc1eba62f9daace8a8918f797fc8e87cc",
"shasum": ""
},
"require": {
@ -748,7 +748,7 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2017-10-01T21:00:16+00:00"
"time": "2018-01-03T07:36:31+00:00"
},
{
"name": "zendframework/zend-code",
@ -1334,29 +1334,35 @@
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "4.1.1",
"version": "4.2.0",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2"
"reference": "66465776cfc249844bde6d117abff1d22e06c2da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2d3d238c433cf69caeb4842e97a3223a116f94b2",
"reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/66465776cfc249844bde6d117abff1d22e06c2da",
"reference": "66465776cfc249844bde6d117abff1d22e06c2da",
"shasum": ""
},
"require": {
"php": "^7.0",
"phpdocumentor/reflection-common": "^1.0@dev",
"phpdocumentor/reflection-common": "^1.0.0",
"phpdocumentor/type-resolver": "^0.4.0",
"webmozart/assert": "^1.0"
},
"require-dev": {
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "^4.4"
"doctrine/instantiator": "~1.0.5",
"mockery/mockery": "^1.0",
"phpunit/phpunit": "^6.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.x-dev"
}
},
"autoload": {
"psr-4": {
"phpDocumentor\\Reflection\\": [
@ -1375,7 +1381,7 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2017-08-30T18:51:59+00:00"
"time": "2017-11-27T17:38:31+00:00"
},
{
"name": "phpdocumentor/type-resolver",
@ -1426,16 +1432,16 @@
},
{
"name": "phpspec/prophecy",
"version": "v1.7.2",
"version": "1.7.3",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6"
"reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
"reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
"reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf",
"shasum": ""
},
"require": {
@ -1447,7 +1453,7 @@
},
"require-dev": {
"phpspec/phpspec": "^2.5|^3.2",
"phpunit/phpunit": "^4.8 || ^5.6.5"
"phpunit/phpunit": "^4.8.35 || ^5.7"
},
"type": "library",
"extra": {
@ -1485,20 +1491,20 @@
"spy",
"stub"
],
"time": "2017-09-04T11:05:03+00:00"
"time": "2017-11-24T13:59:53+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "5.2.3",
"version": "5.3.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "8e1d2397d8adf59a3f12b2878a3aaa66d1ab189d"
"reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/8e1d2397d8adf59a3f12b2878a3aaa66d1ab189d",
"reference": "8e1d2397d8adf59a3f12b2878a3aaa66d1ab189d",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/661f34d0bd3f1a7225ef491a70a020ad23a057a1",
"reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1",
"shasum": ""
},
"require": {
@ -1507,14 +1513,13 @@
"php": "^7.0",
"phpunit/php-file-iterator": "^1.4.2",
"phpunit/php-text-template": "^1.2.1",
"phpunit/php-token-stream": "^2.0",
"phpunit/php-token-stream": "^2.0.1",
"sebastian/code-unit-reverse-lookup": "^1.0.1",
"sebastian/environment": "^3.0",
"sebastian/version": "^2.0.1",
"theseer/tokenizer": "^1.1"
},
"require-dev": {
"ext-xdebug": "^2.5",
"phpunit/phpunit": "^6.0"
},
"suggest": {
@ -1523,7 +1528,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2.x-dev"
"dev-master": "5.3.x-dev"
}
},
"autoload": {
@ -1538,7 +1543,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
@ -1549,20 +1554,20 @@
"testing",
"xunit"
],
"time": "2017-11-03T13:47:33+00:00"
"time": "2017-12-06T09:29:45+00:00"
},
{
"name": "phpunit/php-file-iterator",
"version": "1.4.2",
"version": "1.4.5",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4",
"reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4",
"shasum": ""
},
"require": {
@ -1596,7 +1601,7 @@
"filesystem",
"iterator"
],
"time": "2016-10-03T07:40:28+00:00"
"time": "2017-11-27T13:52:08+00:00"
},
{
"name": "phpunit/php-text-template",
@ -1690,16 +1695,16 @@
},
{
"name": "phpunit/php-token-stream",
"version": "2.0.1",
"version": "2.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0"
"reference": "791198a2c6254db10131eecfe8c06670700904db"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9a02332089ac48e704c70f6cefed30c224e3c0b0",
"reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db",
"reference": "791198a2c6254db10131eecfe8c06670700904db",
"shasum": ""
},
"require": {
@ -1735,7 +1740,7 @@
"keywords": [
"tokenizer"
],
"time": "2017-08-20T05:47:52+00:00"
"time": "2017-11-27T05:48:46+00:00"
},
{
"name": "phpunit/phpunit",
@ -1974,16 +1979,16 @@
},
{
"name": "sebastian/comparator",
"version": "2.1.0",
"version": "2.1.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "1174d9018191e93cb9d719edec01257fc05f8158"
"reference": "11c07feade1d65453e06df3b3b90171d6d982087"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1174d9018191e93cb9d719edec01257fc05f8158",
"reference": "1174d9018191e93cb9d719edec01257fc05f8158",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/11c07feade1d65453e06df3b3b90171d6d982087",
"reference": "11c07feade1d65453e06df3b3b90171d6d982087",
"shasum": ""
},
"require": {
@ -2034,7 +2039,7 @@
"compare",
"equality"
],
"time": "2017-11-03T07:16:52+00:00"
"time": "2018-01-12T06:34:42+00:00"
},
{
"name": "sebastian/diff",
@ -2488,16 +2493,16 @@
},
{
"name": "symfony/console",
"version": "v2.8.28",
"version": "v2.8.33",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853"
"reference": "a4bd0f02ea156cf7b5138774a7ba0ab44d8da4fe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/f81549d2c5fdee8d711c9ab3c7e7362353ea5853",
"reference": "f81549d2c5fdee8d711c9ab3c7e7362353ea5853",
"url": "https://api.github.com/repos/symfony/console/zipball/a4bd0f02ea156cf7b5138774a7ba0ab44d8da4fe",
"reference": "a4bd0f02ea156cf7b5138774a7ba0ab44d8da4fe",
"shasum": ""
},
"require": {
@ -2545,7 +2550,7 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2017-10-01T21:00:16+00:00"
"time": "2018-01-03T07:36:31+00:00"
},
{
"name": "symfony/debug",

@ -45,8 +45,15 @@ function internalOrAuthHandler() {
function publicHandler() {
global $userContext;
//-- Create an "anonymous" UserContext
$userContext = \BusinessLogic\Security\UserContext::buildAnonymousUser();
// Check if we passed in a X-Auth-Token or X-Internal-Call header. Those take priority
if (\BusinessLogic\Helpers::getHeader('X-INTERNAL-CALL') === 'true') {
internalHandler();
} elseif (\BusinessLogic\Helpers::getHeader('X-AUTH-TOKEN') !== null) {
authTokenHandler();
} else {
//-- Create an "anonymous" UserContext
$userContext = \BusinessLogic\Security\UserContext::buildAnonymousUser();
}
}
function assertApiIsEnabled() {
@ -105,7 +112,7 @@ function exceptionHandler($exception) {
/* @var $castedException \BusinessLogic\Exceptions\ApiFriendlyException */
$castedException = $exception;
print_error($castedException->title, $castedException->getMessage(), $castedException->httpResponseCode);
print_error($castedException->title, $castedException->getMessage(), null, $castedException->httpResponseCode);
} elseif (exceptionIsOfType($exception, \Core\Exceptions\SQLException::clazz())) {
/* @var $castedException \Core\Exceptions\SQLException */
$castedException = $exception;
@ -194,6 +201,7 @@ Link::all(array(
'/v1/tickets' => action(\Controllers\Tickets\CustomerTicketController::clazz(), RequestMethod::all(), 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),
// Attachments
'/v1/tickets/{a}/attachments/{i}' => action(\Controllers\Attachments\PublicAttachmentController::clazz() . '::getRaw', RequestMethod::all()),
'/v1/staff/tickets/{i}/attachments' => action(\Controllers\Attachments\StaffTicketAttachmentsController::clazz(), RequestMethod::all()),
@ -202,6 +210,21 @@ Link::all(array(
'/v1/statuses' => action(\Controllers\Statuses\StatusController::clazz(), RequestMethod::all()),
// Settings
'/v1/settings' => action(\Controllers\Settings\SettingsController::clazz(), RequestMethod::all()),
// Calendar
'/v1/calendar/business-hours' => action(\Controllers\Calendar\CalendarController::clazz() . '::getBusinessHours', array(RequestMethod::GET), SecurityHandler::OPEN),
'/v1/calendar/events' => action(\Controllers\Calendar\CalendarController::clazz(), array(RequestMethod::GET), SecurityHandler::OPEN),
'/v1/calendar/events/staff' => action(\Controllers\Calendar\CalendarController::clazz(), array(RequestMethod::GET, RequestMethod::POST), SecurityHandler::INTERNAL_OR_AUTH_TOKEN),
'/v1/calendar/events/staff/{i}' => action(\Controllers\Calendar\CalendarController::clazz(), array(RequestMethod::PUT, RequestMethod::DELETE), SecurityHandler::INTERNAL_OR_AUTH_TOKEN),
// Service Messages
'/v1/service-messages' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz(),
array(RequestMethod::GET, RequestMethod::POST),
SecurityHandler::OPEN),
'/v1/service-messages/{i}' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz(),
array(RequestMethod::PUT, RequestMethod::DELETE),
SecurityHandler::INTERNAL_OR_AUTH_TOKEN),
'/v1-internal/service-messages/{i}/sort/{s}' => action(\Controllers\ServiceMessages\ServiceMessagesController::clazz() . '::sort',
array(RequestMethod::POST),
SecurityHandler::INTERNAL),
/* Internal use only routes */
// Resend email response

@ -111,8 +111,20 @@ require_once(HESK_PATH . 'inc/header.inc.php');
</div>
</div>
</div>
<?php
echo mfh_get_hidden_fields_for_language(array(
'error_loading_events'
));
?>
<div style="display: none">
<p id="lang_error_loading_events"><?php echo $hesklang['error_loading_events']; ?></p>
<p id="setting_default_view"><?php echo $modsForHesk_settings['default_calendar_view']; ?></p>
<p id="setting_first_day_of_week"><?php echo $modsForHesk_settings['first_day_of_week']; ?></p>
</div>
<p id="setting_show_start_time"><?php echo $modsForHesk_settings['calendar_show_start_time']; ?></p>
</div>
<?php
$businessHoursRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`");
while ($row = hesk_dbFetchAssoc($businessHoursRs)):
?>
<p id="business_hours_<?php echo $row['day_of_week']; ?>_start"><?php echo $row['start_time']; ?></p>
<p id="business_hours_<?php echo $row['day_of_week']; ?>_end"><?php echo $row['end_time']; ?></p>
<?php endwhile; ?>

@ -32,6 +32,7 @@ $hesk_settings['possible_ticket_list'] = array(
'staffreplies' => $hesklang['replies'] . ' (' . $hesklang['staff'] . ')',
'lastreplier' => $hesklang['last_replier'],
'time_worked' => $hesklang['ts'],
'due_date' => $hesklang['due_date'],
);
define('HESK_NO_ROBOTS', true);

@ -185,12 +185,34 @@ function hesk_service_message($sm)
?>
<div class="<?php echo $style; ?>">
<?php echo $faIcon == '' ? '' : '<i class="' . $faIcon . '"></i> '; ?>
<b><?php echo $sm['title']; ?></b><?php echo $sm['message']; ?>
<b><?php echo $sm['title']; ?></b><br>
<?php echo $sm['message']; ?>
</div>
<br/>
<?php
} // END hesk_service_message()
function mfh_get_service_messages($location) {
global $hesk_settings;
$language = $hesk_settings['languages'][$hesk_settings['language']]['folder'];
$res = hesk_dbQuery('SELECT `title`, `message`, `style`, `icon` FROM `'.hesk_dbEscape($hesk_settings['db_pfix'])."service_messages` AS `sm`
INNER JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_service_message_to_location` AS `location`
ON `sm`.`id` = `location`.`service_message_id`
AND `location`.`location` = '" . hesk_dbEscape($location) . "'
AND `sm`.`mfh_language` IN ('ALL', '" . hesk_dbEscape($language) . "')
WHERE `type`='0'
ORDER BY `order` ASC");
$sm = array();
while ($row = hesk_dbFetchAssoc($res)) {
$sm[] = $row;
}
return $sm;
}
function hesk_isBannedIP($ip)
{
@ -357,6 +379,16 @@ function hesk_isREQUEST($in)
return isset($_GET[$in]) || isset($_POST[$in]) ? true : false;
} // END hesk_isREQUEST()
function hesk_mb_substr($in, $start, $length)
{
return function_exists('mb_substr') ? mb_substr($in, $start, $length, 'UTF-8') : substr($in, $start, $length);
} // END hesk_mb_substr()
function hesk_mb_strlen($in)
{
return function_exists('mb_strlen') ? mb_strlen($in, 'UTF-8') : strlen($in);
} // END hesk_mb_strlen()
function hesk_mb_strtolower($in) {
return function_exists('mb_strtolower') ? mb_strtolower($in) : strtolower($in);
} // END hesk_mb_strtolower()
@ -455,7 +487,7 @@ function hesk_verifyEmailMatch($trackingID, $my_email = 0, $ticket_email = 0, $e
} // END hesk_verifyEmailMatch()
function hesk_getCustomerEmail($can_remember = 0, $field = '')
function hesk_getCustomerEmail($can_remember = 0, $field = '', $force_only_one = 0)
{
global $hesk_settings, $hesklang;
@ -494,6 +526,11 @@ function hesk_getCustomerEmail($can_remember = 0, $field = '')
// Remove unwanted side-effects
$my_email = hesk_emailCleanup($my_email);
// Force only one email address? Use the first one.
if ($force_only_one) {
$my_email = strtok($my_email, ',');
}
$hesk_settings['e_param'] = '&e=' . rawurlencode($my_email);
$hesk_settings['e_query'] = '&amp;e=' . rawurlencode($my_email);
$hesk_settings['e_email'] = $my_email;
@ -1643,7 +1680,7 @@ function hesk_input($in, $error = 0, $redirect_to = '', $force_slashes = 0, $max
// Check length
if ($max_length) {
$in = substr($in, 0, $max_length);
$in = hesk_mb_substr($in, 0, $max_length);
}
// Return processed value
@ -1663,7 +1700,7 @@ function hesk_validateEmail($address, $error, $required = 1)
$address = str_replace(';', ',', $address);
/* Check if addresses are valid */
$all = explode(',', $address);
$all = array_unique(explode(',',$address));
foreach ($all as $k => $v) {
if (!hesk_isValidEmail($v)) {
unset($all[$k]);
@ -1777,7 +1814,7 @@ function hesk_session_start()
return true;
} else {
global $hesk_settings, $hesklang;
hesk_error("$hesklang[no_session] $hesklang[contact_webmaster] $hesk_settings[webmaster_mail]");
hesk_error("$hesklang[no_session] $hesklang[contact_webmsater] $hesk_settings[webmaster_mail]");
}
} // END hesk_session_start()
@ -2109,6 +2146,31 @@ function mfh_getNumberOfDownloadsForAttachment($att_id, $table = 'attachments')
return $rec['download_count'];
}
function mfh_getAttachmentFileSize($att_id, $table = 'attachments') {
global $hesk_settings;
$res = hesk_dbQuery('SELECT `size` FROM `' . hesk_dbEscape($hesk_settings['db_pfix'] . $table) . "` WHERE `att_id` = " . intval($att_id));
$rec = hesk_dbFetchAssoc($res);
return human_filesize($rec['size']);
}
function human_filesize($bytes, $decimals = 2) {
global $hesklang;
$sz = 'BKMGTP';
$factor = floor((strlen($bytes) - 1) / 3);
if ($factor < strlen($sz)) {
$factorName = @$sz[$factor];
if ($factorName !== 'B') {
$factorName .= 'B';
}
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . ' ' . $factorName;
}
return $hesklang['unknown'];
}
function mfh_getSettings()
{
global $hesk_settings;

@ -66,7 +66,7 @@ function hesk_load_custom_fields($category=0, $use_cache=1)
// Name for display in ticket list; punctuation removed and shortened
$row['title'] = hesk_remove_punctuation($row['name']);
$row['title'] = strlen($row['title']) > 30 ? substr($row['title'], 0, 30) . '...' : $row['title'];
$row['title'] = hesk_mb_strlen($row['title']) > 30 ? hesk_mb_substr($row['title'], 0, 30) . '...' : $row['title'];
// A version with forced punctuation
$row['name:'] = in_array(substr($row['name'], -1), array(':', '?', '!', '.') ) ? $row['name'] : $row['name'] . ':';

@ -50,20 +50,19 @@ function hesk_notifyCustomerForVerifyEmail($email_template = 'verify_email', $ac
$ccEmails = array();
$bccEmails = array();
//TODO Update the email custom field to handle this properly
/*foreach ($hesk_settings['custom_fields'] as $k => $v) {
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if ($v['use']) {
if ($v['type'] == 'email' && !empty($ticket[$k])) {
if ($v['value'] == 'cc') {
if ($v['value']['email_type'] == 'cc') {
$emails = explode(',', $ticket[$k]);
array_push($ccEmails, $emails);
} elseif ($v['value'] == 'bcc') {
} elseif ($v['value']['email_type'] == 'bcc') {
$emails = explode(',', $ticket[$k]);
array_push($bccEmails, $emails);
}
}
}
}*/
}
hesk_mail($ticket['email'], $subject, $message, $htmlMessage, $modsForHesk_settings, $ccEmails, $bccEmails, $hasMessage);
}
@ -95,18 +94,19 @@ function hesk_notifyCustomer($modsForHesk_settings, $email_template = 'new_ticke
$ccEmails = array();
$bccEmails = array();
//TODO Update the email custom field to handle this properly
/*foreach ($hesk_settings['custom_fields'] as $k => $v) {
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if ($v['use']) {
if ($v['type'] == 'email' && !empty($ticket[$k])) {
if ($v['value'] == 'cc') {
array_push($ccEmails, $ticket[$k]);
} elseif ($v['value'] == 'bcc') {
array_push($bccEmails, $ticket[$k]);
if ($v['type'] == 'email' && !empty($ticket[$k]) && isset($v['value']['emails_to_receive'])) {
if ($v['value']['email_type'] == 'cc') {
$emails = explode(',', $ticket[$k]);
array_push($ccEmails, $emails);
} elseif ($v['value']['email_type'] == 'bcc') {
$emails = explode(',', $ticket[$k]);
array_push($bccEmails, $emails);
}
}
}
}*/
}
// Send e-mail
hesk_mail($ticket['email'], $subject, $message, $htmlMessage, $modsForHesk_settings, $ccEmails, $bccEmails, $hasMessage);
@ -513,6 +513,7 @@ function hesk_mail($to, $subject, $message, $htmlMessage, $modsForHesk_settings,
// Remove duplicate recipients
$to_arr = array_unique(explode(',', $to));
$to_arr = array_values($to_arr);
$to = implode(',', $to_arr);
// Use PHP's mail function

@ -175,7 +175,7 @@ header('X-UA-Compatible: IE=edge');
/* If page requires WYSIWYG editor include TinyMCE Javascript */
if (defined('WYSIWYG') && $hesk_settings['kb_wysiwyg']) {
?>
<script type="text/javascript" src="<?php echo HESK_PATH; ?>inc/tiny_mce/3.5.11/tiny_mce.js"></script>
<script type="text/javascript" src="<?php echo HESK_PATH; ?>inc/tiny_mce/3.5.12/tiny_mce.js"></script>
<?php
}

@ -78,6 +78,7 @@ header('X-UA-Compatible: IE=edge');
<script type="text/javascript" src="<?php echo HESK_PATH; ?>internal-api/js/lang.js?v=<?php echo MODS_FOR_HESK_BUILD; ?>"></script>
<script type="text/javascript" src="<?php echo HESK_PATH; ?>js/clipboard.min.js?v=<?php echo MODS_FOR_HESK_BUILD; ?>"></script>
<script type="text/javascript" src="<?php echo HESK_PATH; ?>js/bootstrap-select.js?v=<?php echo MODS_FOR_HESK_BUILD; ?>"></script>
<script type="text/javascript" src="<?php echo HESK_PATH; ?>js/sprintf.min.js?v=<?php echo MODS_FOR_HESK_BUILD; ?>"></script>
<?php
if (defined('EXTRA_JS')) {
echo EXTRA_JS;

@ -26,12 +26,12 @@ function hesk_kbArticleContentPreview($txt)
$txt = strip_tags($txt);
// If text is larger than article preview length, shorten it
if (strlen($txt) > $hesk_settings['kb_substrart']) {
if (hesk_mb_strlen($txt) > $hesk_settings['kb_substrart']) {
// The quick but not 100% accurate way (number of chars displayed may be lower than the limit)
return substr($txt, 0, $hesk_settings['kb_substrart']) . '...';
return hesk_mb_substr($txt, 0, $hesk_settings['kb_substrart']) . '...';
// If you want a more accurate, but also slower way, use this instead
// return hesk_htmlentities( substr( hesk_html_entity_decode($txt), 0, $hesk_settings['kb_substrart'] ) ) . '...';
// return hesk_htmlentities( hesk_mb_substr( hesk_html_entity_decode($txt), 0, $hesk_settings['kb_substrart'] ) ) . '...';
}
return $txt;

@ -366,7 +366,7 @@ function hesk_stripQuotedText($message)
foreach ($hesk_settings['languages'] as $language => $settings) {
if (($found = strpos($message, $settings['hr'])) !== false) {
// "Reply above this line" tag found, strip quoted reply
$message = substr($message, 0, $found);
$message = hesk_mb_substr($message, 0, $found);
$message .= "\n" . $hesklang['qrr'];
// Set language to the detected language

@ -23,7 +23,7 @@ function hesk_newTicket($ticket, $isVerified = true)
global $hesk_settings, $hesklang, $hesk_db_link;
// Generate a subject if necessary
if (strlen($ticket['subject']) < 1)
if (hesk_mb_strlen($ticket['subject']) < 1)
{
$ticket['subject'] = sprintf($hesklang['default_subject'], $ticket['name']);
}

@ -45,7 +45,8 @@ LEFT(`message`, 400) AS `message`,
`replierid`,
`archive`,
`locked`,
`merged`
`merged`,
`due_date`
";
foreach ($hesk_settings['custom_fields'] as $k => $v) {

@ -53,7 +53,7 @@ $mails = mfh_get_mail_headers_for_dropdown($_SESSION['id'], $hesk_settings, $hes
?>
<li <?php echo $active; ?>>
<a href="admin_main.php">
<i class="fa fa-home" <?php echo $iconDisplay; ?>></i> <span><?php echo $hesklang['main_page']; ?></span>
<i class="fa fa-ticket" <?php echo $iconDisplay; ?>></i> <span><?php echo $hesklang['tickets']; ?></span>
</a>
</li>
<?php

@ -57,14 +57,14 @@ $can_view_unassigned = hesk_checkPermission('can_view_unassigned', 0);
$category_options = '';
if (isset($hesk_settings['categories']) && count($hesk_settings['categories'])) {
foreach ($hesk_settings['categories'] as $row['id'] => $row['name']) {
$row['name'] = (strlen($row['name']) > 30) ? substr($row['name'], 0, 30) . '...' : $row['name'];
$row['name'] = (hesk_mb_strlen($row['name']) > 30) ? hesk_mb_substr($row['name'],0,30) . '...' : $row['name'];
$selected = ($row['id'] == $category) ? 'selected="selected"' : '';
$category_options .= '<option value="' . $row['id'] . '" ' . $selected . '>' . $row['name'] . '</option>';
}
} else {
$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)) {
$row['name'] = (strlen($row['name']) > 30) ? substr($row['name'], 0, 30) . '...' : $row['name'];
$row['name'] = (hesk_mb_strlen($row['name']) > 30) ? hesk_mb_substr($row['name'],0,30) . '...' : $row['name'];
$selected = ($row['id'] == $category) ? 'selected="selected"' : '';
$category_options .= '<option value="' . $row['id'] . '" ' . $selected . '>' . $row['name'] . '</option>';
}
@ -436,7 +436,7 @@ $more2 = empty($_GET['more2']) ? 0 : 1;
$v['name'] = $hesklang[$v['name']];
}
$v['name'] = (strlen($v['name']) > 30) ? substr($v['name'], 0, 30) . '...' : $v['name'];
$v['name'] = (hesk_mb_strlen($v['name']) > 30) ? hesk_mb_substr($v['name'],0,30) . '...' : $v['name'];
echo '<option style="background: #ffffff" value="' . $k . '" ' . $selected . '>' . $v['name'] . '</option>';
}
}

@ -238,13 +238,15 @@ if ($total > 0) {
break;
case 2:
$ticket['priority'] = '<span style="color: green; font-size:1.3em" class="fa fa-fw fa-angle-double-down" data-toggle="tooltip" data-placement="top" title="' . $hesklang['medium'] . '"></span>';
$color = $modsForHesk_settings['highlight_ticket_rows_based_on_priority'] ? 'success' : '';
break;
default:
$ticket['priority'] = '<span style="color: blue; font-size:1.3em" class="fa fa-fw fa-long-arrow-down" data-toggle="tooltip" data-placement="top" title="' . $hesklang['low'] . '"></span>';
$color = $modsForHesk_settings['highlight_ticket_rows_based_on_priority'] ? 'info' : '';
}
// Set message (needed for row title)
$ticket['message'] = $first_line . substr(strip_tags($ticket['message']), 0, 200) . '...';
$ticket['message'] = $first_line . hesk_mb_substr(strip_tags($ticket['message']),0,200).'...';
// Start ticket row
echo '
@ -373,6 +375,16 @@ if ($total > 0) {
echo '<td class="' . $color . '">' . $ticket['time_worked'] . '</td>';
}
// Print due date
if (hesk_show_column('due_date')) {
$due_date = $hesklang['none'];
if ($ticket['due_date'] != null) {
$due_date = hesk_date($ticket['due_date'], false, true, false);
}
echo '<td class="' . $color . '">' . ($ticket['due_date'] == null ? 'NONE' : date('Y-m-d', $due_date)) . '</td>';
}
// Print custom fields
foreach ($hesk_settings['custom_fields'] as $key => $value) {
if ($value['use'] && hesk_show_column($key)) {

@ -24,6 +24,7 @@ function mfh_listAttachments($attachments = '', $reply = 0, $is_staff)
if ($is_staff) {
echo '<th>' . $hesklang['download_count'] . '</th>';
}
echo '<th>' . 'File size' . '</th>';
echo '<th>' . $hesklang['action'] . '</th>
</tr>
</thead>';
@ -72,6 +73,7 @@ function mfh_listAttachments($attachments = '', $reply = 0, $is_staff)
if ($is_staff) {
echo '<td>' . mfh_getNumberOfDownloadsForAttachment($att_id) . '</td>';
}
echo '<td>' . mfh_getAttachmentFileSize($att_id) . '</td>';
echo '<td>
<div class="btn-group">';
/* Can edit and delete tickets? */
@ -279,7 +281,6 @@ function display_dropzone_field($url, $id = 'filedrop', $max_files_override = -1
paramName: 'attachment',
url: '" . $url . "',
parallelUploads: ".$max_files.",
uploadMultiple: true,
maxFiles: ".$max_files.",
acceptedFiles: ".json_encode($acceptedFiles).",
maxFilesize: ".$size.", // MB

@ -79,7 +79,6 @@ function print_select_category($number_of_categories)
?>
<div style="text-align: center">
<h3><?php echo $hesklang['select_category_text']; ?></h3>
<div class="select_category">
@ -322,6 +321,13 @@ function print_add_ticket()
<h2><?php hesk_showTopBar($hesklang['submit_ticket']); ?></h2>
<small><?php echo $hesklang['use_form_below']; ?></small>
<div class="blankSpace"></div>
<?php
// Service messages
$service_messages = mfh_get_service_messages('CUSTOMER_SUBMIT_TICKET');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
?>
<div align="left" class="h3"><?php echo $hesklang['add_ticket_general_information']; ?></div>
<div class="footerWithBorder"></div>
@ -892,10 +898,10 @@ function print_add_ticket()
echo '<option '.$selected.'>'.$option.'</option>';
}
echo '</select>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '</select>';
echo '<div class="help-block with-errors"></div>
</div>
</div>';
@ -1315,15 +1321,13 @@ function print_start()
</ol>
<?php
// Service messages
$res = hesk_dbQuery('SELECT `title`, `message`, `style`, `icon` FROM `'.hesk_dbEscape($hesk_settings['db_pfix'])."service_messages` WHERE `type`='0' ORDER BY `order` ASC");
if (hesk_dbNumRows($res) > 0)
{
$service_messages = mfh_get_service_messages('CUSTOMER_HOME');
if (count($service_messages) > 0) {
?>
<div class="row">
<div class="col-md-12">
<?php
while ($sm=hesk_dbFetchAssoc($res))
{
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
?>

@ -5,6 +5,59 @@ require(HESK_PATH . 'install/install_functions.inc.php');
require(HESK_PATH . 'hesk_settings.inc.php');
hesk_dbConnect();
/*
We have four possible validation scenarios:
1. Fresh install - the user has never installed Mods for HESK before. Nothing to validate.
2. Installed a really old version - we don't have a previous version to start from.
3. Installed a recent version, but before migrations began - just pull the version # and use the dictionary below.
4. Migration number present in the settings table. Take that number and run with it.
*/
$tableSql = hesk_dbQuery("SHOW TABLES LIKE '" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings'");
$startingValidationNumber = 1;
if (hesk_dbNumRows($tableSql) > 0) {
// They have installed at LEAST to version 1.6.0. Just pull the version number OR migration number
$migrationNumberSql = hesk_dbQuery("SELECT `Value` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings` WHERE `Key` = 'migrationNumber'");
if ($migrationRow = hesk_dbFetchAssoc($migrationNumberSql)) {
$startingValidationNumber = intval($migrationRow['Value']);
} else {
$versionSql = hesk_dbQuery("SELECT `Value` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings` WHERE `Key` = 'modsForHeskVersion'");
$versionRow = hesk_dbFetchAssoc($versionSql);
$migration_map = array(
// Pre-1.4.0 to 1.5.0 did not have a settings table
'1.6.0' => 22, '1.6.1' => 23, '1.7.0' => 27, '2.0.0' => 37, '2.0.1' => 38, '2.1.0' => 39, '2.1.1' => 42,
'2.2.0' => 47, '2.2.1' => 48, '2.3.0' => 68, '2.3.1' => 69, '2.3.2' => 70, '2.4.0' => 86, '2.4.1' => 87,
'2.4.2' => 88, '2.5.0' => 98, '2.5.1' => 99, '2.5.2' => 100, '2.5.3' => 101, '2.5.4' => 102, '2.5.5' => 103,
'2.6.0' => 121, '2.6.1' => 122, '2.6.2' => 125, '2.6.3' => 126, '2.6.4' => 127, '3.0.0 beta 1' => 130,
'3.0.0 RC 1' => 131, '3.0.0' => 132, '3.0.1' => 133, '3.0.2' => 135, '3.0.3' => 136, '3.0.4' => 137,
'3.0.5' => 138, '3.0.6' => 139, '3.0.7' => 140, '3.1.0' => 153, '3.1.1' => 154
);
$startingValidationNumber = $migration_map[$versionRow['Value']];
}
} else {
// migration # => sql for checking
$versionChecks = array(
// 1.5.0 -> users.active
14 => "SHOW COLUMNS FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` LIKE 'active'",
// 1.4.1 -> denied_emails
11 => "SHOW TABLES LIKE '" . hesk_dbEscape($hesk_settings['db_pfix']) . "denied_emails'",
// 1.4.0 -> denied ips
9 => "SHOW TABLES LIKE '" . hesk_dbEscape($hesk_settings['db_pfix']) . "denied_ips'",
// Pre-1.4.0 but still something -> statuses
7 => "SHOW TABLES LIKE '" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses'"
);
foreach ($versionChecks as $migrationNumber => $sql) {
$rs = hesk_dbQuery($sql);
if (hesk_dbNumRows($rs) > 0) {
$startingValidationNumber = $migrationNumber;
break;
}
}
}
?>
<html>
<head>
@ -26,12 +79,11 @@ hesk_dbConnect();
<div class="container">
<div class="page-header">
<h1>Mods for HESK Database Validation</h1>
<p>The database validation tool will check your database setup to ensure that everything is set up correctly.
As of this time, the database validator assumes you are running the latest version of Mods for HESK (<?php echo MODS_FOR_HESK_NEW_VERSION; ?>)</p>
<p>The database validation tool will check your database setup to ensure that everything is set up correctly.</p>
</div>
<div class="panel panel-success" id="all-good" style="display: none">
<div class="panel-heading">
<h4>Success</h4>
<h4><i class="fa fa-check-circle"></i> Success</h4>
</div>
<div class="panel-body text-center">
<i class="fa fa-check-circle fa-4x" style="color: green"></i><br>
@ -48,6 +100,14 @@ hesk_dbConnect();
<a href="https://developers.phpjunkyard.com/viewforum.php?f=19" target="_blank">PHP Junkyard Forums</a> with this information for assistance.</h4>
</div>
</div>
<div class="panel panel-warning" id="some-skipped" style="display: none">
<div class="panel-heading">
<h4><i class="fa fa-exclamation-triangle"></i> Some Checks Skipped</h4>
</div>
<div class="panel-body">
You are not running the latest version of Mods for HESK, so some checks have been skipped.
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h4>Results</h4>
@ -61,157 +121,192 @@ hesk_dbConnect();
</thead>
<tbody>
<?php
$all_good = true;
$validations = array();
output_header_row('1.0.0 - 1.3.x');
$all_good = run_table_check('statuses');
$all_good &= run_column_check('statuses', 'ID');
$all_good &= run_column_check('statuses', 'TextColor');
$all_good &= run_column_check('statuses', 'IsNewTicketStatus');
$all_good &= run_column_check('statuses', 'IsClosed');
$all_good &= run_column_check('statuses', 'IsClosedByClient');
$all_good &= run_column_check('statuses', 'IsCustomerReplyStatus');
$all_good &= run_column_check('statuses', 'IsStaffClosedOption');
$all_good &= run_column_check('statuses', 'IsStaffReopenedStatus');
$all_good &= run_column_check('statuses', 'IsDefaultStaffReplyStatus');
$all_good &= run_column_check('statuses', 'LockedTicketStatus');
$validations[] = run_table_check('statuses', 7);
$validations[] = run_column_check('statuses', 'ID', 7);
$validations[] = run_column_check('statuses', 'TextColor', 7);
$validations[] = run_column_check('statuses', 'IsNewTicketStatus', 7);
$validations[] = run_column_check('statuses', 'IsClosed', 7);
$validations[] = run_column_check('statuses', 'IsClosedByClient', 7);
$validations[] = run_column_check('statuses', 'IsCustomerReplyStatus', 7);
$validations[] = run_column_check('statuses', 'IsStaffClosedOption', 7);
$validations[] = run_column_check('statuses', 'IsStaffReopenedStatus', 7);
$validations[] = run_column_check('statuses', 'IsDefaultStaffReplyStatus', 7);
$validations[] = run_column_check('statuses', 'LockedTicketStatus', 7);
output_header_row('1.5.0');
$all_good &= run_column_check('users', 'active');
$validations[] = run_column_check('users', 'active', 11);
output_header_row('1.6.0');
$all_good &= run_column_check('users', 'notify_note_unassigned');
$all_good &= run_table_check('settings');
$validations[] = run_column_check('users', 'notify_note_unassigned', 14);
$validations[] = run_table_check('settings', 20);
output_header_row('1.7.0');
$all_good &= run_table_check('verified_emails');
$all_good &= run_table_check('pending_verification_emails');
$all_good &= run_table_check('stage_tickets');
$validations[] = run_table_check('verified_emails', 23);
$validations[] = run_table_check('pending_verification_emails', 24);
$validations[] = run_table_check('stage_tickets', 25);
output_header_row('2.2.0');
$all_good &= run_column_check('statuses', 'IsAutocloseOption');
$all_good &= run_column_check('statuses', 'Closable');
$validations[] = run_column_check('statuses', 'IsAutocloseOption', 42);
$validations[] = run_column_check('statuses', 'Closable', 44);
output_header_row('2.3.0');
$all_good &= run_column_check('service_messages', 'icon');
$all_good &= run_column_check('statuses', 'Key');
$all_good &= run_column_check('tickets', 'latitude');
$all_good &= run_column_check('tickets', 'longitude');
$all_good &= run_column_check('stage_tickets', 'latitude');
$all_good &= run_column_check('stage_tickets', 'longitude');
$all_good &= run_column_check('categories', 'manager');
$all_good &= run_column_check('users', 'permission_template');
$all_good &= run_table_check('permission_templates');
$all_good &= run_column_check('permission_templates', 'id');
$all_good &= run_column_check('permission_templates', 'name');
$all_good &= run_column_check('permission_templates', 'heskprivileges');
$all_good &= run_column_check('permission_templates', 'categories');
$validations[] = run_column_check('service_messages', 'icon', 48);
$validations[] = run_column_check('statuses', 'Key', 49);
$validations[] = run_column_check('tickets', 'latitude', 53);
$validations[] = run_column_check('tickets', 'longitude', 54);
$validations[] = run_column_check('stage_tickets', 'latitude', 55);
$validations[] = run_column_check('stage_tickets', 'longitude', 56);
$validations[] = run_column_check('categories', 'manager', 57);
$validations[] = run_column_check('users', 'permission_template', 62);
$validations[] = run_table_check('permission_templates', 63);
$validations[] = run_column_check('permission_templates', 'id', 63);
$validations[] = run_column_check('permission_templates', 'name', 63);
$validations[] = run_column_check('permission_templates', 'heskprivileges', 63);
$validations[] = run_column_check('permission_templates', 'categories', 63);
output_header_row('2.4.0');
$all_good &= run_table_check('quick_help_sections');
$all_good &= run_column_check('quick_help_sections', 'id');
$all_good &= run_column_check('quick_help_sections', 'location');
$all_good &= run_column_check('quick_help_sections', 'show');
$all_good &= run_table_check('text_to_status_xref');
$all_good &= run_column_check('text_to_status_xref', 'id');
$all_good &= run_column_check('text_to_status_xref', 'language');
$all_good &= run_column_check('text_to_status_xref', 'text');
$all_good &= run_column_check('text_to_status_xref', 'status_id');
$all_good &= run_column_check('statuses', 'sort');
$all_good &= run_column_check('attachments', 'download_count');
$all_good &= run_column_check('kb_attachments', 'download_count');
$all_good &= run_column_check('tickets', 'html');
$all_good &= run_column_check('stage_tickets', 'html');
$all_good &= run_column_check('replies', 'html');
$validations[] = run_table_check('quick_help_sections', 70);
$validations[] = run_column_check('quick_help_sections', 'id', 70);
$validations[] = run_column_check('quick_help_sections', 'location', 70);
$validations[] = run_column_check('quick_help_sections', 'show', 70);
$validations[] = run_table_check('text_to_status_xref', 76);
$validations[] = run_column_check('text_to_status_xref', 'id', 76);
$validations[] = run_column_check('text_to_status_xref', 'language', 76);
$validations[] = run_column_check('text_to_status_xref', 'text', 76);
$validations[] = run_column_check('text_to_status_xref', 'status_id', 76);
$validations[] = run_column_check('statuses', 'sort', 77);
$validations[] = run_column_check('attachments', 'download_count', 80);
$validations[] = run_column_check('kb_attachments', 'download_count', 81);
$validations[] = run_column_check('tickets', 'html', 82);
$validations[] = run_column_check('stage_tickets', 'html', 83);
$validations[] = run_column_check('replies', 'html', 84);
output_header_row('2.5.0');
$all_good &= run_column_check('tickets', 'user_agent');
$all_good &= run_column_check('tickets', 'screen_resolution_width');
$all_good &= run_column_check('tickets', 'screen_resolution_height');
$all_good &= run_column_check('stage_tickets', 'user_agent');
$all_good &= run_column_check('stage_tickets', 'screen_resolution_width');
$all_good &= run_column_check('stage_tickets', 'screen_resolution_height');
$validations[] = run_column_check('tickets', 'user_agent', 89);
$validations[] = run_column_check('tickets', 'screen_resolution_width', 91);
$validations[] = run_column_check('tickets', 'screen_resolution_height', 92);
$validations[] = run_column_check('stage_tickets', 'user_agent', 90);
$validations[] = run_column_check('stage_tickets', 'screen_resolution_width', 93);
$validations[] = run_column_check('stage_tickets', 'screen_resolution_height', 94);
$validations[] = run_setting_check('navbar_title_url', 96);
output_header_row('2.6.0');
$all_good &= run_table_check('logging');
$all_good &= run_column_check('logging', 'id');
$all_good &= run_column_check('logging', 'username');
$all_good &= run_column_check('logging', 'message');
$all_good &= run_column_check('logging', 'severity');
$all_good &= run_column_check('logging', 'location');
$all_good &= run_column_check('logging', 'timestamp');
$all_good &= run_table_check('user_api_tokens');
$all_good &= run_column_check('user_api_tokens', 'id');
$all_good &= run_column_check('user_api_tokens', 'user_id');
$all_good &= run_column_check('user_api_tokens', 'token');
$all_good &= run_table_check('temp_attachment');
$all_good &= run_column_check('temp_attachment', 'id');
$all_good &= run_column_check('temp_attachment', 'file_name');
$all_good &= run_column_check('temp_attachment', 'saved_name');
$all_good &= run_column_check('temp_attachment', 'size');
$all_good &= run_column_check('temp_attachment', 'type');
$all_good &= run_column_check('temp_attachment', 'date_uploaded');
$all_good &= run_table_check('calendar_event');
$all_good &= run_column_check('calendar_event', 'id');
$all_good &= run_column_check('calendar_event', 'start');
$all_good &= run_column_check('calendar_event', 'end');
$all_good &= run_column_check('calendar_event', 'all_day');
$all_good &= run_column_check('calendar_event', 'name');
$all_good &= run_column_check('calendar_event', 'location');
$all_good &= run_column_check('calendar_event', 'comments');
$all_good &= run_column_check('calendar_event', 'category');
$all_good &= run_table_check('calendar_event_reminder');
$all_good &= run_column_check('calendar_event_reminder', 'id');
$all_good &= run_column_check('calendar_event_reminder', 'user_id');
$all_good &= run_column_check('calendar_event_reminder', 'event_id');
$all_good &= run_column_check('calendar_event_reminder', 'amount');
$all_good &= run_column_check('calendar_event_reminder', 'unit');
$all_good &= run_column_check('calendar_event_reminder', 'email_sent');
$all_good &= run_column_check('tickets', 'due_date');
$all_good &= run_column_check('tickets', 'overdue_email_sent');
$all_good &= run_column_check('categories', 'usage');
$all_good &= run_column_check('users', 'notify_overdue_unassigned');
$all_good &= run_column_check('users', 'default_calendar_view');
$validations[] = run_table_check('logging', 105);
$validations[] = run_column_check('logging', 'id', 105);
$validations[] = run_column_check('logging', 'username', 105);
$validations[] = run_column_check('logging', 'message', 105);
$validations[] = run_column_check('logging', 'severity', 105);
$validations[] = run_column_check('logging', 'location', 105);
$validations[] = run_column_check('logging', 'timestamp', 105);
$validations[] = run_table_check('user_api_tokens', 103);
$validations[] = run_column_check('user_api_tokens', 'id', 103);
$validations[] = run_column_check('user_api_tokens', 'user_id', 103);
$validations[] = run_column_check('user_api_tokens', 'token', 103);
$validations[] = run_setting_check('public_api', 104);
$validations[] = run_table_check('temp_attachment', 106);
$validations[] = run_column_check('temp_attachment', 'id', 106);
$validations[] = run_column_check('temp_attachment', 'file_name', 106);
$validations[] = run_column_check('temp_attachment', 'saved_name', 106);
$validations[] = run_column_check('temp_attachment', 'size', 106);
$validations[] = run_column_check('temp_attachment', 'type', 106);
$validations[] = run_column_check('temp_attachment', 'date_uploaded', 106);
$validations[] = run_table_check('calendar_event', 107);
$validations[] = run_column_check('calendar_event', 'id', 107);
$validations[] = run_column_check('calendar_event', 'start', 107);
$validations[] = run_column_check('calendar_event', 'end', 107);
$validations[] = run_column_check('calendar_event', 'all_day', 107);
$validations[] = run_column_check('calendar_event', 'name', 107);
$validations[] = run_column_check('calendar_event', 'location', 107);
$validations[] = run_column_check('calendar_event', 'comments', 107);
$validations[] = run_column_check('calendar_event', 'category', 107);
$validations[] = run_table_check('calendar_event_reminder', 108);
$validations[] = run_column_check('calendar_event_reminder', 'id', 108);
$validations[] = run_column_check('calendar_event_reminder', 'user_id', 108);
$validations[] = run_column_check('calendar_event_reminder', 'event_id', 108);
$validations[] = run_column_check('calendar_event_reminder', 'amount', 108);
$validations[] = run_column_check('calendar_event_reminder', 'unit', 108);
$validations[] = run_column_check('calendar_event_reminder', 'email_sent', 108);
$validations[] = run_column_check('tickets', 'due_date', 109);
$validations[] = run_column_check('tickets', 'overdue_email_sent', 110);
$validations[] = run_column_check('categories', 'usage', 112);
$validations[] = run_column_check('users', 'notify_overdue_unassigned', 113);
$validations[] = run_column_check('users', 'default_calendar_view', 114);
$validations[] = run_setting_check('enable_calendar', 115);
$validations[] = run_setting_check('first_day_of_week', 116);
$validations[] = run_setting_check('default_calendar_view', 117);
output_header_row('2.6.2');
$all_good &= run_column_check('stage_tickets', 'due_date');
$all_good &= run_column_check('stage_tickets', 'overdue_email_sent');
$validations[] = run_column_check('stage_tickets', 'due_date', 122);
$validations[] = run_column_check('stage_tickets', 'overdue_email_sent', 123);
output_header_row('3.1.0');
$all_good &= run_column_check('categories', 'background_color');
$all_good &= run_column_check('categories', 'foreground_color');
$all_good &= run_column_check('categories', 'display_border_outline');
$all_good &= run_column_check('logging', 'stack_trace');
$all_good &= run_table_check('custom_nav_element');
$all_good &= run_column_check('custom_nav_element', 'id');
$all_good &= run_column_check('custom_nav_element', 'image_url');
$all_good &= run_column_check('custom_nav_element', 'font_icon');
$all_good &= run_column_check('custom_nav_element', 'place');
$all_good &= run_column_check('custom_nav_element', 'url');
$all_good &= run_column_check('custom_nav_element', 'sort');
$all_good &= run_table_check('custom_nav_element_to_text');
$all_good &= run_column_check('custom_nav_element_to_text', 'id');
$all_good &= run_column_check('custom_nav_element_to_text', 'nav_element_id');
$all_good &= run_column_check('custom_nav_element_to_text', 'language');
$all_good &= run_column_check('custom_nav_element_to_text', 'text');
$all_good &= run_column_check('custom_nav_element_to_text', 'subtext');
$all_good &= run_setting_check('admin_navbar_background');
$all_good &= run_setting_check('admin_navbar_background_hover');
$all_good &= run_setting_check('admin_navbar_text');
$all_good &= run_setting_check('admin_navbar_text_hover');
$all_good &= run_setting_check('admin_navbar_brand_background');
$all_good &= run_setting_check('admin_navbar_brand_background_hover');
$all_good &= run_setting_check('admin_navbar_brand_text');
$all_good &= run_setting_check('admin_navbar_brand_text_hover');
$all_good &= run_setting_check('admin_sidebar_background');
$all_good &= run_setting_check('admin_sidebar_background_hover');
$all_good &= run_setting_check('admin_sidebar_text');
$all_good &= run_setting_check('admin_sidebar_text_hover');
$all_good &= run_setting_check('admin_sidebar_font_weight');
$all_good &= run_setting_check('admin_sidebar_header_background');
$all_good &= run_setting_check('admin_sidebar_header_text');
$validations[] = run_column_check('logging', 'stack_trace', 140);
$validations[] = run_column_check('categories', 'background_color', 145);
$validations[] = run_column_check('categories', 'foreground_color', 143);
$validations[] = run_column_check('categories', 'display_border_outline', 144);
$validations[] = run_table_check('custom_nav_element', 141);
$validations[] = run_column_check('custom_nav_element', 'id', 141);
$validations[] = run_column_check('custom_nav_element', 'image_url', 141);
$validations[] = run_column_check('custom_nav_element', 'font_icon', 141);
$validations[] = run_column_check('custom_nav_element', 'place', 141);
$validations[] = run_column_check('custom_nav_element', 'url', 141);
$validations[] = run_column_check('custom_nav_element', 'sort', 141);
$validations[] = run_table_check('custom_nav_element_to_text', 142);
$validations[] = run_column_check('custom_nav_element_to_text', 'id', 142);
$validations[] = run_column_check('custom_nav_element_to_text', 'nav_element_id', 142);
$validations[] = run_column_check('custom_nav_element_to_text', 'language', 142);
$validations[] = run_column_check('custom_nav_element_to_text', 'text', 142);
$validations[] = run_column_check('custom_nav_element_to_text', 'subtext', 142);
$validations[] = run_setting_check('admin_navbar_background', 151);
$validations[] = run_setting_check('admin_navbar_background_hover', 151);
$validations[] = run_setting_check('admin_navbar_text', 151);
$validations[] = run_setting_check('admin_navbar_text_hover', 151);
$validations[] = run_setting_check('admin_navbar_brand_background', 151);
$validations[] = run_setting_check('admin_navbar_brand_background_hover', 151);
$validations[] = run_setting_check('admin_navbar_brand_text', 151);
$validations[] = run_setting_check('admin_navbar_brand_text_hover', 151);
$validations[] = run_setting_check('admin_sidebar_background', 151);
$validations[] = run_setting_check('admin_sidebar_background_hover', 151);
$validations[] = run_setting_check('admin_sidebar_text', 151);
$validations[] = run_setting_check('admin_sidebar_text_hover', 151);
$validations[] = run_setting_check('admin_sidebar_font_weight', 151);
$validations[] = run_setting_check('admin_sidebar_header_background', 151);
$validations[] = run_setting_check('admin_sidebar_header_text', 151);
$validations[] = run_setting_check('login_background_type', 146);
$validations[] = run_setting_check('login_background', 147);
$validations[] = run_setting_check('login_box_header', 148);
$validations[] = run_setting_check('login_box_header_image', 149);
$validations[] = run_setting_check('api_url_rewrite', 150);
output_header_row('3.2.0');
$all_good &= run_table_check('audit_trail');
$all_good &= run_table_check('audit_trail_to_replacement_values');
$all_good &= run_column_check('categories', 'mfh_description');
$all_good &= run_column_check('custom_fields', 'mfh_description');
$all_good &= run_setting_check('migrationNumber');
$validations[] = run_table_check('audit_trail', 156);
$validations[] = run_table_check('audit_trail_to_replacement_values', 157);
$validations[] = run_column_check('categories', 'mfh_description', 154);
$validations[] = run_column_check('custom_fields', 'mfh_description', 155);
$validations[] = run_setting_check('migrationNumber', 158);
output_header_row('3.3.0');
$validations[] = run_table_check('mfh_service_message_to_location', 164);
$validations[] = run_column_check('mfh_service_message_to_location', 'service_message_id', 164);
$validations[] = run_column_check('mfh_service_message_to_location', 'location', 164);
$validations[] = run_column_check('service_messages', 'mfh_language', 166);
$validations[] = run_table_check('mfh_calendar_business_hours', 167);
$validations[] = run_setting_check('calendar_show_start_time', 169);
$validations[] = run_setting_check('calendar_show_start_time', 999);
$passed = false;
$failed = false;
$skipped = false;
foreach ($validations as $validation) {
if ($validation === 'SKIPPED') {
$skipped = true;
} elseif ($validation === 'FAIL') {
$failed = true;
} else if ($validation === 'PASS') {
$passed = true;
}
}
if ($all_good) {
if ($passed && !$failed) {
echo "<script>$('#all-good').show()</script>";
} else {
} elseif ($failed) {
echo "<script>$('#not-good').show()</script>";
}
if ($skipped) {
echo "<script>$('#some-skipped').show()</script>";
}
?>
</tbody>
</table>
@ -220,39 +315,53 @@ hesk_dbConnect();
</body>
</html>
<?php
function run_setting_check($setting_name) {
global $hesk_settings;
function run_setting_check($setting_name, $minimumValidationNumber) {
global $hesk_settings, $startingValidationNumber;
$res = run_check("SELECT 1 FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings` WHERE `Key` = '{$setting_name}'");
$all_good = hesk_dbNumRows($res) > 0;
if ($startingValidationNumber < $minimumValidationNumber) {
$checks = 'SKIPPED';
} else {
$res = run_check("SELECT 1 FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings` WHERE `Key` = '{$setting_name}'", false);
$checks = hesk_dbNumRows($res) > 0 ? 'PASS' : 'FAIL';
}
output_result('<b>Setting Exists</b>: ' . $setting_name, $all_good);
output_result('<b>Setting Exists</b>: ' . $setting_name, $checks);
return $all_good !== false;
return $checks;
}
function run_table_check($table_name) {
return run_column_check($table_name, '1');
function run_table_check($table_name, $minimumValidationNumber) {
return run_column_check($table_name, '1', $minimumValidationNumber);
}
function run_column_check($table_name, $column_name) {
global $hesk_settings;
function run_column_check($table_name, $column_name, $minimumValidationNumber) {
global $hesk_settings, $startingValidationNumber;
if ($column_name == '1') {
$all_good = run_check('SELECT ' . $column_name . ' FROM `' . $hesk_settings['db_pfix'] . $table_name . '` LIMIT 1');
if ($startingValidationNumber < $minimumValidationNumber) {
$checks = 'SKIPPED';
} else {
$checks = run_check('SELECT ' . $column_name . ' FROM `' . $hesk_settings['db_pfix'] . $table_name . '` LIMIT 1');
}
output_result('<b>Table Exists</b>: ' . $table_name,
$all_good);
$checks);
} else {
$all_good = run_check('SELECT `' . $column_name . '` FROM `' . $hesk_settings['db_pfix'] . $table_name . '` LIMIT 1');
if ($startingValidationNumber < $minimumValidationNumber) {
$checks = 'SKIPPED';
} else {
$checks = run_check('SELECT `' . $column_name . '` FROM `' . $hesk_settings['db_pfix'] . $table_name . '` LIMIT 1');
}
output_result('<b>Column Exists</b>: ' . $table_name . '.' . $column_name,
$all_good);
$checks);
}
return $all_good !== false;
return $checks;
}
function run_check($sql) {
function run_check($sql, $returnString = true) {
global $hesk_last_query;
global $hesk_db_link;
if (function_exists('mysqli_connect')) {
@ -261,23 +370,43 @@ function run_check($sql) {
}
$hesk_last_query = $sql;
return @mysqli_query($hesk_db_link, $sql);
if ($returnString) {
return @mysqli_query($hesk_db_link, $sql) ? 'PASS' : 'FAIL';
} else {
return @mysqli_query($hesk_db_link, $sql);
}
} else {
if (!$hesk_db_link && !hesk_dbConnect()) {
return false;
}
$hesk_last_query = $sql;
return $res = @mysql_query($sql, $hesk_db_link);
if ($returnString) {
return $res = @mysql_query($sql, $hesk_db_link) ? 'PASS' : 'FAIL';
} else {
return $res = @mysql_query($sql, $hesk_db_link);
}
}
}
function output_result($change_title, $success) {
$css_color = 'success';
$text = '<span data-toggle="tooltip" title="This looks good!"><i class="fa fa-check-circle"></i> Success</span>';
if (!$success) {
$css_color = 'danger';
$text = '<span data-toggle="tooltip" title="Oh no! Something isn\'t right."><i class="fa fa-times-circle"></i> Failure</span>';
function output_result($change_title, $status) {
switch ($status) {
case 'PASS':
$css_color = 'success';
$text = '<span data-toggle="tooltip" title="This looks good!"><i class="fa fa-check-circle"></i> Success</span>';
break;
case 'FAIL':
$css_color = 'danger';
$text = '<span data-toggle="tooltip" title="Oh no! Something isn\'t right."><i class="fa fa-times-circle"></i> Failure</span>';
break;
case 'SKIPPED':
$css_color = 'default';
$text = '<span data-toggle="tooltip" title="Skipped - You are not running a new enough version of Mods for HESK."><i class="fa fa-minus-circle"></i> Skipped</span>';
break;
default:
$css_color = 'danger';
$text = 'WTF?! ' . $status;
}
$formatted_text = sprintf('<tr class="'.$css_color.'"><td>%s</td><td style="color: %s">%s</td></tr>', $change_title, $css_color, $text);

@ -31,9 +31,9 @@ if (hesk_dbNumRows($tableSql) > 0) {
'1.6.0' => 22, '1.6.1' => 23, '1.7.0' => 27, '2.0.0' => 37, '2.0.1' => 38, '2.1.0' => 39, '2.1.1' => 42,
'2.2.0' => 47, '2.2.1' => 48, '2.3.0' => 68, '2.3.1' => 69, '2.3.2' => 70, '2.4.0' => 86, '2.4.1' => 87,
'2.4.2' => 88, '2.5.0' => 98, '2.5.1' => 99, '2.5.2' => 100, '2.5.3' => 101, '2.5.4' => 102, '2.5.5' => 103,
'2.6.0' => 121, '2.6.1' => 122, '2.6.2' => 125, '2.6.3' => 126, '2.6.4' => 127, '3.0.0' => 132, '3.0.1' => 133,
'3.0.2' => 135, '3.0.3' => 136, '3.0.4' => 137, '3.0.5' => 138, '3.0.6' => 139, '3.0.7' => 140, '3.1.0' => 153,
'3.1.1' => 154
'2.6.0' => 121, '2.6.1' => 122, '2.6.2' => 125, '2.6.3' => 126, '2.6.4' => 127, '3.0.0 beta 1' => 130,
'3.0.0 RC 1' => 131, '3.0.0' => 132, '3.0.1' => 133, '3.0.2' => 135, '3.0.3' => 136, '3.0.4' => 137,
'3.0.5' => 138, '3.0.6' => 139, '3.0.7' => 140, '3.1.0' => 153, '3.1.1' => 154
);
$startingMigrationNumber = $migration_map[$versionRow['Value']];
}

@ -15,8 +15,8 @@
if (!defined('IN_SCRIPT')) {die('Invalid attempt');}
// We will be installing this HESK version:
define('HESK_NEW_VERSION','2.7.5');
define('MODS_FOR_HESK_NEW_VERSION','3.2.4');
define('HESK_NEW_VERSION','2.7.6');
define('MODS_FOR_HESK_NEW_VERSION','3.3.0');
define('REQUIRE_PHP_VERSION','5.3.0');
define('REQUIRE_MYSQL_VERSION','5.0.7');

@ -104,10 +104,10 @@ function executeMigration(startingMigrationNumber, migrationNumber, latestMigrat
console.log('latestMigrationNumber: ' + latestMigrationNumber);
console.info('---');
if (migrationNumber === latestMigrationNumber || (migrationNumber === startingMigrationNumber && direction === 'down')) {
updateProgressBar(migrationNumber, latestMigrationNumber, direction === 'down', true);
updateProgressBar(migrationNumber - startingMigrationNumber, latestMigrationNumber - startingMigrationNumber, direction === 'down', true);
console.log('%c Success! ', 'color: white; background-color: green; font-size: 2em');
} else {
updateProgressBar(migrationNumber, latestMigrationNumber, false, false);
updateProgressBar(migrationNumber - startingMigrationNumber, latestMigrationNumber - startingMigrationNumber, false, false);
var newMigrationNumber = direction === 'up' ? migrationNumber + 1 : migrationNumber - 1;
executeMigration(startingMigrationNumber, newMigrationNumber, latestMigrationNumber, direction);
}
@ -121,7 +121,7 @@ function executeMigration(startingMigrationNumber, migrationNumber, latestMigrat
$errorBlock = $('#error-block');
$errorBlock.html($errorBlock.html() + "<br><br>An error occurred! (Error Code: " + migrationNumber + ")<br>" + message).show();
updateProgressBar(migrationNumber, latestMigrationNumber, true, false);
updateProgressBar(migrationNumber - startingMigrationNumber, latestMigrationNumber - startingMigrationNumber, true, false);
if (direction === 'up') {
// Revert!

@ -7,10 +7,12 @@ use AbstractMigration;
class AddIntColumnUpDropTableDown extends AbstractMigration {
function up($hesk_settings) {
$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` ADD COLUMN `status_int` INT NOT NULL DEFAULT 0 AFTER `status`;");
// We no longer need to do this thanks to HESK 2.7.0
//$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` ADD COLUMN `status_int` INT NOT NULL DEFAULT 0 AFTER `status`;");
}
function down($hesk_settings) {
$this->executeQuery("DROP TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses`");
// Moved to migration #2 for clarity
//$this->executeQuery("DROP TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses`");
}
}

@ -23,6 +23,9 @@ class CreateStatusesTable extends \AbstractMigration {
}
function down($hesk_settings) {
$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` ADD COLUMN `status_int` INT NOT NULL AFTER `status`;");
// We no longer need to do this thanks to HESK 2.7.0
//$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` ADD COLUMN `status_int` INT NOT NULL AFTER `status`;");
// Moved from migration #1
$this->executeQuery("DROP TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses`");
}
}

@ -8,14 +8,16 @@ use AbstractMigration;
class DropOldStatusColumn extends AbstractMigration {
function up($hesk_settings) {
$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` DROP COLUMN `status`");
// We no longer need to do this thanks to HESK 2.7.0
//$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` DROP COLUMN `status`");
}
function down($hesk_settings) {
$ticketsRS = $this->executeQuery("SELECT `id`, `status_int` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets`;");
while ($currentResult = hesk_dbFetchAssoc($ticketsRS)) {
$this->executeQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status_int` = '" . intval($currentResult['status']) . "' WHERE `id` = " . $currentResult['id']);
}
// We no longer need to do this thanks to HESK 2.7.0
//$ticketsRS = $this->executeQuery("SELECT `id`, `status_int` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets`;");
//while ($currentResult = hesk_dbFetchAssoc($ticketsRS)) {
//
// $this->executeQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status_int` = '" . intval($currentResult['status_int']) . "' WHERE `id` = " . $currentResult['id']);
//}
}
}

@ -7,14 +7,16 @@ use AbstractMigration;
class MoveStatusesToNewColumn extends AbstractMigration {
function up($hesk_settings) {
$ticketsRS = $this->executeQuery("SELECT `id`, `status` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets`;");
while ($currentResult = hesk_dbFetchAssoc($ticketsRS)) {
$this->executeQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status_int` = " . $currentResult['status'] . " WHERE `id` = " . $currentResult['id']);
}
// We no longer need to do this thanks to HESK 2.7.0
//$ticketsRS = $this->executeQuery("SELECT `id`, `status` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets`;");
//while ($currentResult = hesk_dbFetchAssoc($ticketsRS)) {
//
// $this->executeQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status_int` = " . $currentResult['status'] . " WHERE `id` = " . $currentResult['id']);
//}
}
function down($hesk_settings) {
$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` CHANGE COLUMN `status_int` `status` INT NOT NULL");
// We no longer need to do this thanks to HESK 2.7.0
//$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` CHANGE COLUMN `status_int` `status` INT NOT NULL");
}
}

@ -6,10 +6,12 @@ namespace Pre140\Statuses;
class RenameTempColumn extends \AbstractMigration {
function up($hesk_settings) {
$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` CHANGE COLUMN `status_int` `status` INT NOT NULL");
// We no longer need to do this thanks to HESK 2.7.0
//$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` CHANGE COLUMN `status_int` `status` INT NOT NULL");
}
function down($hesk_settings) {
$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` DROP COLUMN `status`");
// We no longer need to do this thanks to HESK 2.7.0
//$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` DROP COLUMN `status`");
}
}

@ -176,8 +176,8 @@ function getAllMigrations() {
//3.0.0
127 => new \v300\MigrateHeskCustomStatuses(),
128 => new \v300\MigrateAutorefreshOption\UpdateFromOldValue(),
129 => new \v300\MigrateAutorefreshOption\DropOldColumn(),
130 => new \v300\AddColorSchemeSetting(),
129 => new \v300\AddColorSchemeSetting(),
130 => new \v300\MigrateAutorefreshOption\DropOldColumn(),
131 => new LegacyUpdateMigration('3.0.0', '2.6.4'),
//3.0.1
132 => new LegacyUpdateMigration('3.0.1', '3.0.0'),
@ -219,5 +219,13 @@ function getAllMigrations() {
162 => new UpdateMigration('3.2.3', '3.2.2', 162),
163 => new UpdateMigration('3.2.4', '3.2.3', 163),
164 => new UpdateMigration('3.2.5', '3.2.4', 164),
// 3.3.0
165 => new \v330\ServiceMessagesImprovements\CreateServiceMessageToLocationTable(165),
166 => new \v330\ServiceMessagesImprovements\UpdateExistingServiceMessagesLocations(166),
167 => new \v330\ServiceMessagesImprovements\AddLanguageColumnToServiceMessages(167),
168 => new \v330\CalendarImprovements\AddBusinessHoursTable(168),
169 => new \v330\CalendarImprovements\InsertDefaultBusinessHours(169),
170 => new \v330\CalendarImprovements\AddShowStartTimeSetting(170),
171 => new UpdateMigration('3.3.0', '3.2.5', 171),
);
}

@ -17,10 +17,26 @@ class InsertTextToStatusXrefValues extends \AbstractMigration {
$oldSetting = $hesk_settings['can_sel_lang'];
$hesk_settings['can_sel_lang'] = 1;
while ($row = hesk_dbFetchAssoc($statusesRs)) {
$englishText = '';
foreach ($languages as $language => $languageCode) {
hesk_setLanguage($language);
if ($language === 'English') {
if (key_exists($row['Key'], $hesklang)) {
$englishText = $hesklang[$row['Key']];
} else {
$englishText = $row['Key'];
}
}
if (key_exists($row['Key'], $hesklang)) {
$textToInsert = $hesklang[$row['Key']];
} else {
$textToInsert = $englishText;
}
$sql = "INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "text_to_status_xref` (`language`, `text`, `status_id`)
VALUES ('" . hesk_dbEscape($language) . "', '" . hesk_dbEscape($hesklang[$row['Key']]) . "', " . intval($row['ID']) . ")";
VALUES ('" . hesk_dbEscape($language) . "', '" . hesk_dbEscape($textToInsert) . "', " . intval($row['ID']) . ")";
$this->executeQuery($sql);
}
}

@ -0,0 +1,16 @@
<?php
namespace v330;
class AddHighlightTicketRowsSetting extends \AbstractUpdatableMigration {
function innerUp($hesk_settings) {
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings` (`Key`, `Value`)
VALUES ('highlight_ticket_rows_based_on_priority', '0')");
}
function innerDown($hesk_settings) {
$this->executeQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings`
WHERE `Key` = 'highlight_ticket_rows_based_on_priority'");
}
}

@ -0,0 +1,15 @@
<?php
namespace v330\CalendarImprovements;
class AddBusinessHoursTable extends \AbstractUpdatableMigration {
function innerUp($hesk_settings) {
$this->executeQuery("CREATE TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
(`day_of_week` INT NOT NULL, `start_time` VARCHAR(5) NOT NULL, `end_time` VARCHAR(5) NOT NULL)");
}
function innerDown($hesk_settings) {
$this->executeQuery("DROP TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`");
}
}

@ -0,0 +1,17 @@
<?php
namespace v330\CalendarImprovements;
class AddShowStartTimeSetting extends \AbstractUpdatableMigration {
function innerUp($hesk_settings) {
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings` (`Key`, `Value`)
VALUES ('calendar_show_start_time', 'true')");
}
function innerDown($hesk_settings) {
$this->executeQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings`
WHERE `Key` = 'calendar_show_start_time'");
}
}

@ -0,0 +1,28 @@
<?php
namespace v330\CalendarImprovements;
class InsertDefaultBusinessHours extends \AbstractUpdatableMigration {
function innerUp($hesk_settings) {
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours` (`day_of_week`, `start_time`, `end_time`)
VALUES (0, '00:00', '23:59')");
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours` (`day_of_week`, `start_time`, `end_time`)
VALUES (1, '00:00', '23:59')");
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours` (`day_of_week`, `start_time`, `end_time`)
VALUES (2, '00:00', '23:59')");
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours` (`day_of_week`, `start_time`, `end_time`)
VALUES (3, '00:00', '23:59')");
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours` (`day_of_week`, `start_time`, `end_time`)
VALUES (4, '00:00', '23:59')");
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours` (`day_of_week`, `start_time`, `end_time`)
VALUES (5, '00:00', '23:59')");
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours` (`day_of_week`, `start_time`, `end_time`)
VALUES (6, '00:00', '23:59')");
}
function innerDown($hesk_settings) {
$this->executeQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`");
}
}

@ -0,0 +1,17 @@
<?php
namespace v330\ServiceMessagesImprovements;
class AddLanguageColumnToServiceMessages extends \AbstractUpdatableMigration {
function innerUp($hesk_settings) {
$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages`
ADD COLUMN `mfh_language` VARCHAR(255) NOT NULL DEFAULT 'ALL'");
}
function innerDown($hesk_settings) {
$this->executeQuery("ALTER TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages`
DROP COLUMN `mfh_language`");
}
}

@ -0,0 +1,16 @@
<?php
namespace v330\ServiceMessagesImprovements;
class CreateServiceMessageToLocationTable extends \AbstractUpdatableMigration {
function innerUp($hesk_settings) {
$this->executeQuery("CREATE TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_service_message_to_location`
(`service_message_id` INT NOT NULL, `location` VARCHAR(100) NOT NULL)");
}
function innerDown($hesk_settings) {
$this->executeQuery("DROP TABLE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_service_message_to_location`");
}
}

@ -0,0 +1,19 @@
<?php
namespace v330\ServiceMessagesImprovements;
use BusinessLogic\ServiceMessages\ServiceMessageLocation;
class UpdateExistingServiceMessagesLocations extends \AbstractUpdatableMigration {
function innerUp($hesk_settings) {
$this->executeQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_service_message_to_location` (`service_message_id`, `location`)
SELECT `id`, '" . hesk_dbEscape(ServiceMessageLocation::CUSTOMER_HOME) . "' FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages`");
}
function innerDown($hesk_settings) {
$this->executeQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_service_message_to_location`
WHERE `service_message_id` IN (SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages`)");
}
}

@ -1,29 +0,0 @@
<?php
define('IN_SCRIPT', 1);
define('HESK_PATH', '../../');
define('INTERNAL_API_PATH', '../');
require_once(HESK_PATH . 'hesk_settings.inc.php');
require_once(HESK_PATH . 'inc/common.inc.php');
require_once(HESK_PATH . 'inc/attachments.inc.php');
require_once(HESK_PATH . 'inc/posting_functions.inc.php');
require_once(INTERNAL_API_PATH . 'core/output.php');
require_once(INTERNAL_API_PATH . 'dao/calendar_dao.php');
require_once(INTERNAL_API_PATH . 'core/cors.php');
hesk_session_start();
hesk_load_internal_api_database_functions();
hesk_dbConnect();
$modsForHesk_settings = mfh_getSettings();
// Routing
$request_method = $_SERVER['REQUEST_METHOD'];
if ($request_method === 'GET') {
$start = hesk_GET('start');
$end = hesk_GET('end');
$events = get_events($start, $end, $hesk_settings, false);
return output($events);
}
return http_response_code(400);

@ -1,218 +0,0 @@
<?php
function get_events($start, $end, $hesk_settings, $staff = true) {
global $hesk_settings, $hesklang;
$start_time_sql = "CONVERT_TZ(FROM_UNIXTIME(" . hesk_dbEscape($start) . " / 1000), @@session.time_zone, '+00:00')";
$end_time_sql = "CONVERT_TZ(FROM_UNIXTIME(" . hesk_dbEscape($end) . " / 1000), @@session.time_zone, '+00:00')";
$sql = "SELECT `events`.*, `categories`.`name` AS `category_name`, `categories`.`background_color` AS `background_color`,
`categories`.`foreground_color` AS `foreground_color`, `categories`.`display_border_outline` AS `display_border` ";
if ($staff) {
$sql .= ",`reminders`.`amount` AS `reminder_value`, `reminders`.`unit` AS `reminder_unit` ";
}
$sql .= "FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "calendar_event` AS `events`
INNER JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` AS `categories`
ON `events`.`category` = `categories`.`id` ";
if ($staff) {
$sql .= "LEFT JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "calendar_event_reminder` AS `reminders` ON
`reminders`.`user_id` = " . intval($_SESSION['id']) . " AND `reminders`.`event_id` = `events`.`id`";
}
$sql .= "WHERE NOT (`end` < {$start_time_sql} OR `start` > {$end_time_sql}) AND `categories`.`usage` <> 1";
if (!$staff) {
$sql .= " AND `categories`.`type` = '0'";
}
$rs = hesk_dbQuery($sql);
$events = array();
while ($row = hesk_dbFetchAssoc($rs)) {
// Skip the event if the user does not have access to it
if ($staff && !$_SESSION['isadmin'] && !in_array($row['category'], $_SESSION['categories'])) {
continue;
}
mfh_log_debug('Calendar', "Creating event with id: {$row['id']}", '');
$event['type'] = 'CALENDAR';
$event['id'] = intval($row['id']);
$event['startTime'] = $row['start'];
$event['endTime'] = $row['end'];
$event['allDay'] = $row['all_day'] ? true : false;
$event['title'] = $row['name'];
$event['location'] = $row['location'];
$event['comments'] = $row['comments'];
$event['categoryId'] = $row['category'];
$event['categoryName'] = $row['category_name'];
$event['backgroundColor'] = $row['background_color'];
$event['foregroundColor'] = $row['foreground_color'];
$event['displayBorder'] = $row['display_border'];
if ($staff) {
$event['reminderValue'] = $row['reminder_value'];
$event['reminderUnits'] = $row['reminder_unit'];
}
$events[] = $event;
}
if ($staff) {
$old_time_setting = $hesk_settings['timeformat'];
$hesk_settings['timeformat'] = 'Y-m-d';
$current_date = hesk_date();
$hesk_settings['timeformat'] = $old_time_setting;
$sql = "SELECT `trackid`, `subject`, `due_date`, `category`, `categories`.`name` AS `category_name`, `categories`.`background_color` AS `background_color`,
`categories`.`foreground_color` AS `foreground_color`, `categories`.`display_border_outline` AS `display_border`,
CASE WHEN `due_date` < '{$current_date}' THEN 1 ELSE 0 END AS `overdue`, `owner`.`name` AS `owner_name`, `tickets`.`owner` AS `owner_id`,
`tickets`.`priority` AS `priority`
FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` AS `tickets`
INNER JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` AS `categories`
ON `categories`.`id` = `tickets`.`category`
AND `categories`.`usage` <> 2
LEFT JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` AS `owner`
ON `tickets`.`owner` = `owner`.`id`
WHERE `due_date` >= CONVERT_TZ(FROM_UNIXTIME(" . hesk_dbEscape($start)
. " / 1000), @@session.time_zone, '+00:00')
AND `due_date` <= CONVERT_TZ(FROM_UNIXTIME(" . hesk_dbEscape($end) . " / 1000), @@session.time_zone, '+00:00')
AND `status` IN (SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` WHERE `IsClosed` = 0) ";
$rs = hesk_dbQuery($sql);
while ($row = hesk_dbFetchAssoc($rs)) {
// Skip the ticket if the user does not have access to it
if (!hesk_checkPermission('can_view_tickets', 0)
|| ($row['owner_id'] && $row['owner_id'] != $_SESSION['id'] && !hesk_checkPermission('can_view_ass_others', 0))
|| (!$row['owner_id'] && !hesk_checkPermission('can_view_unassigned', 0))) {
continue;
}
$event['type'] = 'TICKET';
$event['trackingId'] = $row['trackid'];
$event['subject'] = $row['subject'];
$event['title'] = $row['subject'];
$event['startTime'] = $row['due_date'];
$event['url'] = $hesk_settings['hesk_url'] . '/' . $hesk_settings['admin_dir'] . '/admin_ticket.php?track=' . $event['trackingId'];
$event['categoryId'] = $row['category'];
$event['categoryName'] = $row['category_name'];
$event['backgroundColor'] = $row['background_color'];
$event['foregroundColor'] = $row['foreground_color'];
$event['displayBorder'] = $row['display_border'];
$event['owner'] = $row['owner_name'];
$priorities = array(
0 => $hesklang['critical'],
1 => $hesklang['high'],
2 => $hesklang['medium'],
3 => $hesklang['low']
);
$event['priority'] = $priorities[$row['priority']];
$events[] = $event;
}
}
return $events;
}
function create_event($event, $hesk_settings) {
// Make sure the user can create events in this category
if (!$_SESSION['isadmin'] && !in_array($event['category'], $_SESSION['categories'])) {
print_error('Access Denied', 'You cannot create an event in this category');
}
$event['start'] = date('Y-m-d H:i:s', strtotime($event['start']));
$event['end'] = date('Y-m-d H:i:s', strtotime($event['end']));
$event['all_day'] = $event['all_day'] ? 1 : 0;
$sql = "INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "calendar_event` (`start`, `end`, `all_day`,
`name`, `location`, `comments`, `category`) VALUES (
'" . hesk_dbEscape($event['start']) . "', '" . hesk_dbEscape($event['end']) . "', '" . hesk_dbEscape($event['all_day']) . "',
'" . hesk_dbEscape(addslashes($event['title'])) . "', '" . hesk_dbEscape(addslashes($event['location'])) . "', '" . hesk_dbEscape(addslashes($event['comments'])) . "',
" . intval($event['category']) . ")";
hesk_dbQuery($sql);
$event_id = hesk_dbInsertID();
if ($event['reminder_amount'] != null) {
$sql = "INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "calendar_event_reminder` (`user_id`, `event_id`,
`amount`, `unit`) VALUES (" . intval($event['reminder_user']) . ", " . intval($event_id) . ", " . intval($event['reminder_amount']) . ",
" . intval($event['reminder_units']) . ")";
hesk_dbQuery($sql);
}
return $event_id;
}
function update_event($event, $hesk_settings) {
// Make sure the user can edit events in this category
if (!$_SESSION['isadmin'] && !in_array($event['category'], $_SESSION['categories'])) {
print_error('Access Denied', 'You cannot edit an event in this category');
}
$event['start'] = date('Y-m-d H:i:s', strtotime($event['start']));
$event['end'] = date('Y-m-d H:i:s', strtotime($event['end']));
if ($event['create_ticket_date'] != null) {
$event['create_ticket_date'] = date('Y-m-d H:i:s', strtotime($event['create_ticket_date']));
}
$event['all_day'] = $event['all_day'] ? 1 : 0;
$event['assign_to'] = $event['assign_to'] != null ? intval($event['assign_to']) : 'NULL';
$sql = "UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "calendar_event` SET `start` = '" . hesk_dbEscape($event['start'])
. "', `end` = '" . hesk_dbEscape($event['end']) . "', `all_day` = '" . hesk_dbEscape($event['all_day']) . "', `name` = '"
. hesk_dbEscape(addslashes($event['title'])) . "', `location` = '" . hesk_dbEscape(addslashes($event['location'])) . "', `comments` = '"
. hesk_dbEscape(addslashes($event['comments'])) . "', `category` = " . intval($event['category']) . " WHERE `id` = " . intval($event['id']);
if ($event['reminder_amount'] != null) {
$delete_sql = "DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "calendar_event_reminder` WHERE `event_id` = " . intval($event['id'])
. " AND `user_id` = " . intval($event['reminder_user']);
hesk_dbQuery($delete_sql);
$insert_sql = "INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "calendar_event_reminder` (`user_id`, `event_id`,
`amount`, `unit`) VALUES (" . intval($event['reminder_user']) . ", " . intval($event['id']) . ", " . intval($event['reminder_amount']) . ",
" . intval($event['reminder_units']) . ")";
hesk_dbQuery($insert_sql);
}
hesk_dbQuery($sql);
}
function delete_event($id, $hesk_settings) {
// Make sure the user can delete events in this category
$categoryRs = hesk_dbQuery('SELECT `category` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'calendar_event` WHERE `id` = ' . intval($id));
$category = hesk_dbFetchAssoc($categoryRs);
if (!$_SESSION['isadmin'] && !in_array($category['category'], $_SESSION['categories'])) {
print_error('Access Denied', 'You cannot delete events in this category');
}
$sql = "DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "calendar_event` WHERE `id` = " . intval($id);
hesk_dbQuery($sql);
}
function update_ticket_due_date($ticket, $hesk_settings) {
$ticket_id_rs = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid` = '" . hesk_dbEscape($ticket['trackid']) . "'");
$ticket_id = hesk_dbFetchAssoc($ticket_id_rs);
$due_date = 'NULL';
$language_key = 'audit_due_date_removed';
$audit_array = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
if ($ticket['due_date'] != NULL) {
$audit_array = array(
0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => date('Y-m-d H:i:s', strtotime($ticket['due_date']))
);
$due_date = "'" . date('Y-m-d H:i:s', strtotime($ticket['due_date'])) . "'";
$language_key = 'audit_due_date_changed';
}
$sql = "UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `due_date` = {$due_date}, `overdue_email_sent` = '0'
WHERE `trackid` = '" . hesk_dbEscape($ticket['trackid']) . "'";
mfh_insert_audit_trail_record($ticket_id['id'], 'TICKET', $language_key, hesk_date(),
$audit_array);
hesk_dbQuery($sql);
}

@ -0,0 +1,361 @@
var serviceMessages = [];
var g_styles = [];
g_styles["ERROR"] = 4;
g_styles["NOTICE"] = 3;
g_styles["INFO"] = 2;
g_styles["SUCCESS"] = 1;
g_styles["NONE"] = 0;
$(document).ready(function() {
loadTable();
bindEditModal();
bindFormSubmit();
bindDeleteButton();
bindCreateModal();
bindSortButtons();
bindPreview();
});
function loadTable() {
$('#overlay').show();
var heskUrl = $('p#hesk-path').text();
var $tableBody = $('#table-body');
$.ajax({
method: 'GET',
url: heskUrl + 'api/index.php/v1/service-messages',
headers: { 'X-Internal-Call': true },
success: function(data) {
$tableBody.html('');
if (data.length === 0) {
$tableBody.append('<tr><td colspan="4">' + mfhLang.text('no_sm') + '</td></tr>');
$('#overlay').hide();
return;
}
var first = true;
var lastElement = null;
$.each(data, function() {
var $template = $($('#service-message-template').html());
$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);
if (this.published) {
$template.find('span[data-property="type"]').text(mfhLang.text('sm_published'));
} else {
$template.find('span[data-property="type"]').text(mfhLang.text('sm_draft'));
}
$template.find('[data-property="language"]').text(this.language === 'ALL' ?
mfhLang.text('all') :
languages[this.language]);
$tableBody.append($template);
serviceMessages[this.id] = this;
lastElement = this;
if (first) {
$template.find('[data-direction="up"]').css('visibility', 'hidden');
first = false;
}
});
if (lastElement) {
//-- Hide the down arrow on the last element
$('[data-value="' + lastElement.id + '"]').parent().parent()
.find('[data-direction="down"]').css('visibility', 'hidden');
}
},
error: function(data) {
mfhAlert.errorWithLog(mfhLang.text('error_retrieving_sm'), data.responseJSON);
console.error(data);
},
complete: function() {
$('#overlay').hide();
}
});
}
function getFormattedTitle(icon, title, style) {
var $template = $($('#service-message-title-template').html());
var alertClass = 'none';
switch (style) {
case 'ERROR':
alertClass = 'alert alert-danger';
break;
case 'NOTICE':
alertClass = 'alert alert-warning';
break;
case 'INFO':
alertClass = 'alert alert-info';
break;
case 'SUCCESS':
alertClass = 'alert alert-success';
break;
}
$template.addClass(alertClass)
.find('[data-property="icon"]').addClass(icon).end()
.find('[data-property="title"]').text(title);
return $template;
}
function getServiceMessagePreview(icon, title, message, style) {
var $template = $('#service-message-preview-template').html();
var alertClass = 'none';
switch (style) {
case 'ERROR':
alertClass = 'alert alert-danger';
break;
case 'NOTICE':
alertClass = 'alert alert-warning';
break;
case 'INFO':
alertClass = 'alert alert-info';
break;
case 'SUCCESS':
alertClass = 'alert alert-success';
break;
}
$template = $template.replace('none', alertClass)
.replace('{{TITLE}}', title)
.replace('{{MESSAGE}}', message);
$template = $($template);
if (icon !== '') {
$template.find('i.fa').removeClass('fa').addClass(icon);
}
return $template;
}
function bindEditModal() {
$(document).on('click', '[data-action="edit"]', function() {
var element = serviceMessages[$(this).parent().parent().find('[data-property="id"]').data('value')];
var $modal = $('#service-message-modal');
$modal.find('#preview-pane').html('').end()
.find('input[name="location[]"]').prop('checked', false);
$modal.find('#edit-label').show();
$modal.find('#create-label').hide();
$modal.find('input[name="style"][value="' + (g_styles[element.style]) + '"]').prop('checked', 'checked').end()
.find('input[name="type"][value="' + (element.published ? 0 : 1) + '"]')
.prop('checked', 'checked').end()
.find('input[name="title"]').val(element.title).end()
.find('input[name="id"]').val(element.id).end()
.find('input[name="order"]').val(element.order).end()
.find('select[name="language"]').val(element.language).end();
setIcon(element.icon);
$.each(element.locations, function() {
$modal.find('input[name="location[]"][value="' + this + '"]').prop('checked', 'checked');
});
if ($('input[name="kb_wysiwyg"]').val() === "1") {
tinyMCE.get('content').setContent(element.message);
} else {
$('textarea[name="message"]').val(element.message);
}
$('.tab-pane#sm-contents').addClass('active');
$('.tab-pane#properties').removeClass('active');
$('.nav-tabs > li').removeClass('active');
$('.nav-tabs > li:first').addClass('active');
$modal.modal('show');
});
}
function bindCreateModal() {
$('#create-button').click(function() {
var $modal = $('#service-message-modal');
$modal.find('#edit-label').hide().end()
.find('#create-label').show().end()
.find('input[name="style"][value="0"]').prop('checked', 'checked').end() // "None" style
.find('input[name="type"][value="0"]').prop('checked', 'checked').end() // Published
.find('input[name="title"]').val('').end()
.find('input[name="id"]').val(-1).end()
.find('input[name="order"]').val('').end()
.find('#preview-pane').html('').end()
.find('input[name="location[]"]').prop('checked', false)
.find('select[name="language"]').val('ALL');
setIcon('');
if ($('input[name="kb_wysiwyg"]').val() === "1") {
tinyMCE.get('content').setContent('');
} else {
$('textarea[name="message"]').val('');
}
$('.tab-pane#sm-contents').addClass('active');
$('.tab-pane#properties').removeClass('active');
$('.nav-tabs > li').removeClass('active');
$('.nav-tabs > li:first').addClass('active');
$modal.modal('show');
});
}
function bindFormSubmit() {
$('form#service-message').submit(function(e) {
e.preventDefault();
var heskUrl = $('p#hesk-path').text();
var $modal = $('#service-message-modal');
var styles = [];
styles[0] = "NONE";
styles[1] = "SUCCESS";
styles[2] = "INFO";
styles[3] = "NOTICE";
styles[4] = "ERROR";
var domLocations = $modal.find('input[name="location[]"]:checked');
var locations = [];
$.each(domLocations, function() {
locations.push($(this).val());
});
var data = {
icon: $modal.find('input[name="icon"]').val(),
title: $modal.find('input[name="title"]').val(),
message: getMessage(),
published: $modal.find('input[name="type"]:checked').val() === "0",
style: styles[$modal.find('input[name="style"]:checked').val()],
order: $modal.find('input[name="order"]').val(),
language: $modal.find('select[name="language"]').val(),
locations: locations
};
var url = heskUrl + 'api/index.php/v1/service-messages/';
var method = 'POST';
var serviceMessageId = parseInt($modal.find('input[name="id"]').val());
if (serviceMessageId !== -1) {
url += serviceMessageId;
method = 'PUT';
}
$modal.find('#action-buttons').find('.cancel-button').attr('disabled', 'disabled');
$modal.find('#action-buttons').find('.save-button').attr('disabled', 'disabled');
$.ajax({
method: 'POST',
url: url,
headers: {
'X-Internal-Call': true,
'X-HTTP-Method-Override': method
},
data: JSON.stringify(data),
success: function(data) {
if (serviceMessageId === -1) {
mfhAlert.success(mfhLang.text('sm_added'));
} else {
mfhAlert.success(mfhLang.text('sm_mdf'));
}
$modal.modal('hide');
loadTable();
},
error: function(data) {
mfhAlert.errorWithLog(mfhLang.text('error_saving_updating_sm'), data.responseJSON);
console.error(data);
},
complete: function(data) {
$modal.find('#action-buttons').find('.cancel-button').removeAttr('disabled');
$modal.find('#action-buttons').find('.save-button').removeAttr('disabled');
}
});
});
}
function bindDeleteButton() {
$(document).on('click', '[data-action="delete"]', function() {
$('#overlay').show();
var heskUrl = $('p#hesk-path').text();
var element = serviceMessages[$(this).parent().parent().find('[data-property="id"]').data('value')];
$.ajax({
method: 'POST',
url: heskUrl + 'api/index.php/v1/service-messages/' + element.id,
headers: {
'X-Internal-Call': true,
'X-HTTP-Method-Override': 'DELETE'
},
success: function() {
mfhAlert.success(mfhLang.text('sm_deleted'));
loadTable();
},
error: function(data) {
$('#overlay').hide();
mfhAlert.errorWithLog(mfhLang.text('error_deleting_sm'), data.responseJSON);
console.error(data);
}
});
});
}
function bindSortButtons() {
$(document).on('click', '[data-action="sort"]', function() {
$('#overlay').show();
var heskUrl = $('p#hesk-path').text();
var direction = $(this).data('direction');
var element = serviceMessages[$(this).parent().parent().parent().find('[data-property="id"]').data('value')];
$.ajax({
method: 'POST',
url: heskUrl + 'api/index.php/v1-internal/service-messages/' + element.id + '/sort/' + direction,
headers: { 'X-Internal-Call': true },
success: function() {
loadTable();
},
error: function(data) {
mfhAlert.errorWithLog(mfhLang.text('error_sorting_categories'), data.responseJSON);
console.error(data);
$('#overlay').hide();
}
})
});
}
function bindPreview() {
$('.preview-button').click(function() {
var styles = [];
styles[0] = "NONE";
styles[1] = "SUCCESS";
styles[2] = "INFO";
styles[3] = "NOTICE";
styles[4] = "ERROR";
var $modal = $('#service-message-modal');
var data = {
icon: $modal.find('input[name="icon"]').val(),
title: $modal.find('input[name="title"]').val(),
message: getMessage(),
published: $modal.find('input[name="type"]:checked').val() === "0",
style: styles[$modal.find('input[name="style"]:checked').val()],
order: $modal.find('input[name="order"]').val()
};
var preview = getServiceMessagePreview(data.icon, data.title, data.message, data.style);
$('#preview-pane').html(preview);
});
}
function getMessage() {
if ($('input[name="kb_wysiwyg"]').val() === "1") {
return tinyMCE.get('content').getContent();
}
return $('textarea[name="message"]').val();
}

@ -12,13 +12,52 @@ $(document).ready(function() {
eventLimit: true,
timeFormat: 'H:mm',
axisFormat: 'H:mm',
displayEventTime: $('#setting_show_start_time').text(),
businessHours: [
{
dow: [0],
start: $('#business_hours_0_start').text(),
end: $('#business_hours_0_end').text()
},
{
dow: [1],
start: $('#business_hours_1_start').text(),
end: $('#business_hours_1_end').text()
},
{
dow: [2],
start: $('#business_hours_2_start').text(),
end: $('#business_hours_2_end').text()
},
{
dow: [3],
start: $('#business_hours_3_start').text(),
end: $('#business_hours_3_end').text()
},
{
dow: [4],
start: $('#business_hours_4_start').text(),
end: $('#business_hours_4_end').text()
},
{
dow: [5],
start: $('#business_hours_5_start').text(),
end: $('#business_hours_5_end').text()
},
{
dow: [6],
start: $('#business_hours_6_start').text(),
end: $('#business_hours_6_end').text()
}
],
firstDay: $('#setting_first_day_of_week').text(),
defaultView: $('#setting_default_view').text().trim(),
events: function(start, end, timezone, callback) {
$.ajax({
url: heskPath + 'internal-api/admin/calendar/?start=' + start + '&end=' + end,
url: heskPath + 'api/index.php/v1/calendar/events/staff?start=' + start + '&end=' + end,
method: 'GET',
dataType: 'json',
headers: { 'X-Internal-Call': true },
success: function(data) {
var events = [];
$(data).each(function() {
@ -61,7 +100,8 @@ $(document).ready(function() {
.find('.popover-owner span').text(event.owner).end()
.find('.popover-subject span').text(event.subject).end()
.find('.popover-category span').text(event.categoryName).end()
.find('.popover-priority span').text(event.priority);
.find('.popover-priority span').text(event.priority)
.find('.popover-status span').text(event.status).end();
} else {
if (event.location === '') {
$contents.find('.popover-location').hide();
@ -124,7 +164,13 @@ $(document).ready(function() {
});
function buildEvent(id, dbObject) {
if (dbObject.type == 'TICKET') {
var priorities = [];
priorities['CRITICAL'] = mfhLang.text('critical');
priorities['HIGH'] = mfhLang.text('high');
priorities['MEDIUM'] = mfhLang.text('medium');
priorities['LOW'] = mfhLang.text('low');
if (dbObject.type === 'TICKET') {
return {
title: dbObject.title,
subject: dbObject.subject,
@ -140,8 +186,9 @@ function buildEvent(id, dbObject) {
categoryName: dbObject.categoryName,
className: 'category-' + dbObject.categoryId,
owner: dbObject.owner,
priority: dbObject.priority,
fontIconMarkup: getIcon(dbObject)
priority: priorities[dbObject.priority],
fontIconMarkup: getIcon(dbObject),
status: dbObject.status
};
}

@ -12,11 +12,49 @@ $(document).ready(function() {
eventLimit: true,
timeFormat: 'H:mm',
axisFormat: 'H:mm',
displayEventTime: $('#setting_show_start_time').text(),
businessHours: [
{
dow: [0],
start: $('#business_hours_0_start').text(),
end: $('#business_hours_0_end').text()
},
{
dow: [1],
start: $('#business_hours_1_start').text(),
end: $('#business_hours_1_end').text()
},
{
dow: [2],
start: $('#business_hours_2_start').text(),
end: $('#business_hours_2_end').text()
},
{
dow: [3],
start: $('#business_hours_3_start').text(),
end: $('#business_hours_3_end').text()
},
{
dow: [4],
start: $('#business_hours_4_start').text(),
end: $('#business_hours_4_end').text()
},
{
dow: [5],
start: $('#business_hours_5_start').text(),
end: $('#business_hours_5_end').text()
},
{
dow: [6],
start: $('#business_hours_6_start').text(),
end: $('#business_hours_6_end').text()
}
],
firstDay: $('#setting_first_day_of_week').text(),
defaultView: $('#setting_default_view').text().trim(),
events: function(start, end, timezone, callback) {
$.ajax({
url: heskPath + 'internal-api/calendar/?start=' + start + '&end=' + end,
url: heskPath + 'api/index.php/v1/calendar/events/?start=' + start + '&end=' + end,
method: 'GET',
dataType: 'json',
success: function(data) {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save