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/tabs/tabber.css
inc/timer/hesk_timer.js inc/timer/hesk_timer.js
inc/timer/index.htm inc/timer/index.htm
inc/tiny_mce/3.5.11/langs/en.js inc/tiny_mce/3.5.12/langs/en.js
inc/tiny_mce/3.5.11/license.txt inc/tiny_mce/3.5.12/license.txt
inc/tiny_mce/3.5.11/themes/advanced/about.htm inc/tiny_mce/3.5.12/themes/advanced/about.htm
inc/tiny_mce/3.5.11/themes/advanced/anchor.htm inc/tiny_mce/3.5.12/themes/advanced/anchor.htm
inc/tiny_mce/3.5.11/themes/advanced/charmap.htm inc/tiny_mce/3.5.12/themes/advanced/charmap.htm
inc/tiny_mce/3.5.11/themes/advanced/color_picker.htm inc/tiny_mce/3.5.12/themes/advanced/color_picker.htm
inc/tiny_mce/3.5.11/themes/advanced/editor_template.js inc/tiny_mce/3.5.12/themes/advanced/editor_template.js
inc/tiny_mce/3.5.11/themes/advanced/image.htm inc/tiny_mce/3.5.12/themes/advanced/image.htm
inc/tiny_mce/3.5.11/themes/advanced/img/colorpicker.jpg inc/tiny_mce/3.5.12/themes/advanced/img/colorpicker.jpg
inc/tiny_mce/3.5.11/themes/advanced/img/flash.gif inc/tiny_mce/3.5.12/themes/advanced/img/flash.gif
inc/tiny_mce/3.5.11/themes/advanced/img/icons.gif inc/tiny_mce/3.5.12/themes/advanced/img/icons.gif
inc/tiny_mce/3.5.11/themes/advanced/img/iframe.gif inc/tiny_mce/3.5.12/themes/advanced/img/iframe.gif
inc/tiny_mce/3.5.11/themes/advanced/img/pagebreak.gif inc/tiny_mce/3.5.12/themes/advanced/img/pagebreak.gif
inc/tiny_mce/3.5.11/themes/advanced/img/quicktime.gif inc/tiny_mce/3.5.12/themes/advanced/img/quicktime.gif
inc/tiny_mce/3.5.11/themes/advanced/img/realmedia.gif inc/tiny_mce/3.5.12/themes/advanced/img/realmedia.gif
inc/tiny_mce/3.5.11/themes/advanced/img/shockwave.gif inc/tiny_mce/3.5.12/themes/advanced/img/shockwave.gif
inc/tiny_mce/3.5.11/themes/advanced/img/trans.gif inc/tiny_mce/3.5.12/themes/advanced/img/trans.gif
inc/tiny_mce/3.5.11/themes/advanced/img/video.gif inc/tiny_mce/3.5.12/themes/advanced/img/video.gif
inc/tiny_mce/3.5.11/themes/advanced/img/windowsmedia.gif inc/tiny_mce/3.5.12/themes/advanced/img/windowsmedia.gif
inc/tiny_mce/3.5.11/themes/advanced/js/about.js inc/tiny_mce/3.5.12/themes/advanced/js/about.js
inc/tiny_mce/3.5.11/themes/advanced/js/anchor.js inc/tiny_mce/3.5.12/themes/advanced/js/anchor.js
inc/tiny_mce/3.5.11/themes/advanced/js/charmap.js inc/tiny_mce/3.5.12/themes/advanced/js/charmap.js
inc/tiny_mce/3.5.11/themes/advanced/js/color_picker.js inc/tiny_mce/3.5.12/themes/advanced/js/color_picker.js
inc/tiny_mce/3.5.11/themes/advanced/js/image.js inc/tiny_mce/3.5.12/themes/advanced/js/image.js
inc/tiny_mce/3.5.11/themes/advanced/js/link.js inc/tiny_mce/3.5.12/themes/advanced/js/link.js
inc/tiny_mce/3.5.11/themes/advanced/js/source_editor.js inc/tiny_mce/3.5.12/themes/advanced/js/source_editor.js
inc/tiny_mce/3.5.11/themes/advanced/langs/en.js inc/tiny_mce/3.5.12/themes/advanced/langs/en.js
inc/tiny_mce/3.5.11/themes/advanced/langs/en_dlg.js inc/tiny_mce/3.5.12/themes/advanced/langs/en_dlg.js
inc/tiny_mce/3.5.11/themes/advanced/link.htm inc/tiny_mce/3.5.12/themes/advanced/link.htm
inc/tiny_mce/3.5.11/themes/advanced/shortcuts.htm inc/tiny_mce/3.5.12/themes/advanced/shortcuts.htm
inc/tiny_mce/3.5.11/themes/advanced/skins/default/content.css inc/tiny_mce/3.5.12/themes/advanced/skins/default/content.css
inc/tiny_mce/3.5.11/themes/advanced/skins/default/dialog.css inc/tiny_mce/3.5.12/themes/advanced/skins/default/dialog.css
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/buttons.png inc/tiny_mce/3.5.12/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.12/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.12/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.12/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.12/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.12/themes/advanced/skins/default/img/tabs.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/ui.css inc/tiny_mce/3.5.12/themes/advanced/skins/default/ui.css
inc/tiny_mce/3.5.11/themes/advanced/source_editor.htm inc/tiny_mce/3.5.12/themes/advanced/source_editor.htm
inc/tiny_mce/3.5.11/tiny_mce.js inc/tiny_mce/3.5.12/tiny_mce.js
inc/tiny_mce/3.5.11/tiny_mce_popup.js inc/tiny_mce/3.5.12/tiny_mce_popup.js
inc/tiny_mce/3.5.11/utils/editable_selects.js inc/tiny_mce/3.5.12/utils/editable_selects.js
inc/tiny_mce/3.5.11/utils/form_utils.js inc/tiny_mce/3.5.12/utils/form_utils.js
inc/tiny_mce/3.5.11/utils/mctabs.js inc/tiny_mce/3.5.12/utils/mctabs.js
inc/tiny_mce/3.5.11/utils/validate.js inc/tiny_mce/3.5.12/utils/validate.js
inc/treemenu/TreeMenu.php inc/treemenu/TreeMenu.php
inc/treemenu/index.htm inc/treemenu/index.htm
inc/zip/Zip.php inc/zip/Zip.php

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

@ -54,7 +54,15 @@ else {
?> ?>
<div class="content-wrapper"> <div class="content-wrapper">
<section class="content"> <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">
<div class="box-header with-border"> <div class="box-header with-border">
<h1 class="box-title"> <h1 class="box-title">

@ -93,19 +93,20 @@ if ($hesk_settings['attachments']['use'] && !defined('HESK_DEMO')) {
$tmp = @ini_get('upload_max_filesize'); $tmp = @ini_get('upload_max_filesize');
if ($tmp) { if ($tmp) {
$last = strtoupper(substr($tmp, -1)); $last = strtoupper(substr($tmp, -1));
$number = substr($tmp, 0, -1);
switch ($last) { switch ($last) {
case 'K': case 'K':
$tmp = $tmp * 1024; $tmp = $number * 1024;
break; break;
case 'M': case 'M':
$tmp = $tmp * 1048576; $tmp = $number * 1048576;
break; break;
case 'G': case 'G':
$tmp = $tmp * 1073741824; $tmp = $number * 1073741824;
break; break;
default: default:
$tmp = $tmp; $tmp = $number;
} }
if ($tmp < $hesk_settings['attachments']['max_size']) { 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'); $tmp = @ini_get('post_max_size');
if ($tmp) { if ($tmp) {
$last = strtoupper(substr($tmp, -1)); $last = strtoupper(substr($tmp, -1));
$number = substr($tmp, 0, -1);
switch ($last) { switch ($last) {
case 'K': case 'K':
$tmp = $tmp * 1024; $tmp = $number * 1024;
break; break;
case 'M': case 'M':
$tmp = $tmp * 1048576; $tmp = $number * 1048576;
break; break;
case 'G': case 'G':
$tmp = $tmp * 1073741824; $tmp = $number * 1073741824;
break; break;
default: default:
$tmp = $tmp; $tmp = $number;
} }
if ($tmp < ($hesk_settings['attachments']['max_size'] * $hesk_settings['attachments']['max_number'] + 524288)) { if ($tmp < ($hesk_settings['attachments']['max_size'] * $hesk_settings['attachments']['max_number'] + 524288)) {
@ -2220,6 +2222,106 @@ $modsForHesk_settings = mfh_getSettings();
</select> </select>
</div> </div>
</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>
</div> </div>
@ -3272,6 +3374,27 @@ $modsForHesk_settings = mfh_getSettings();
</div> </div>
</div> </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"> <div class="form-group">
<label for="s_submittedformat" class="col-sm-4 control-label"><?php echo $hesklang['sdf']; ?> <a <label for="s_submittedformat" class="col-sm-4 control-label"><?php echo $hesklang['sdf']; ?> <a
href="Javascript:void(0)" href="Javascript:void(0)"
@ -3387,13 +3510,13 @@ $modsForHesk_settings = mfh_getSettings();
<h4 class="bold"><?php echo $hesklang['other']; ?></h4> <h4 class="bold"><?php echo $hesklang['other']; ?></h4>
<div class="form-group"> <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)" href="Javascript:void(0)"
onclick="Javascript:hesk_window('<?php echo $help_folder; ?>misc.html#61','400','500')"><i onclick="Javascript:hesk_window('<?php echo $help_folder; ?>misc.html#61','400','500')"><i
class="fa fa-question-circle settingsquestionmark"></i></a></label> class="fa fa-question-circle settingsquestionmark"></i></a></label>
<div class="col-sm-8"> <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']; ?>"/> value="<?php echo $hesk_settings['ip_whois']; ?>"/>
</div> </div>
</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'; $set['timeformat'] = hesk_input(hesk_POST('s_timeformat')) or $set['timeformat'] = 'Y-m-d H:i:s';
/* --> Other */ /* --> 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 no {IP} tag append it to the end
if (strlen($set['ip_whois']) == 0) { 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['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['mfh_attachments'] = empty($_POST['email_attachments']) ? 0 : 1;
$set['show_number_merged'] = empty($_POST['show_number_merged']) ? 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['request_location'] = empty($_POST['request_location']) ? 0 : 1;
$set['category_order_column'] = empty($_POST['category_order_column']) ? 'cat_order' : 'name'; $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['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['first_day_of_week'] = hesk_POST('first-day-of-week', 0);
$set['default_view'] = hesk_POST('default-view', 'month'); $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']) { if ($set['customer-email-verification-required']) {
//-- Don't allow multiple emails if verification is 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_background_type'] = hesk_input(hesk_POST('login-background'));
$set['login_box_header'] = hesk_input(hesk_POST('login-box-header')); $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; $changedBackground = false;
$loadedAttachmentFuncs = 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('new_kb_article_visibility', $set['new_kb_article_visibility']);
mfh_updateSetting('attachments', $set['mfh_attachments']); mfh_updateSetting('attachments', $set['mfh_attachments']);
mfh_updateSetting('show_number_merged', $set['show_number_merged']); 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('request_location', $set['request_location']);
mfh_updateSetting('category_order_column', $set['category_order_column'], true); mfh_updateSetting('category_order_column', $set['category_order_column'], true);
mfh_updateSetting('rich_text_for_tickets', $set['rich_text_for_tickets']); 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('enable_calendar', $set['enable_calendar'], false);
mfh_updateSetting('first_day_of_week', $set['first_day_of_week'], false); mfh_updateSetting('first_day_of_week', $set['first_day_of_week'], false);
mfh_updateSetting('default_calendar_view', $set['default_view'], true); 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('admin_color_scheme', $set['admin_color_scheme'], true);
mfh_updateSetting('login_background_type', $set['login_background_type'], 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); 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 // Prepare settings file and save it
$settings_file_content = '<?php $settings_file_content = '<?php
// Settings file for HESK ' . $set['hesk_version'] . ' // 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 */ /* This will handle error, success and notice messages */
hesk_handle_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 // Prepare special custom fields
foreach ($hesk_settings['custom_fields'] as $k=>$v) { foreach ($hesk_settings['custom_fields'] as $k=>$v) {
if ($v['use'] && hesk_is_custom_field_in_category($k, $ticket['category']) ) { 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 ' echo '
<a href="../download_attachment.php?att_id=' . $att_id . '&amp;track=' . $trackingID . '"> <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>
<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>
<div class="col-sm-4"> <div class="col-sm-4">
<select name="reminder-unit" class="form-control"> <select name="reminder-unit" class="form-control">
<option value="0"><?php echo $hesklang['event_min_before_event']; ?></option> <option value="MINUTE"><?php echo $hesklang['event_min_before_event']; ?></option>
<option value="1"><?php echo $hesklang['event_hours_before_event']; ?></option> <option value="HOUR"><?php echo $hesklang['event_hours_before_event']; ?></option>
<option value="2"><?php echo $hesklang['event_days_before_event']; ?></option> <option value="DAY"><?php echo $hesklang['event_days_before_event']; ?></option>
<option value="3"><?php echo $hesklang['event_weeks_before_event']; ?></option> <option value="WEEK"><?php echo $hesklang['event_weeks_before_event']; ?></option>
</select> </select>
</div> </div>
</div> </div>
@ -334,147 +334,168 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div> </div>
<form id="edit-form" class="form-horizontal" data-toggle="validator"> <form id="edit-form" class="form-horizontal" data-toggle="validator">
<div class="modal-body"> <div class="modal-body">
<div class="row"> <ul class="nav nav-tabs" role="tablist" id="edit-modal-tabs">
<div class="col-md-12"> <li role="presentation" class="active"><a href="#edit-contents" aria-controls="home" role="tab" data-toggle="tab"><?php echo $hesklang['information']; ?></a></li>
<div class="form-group"> <li role="presentation"><a href="#edit-history" aria-controls="profile" role="tab" data-toggle="tab"><?php echo $hesklang['thist']; ?></a></li>
<label for="name" class="col-sm-3 control-label"> </ul>
<?php echo $hesklang['event_title']; ?> <div class="tab-content" id="information-tab">
<i class="fa fa-question-circle settingsquestionmark" <div role="tabpanel" class="tab-pane active" id="edit-contents">
data-toggle="tooltip" <br>
title="<?php echo htmlspecialchars($hesklang['event_title_tooltip']); ?>"></i></label> <div class="row">
<div class="col-sm-9"> <div class="col-md-12">
<input type="text" name="name" class="form-control" <div class="form-group">
placeholder="<?php echo htmlspecialchars($hesklang['event_title']); ?>" <label for="name" class="col-sm-3 control-label">
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>" <?php echo $hesklang['event_title']; ?>
required> <i class="fa fa-question-circle settingsquestionmark"
<div class="help-block with-errors"></div> data-toggle="tooltip"
</div> title="<?php echo htmlspecialchars($hesklang['event_title_tooltip']); ?>"></i></label>
</div> <div class="col-sm-9">
<div class="form-group"> <input type="text" name="name" class="form-control"
<label for="location" class="col-sm-3 control-label"> placeholder="<?php echo htmlspecialchars($hesklang['event_title']); ?>"
<?php echo $hesklang['event_location']; ?> data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
<i class="fa fa-question-circle settingsquestionmark" required>
data-toggle="tooltip" <div class="help-block with-errors"></div>
title="<?php echo htmlspecialchars($hesklang['event_location_tooltip']); ?>"></i> </div>
</label> </div>
<div class="col-sm-9"> <div class="form-group">
<input type="text" name="location" class="form-control" <label for="location" class="col-sm-3 control-label">
placeholder="<?php echo htmlspecialchars($hesklang['event_location']); ?>"> <?php echo $hesklang['event_location']; ?>
<div class="help-block with-errors"></div> <i class="fa fa-question-circle settingsquestionmark"
</div> data-toggle="tooltip"
</div> title="<?php echo htmlspecialchars($hesklang['event_location_tooltip']); ?>"></i>
<div class="form-group"> </label>
<label for="category" class="col-sm-3 control-label"> <div class="col-sm-9">
<?php echo $hesklang['category']; ?> <input type="text" name="location" class="form-control"
<i class="fa fa-question-circle settingsquestionmark" placeholder="<?php echo htmlspecialchars($hesklang['event_location']); ?>">
data-toggle="tooltip" <div class="help-block with-errors"></div>
title="<?php echo htmlspecialchars($hesklang['event_category_tooltip']); ?>"></i> </div>
</label> </div>
<div class="col-sm-9"> <div class="form-group">
<select name="category" class="form-control" <label for="category" class="col-sm-3 control-label">
pattern="[0-9]+" <?php echo $hesklang['category']; ?>
data-error="<?php echo htmlspecialchars($hesklang['sel_app_cat']); ?>" required> <i class="fa fa-question-circle settingsquestionmark"
<?php data-toggle="tooltip"
if ($hesk_settings['select_cat']) { title="<?php echo htmlspecialchars($hesklang['event_category_tooltip']); ?>"></i>
echo '<option value="">'.$hesklang['select'].'</option>'; </label>
} <div class="col-sm-9">
foreach ($categories as $category): ?> <select name="category" class="form-control"
<option value="<?php echo $category['id']; ?>" data-background-color="<?php echo htmlspecialchars($category['background_color']); ?>" pattern="[0-9]+"
data-foreground-color="<?php echo htmlspecialchars($category['foreground_color']); ?>" data-error="<?php echo htmlspecialchars($hesklang['sel_app_cat']); ?>" required>
data-display-border="<?php echo htmlspecialchars($category['display_border_outline']); ?>"> <?php
<?php echo $category['name']; ?> if ($hesk_settings['select_cat']) {
</option> echo '<option value="">'.$hesklang['select'].'</option>';
<?php endforeach; ?> }
</select> foreach ($categories as $category): ?>
<div class="help-block with-errors"></div> <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> <div class="row">
</div> <div class="col-md-6">
<div class="row"> <div class="form-group">
<div class="col-md-6"> <label for="start-date" class="col-sm-6 control-label">
<div class="form-group"> <?php echo $hesklang['event_start']; ?>
<label for="start-date" class="col-sm-6 control-label"> <i class="fa fa-question-circle settingsquestionmark"
<?php echo $hesklang['event_start']; ?> data-toggle="tooltip"
<i class="fa fa-question-circle settingsquestionmark" title="<?php echo htmlspecialchars($hesklang['event_start_tooltip']); ?>"></i>
data-toggle="tooltip" </label>
title="<?php echo htmlspecialchars($hesklang['event_start_tooltip']); ?>"></i> <div class="col-sm-6">
</label> <input type="text" name="start-date" class="form-control datepicker"
<div class="col-sm-6"> placeholder="<?php echo htmlspecialchars($hesklang['event_start_date']); ?>"
<input type="text" name="start-date" class="form-control datepicker" data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
placeholder="<?php echo htmlspecialchars($hesklang['event_start_date']); ?>" required>
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>" <input type="text" name="start-time" class="form-control clockpicker"
required> placeholder="<?php echo htmlspecialchars($hesklang['event_start_time']); ?>"
<input type="text" name="start-time" class="form-control clockpicker" data-placement="left" data-align="top" data-autoclose="true">
placeholder="<?php echo htmlspecialchars($hesklang['event_start_time']); ?>" <div class="help-block with-errors"></div>
data-placement="left" data-align="top" data-autoclose="true">
<div class="help-block with-errors"></div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="all-day"> <?php echo $hesklang['event_all_day']; ?> <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> </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> </div>
</div> <div class="row">
<div class="col-md-6"> <div class="col-md-12">
<div class="form-group"> <div class="form-group">
<label for="end-date" class="col-sm-6 control-label"> <label for="reminder" class="col-sm-3 control-label">
<?php echo $hesklang['event_end']; ?> <?php echo $hesklang['event_reminder']; ?>
<i class="fa fa-question-circle settingsquestionmark" <i class="fa fa-question-circle settingsquestionmark"
data-toggle="tooltip" data-toggle="tooltip"
title="<?php echo htmlspecialchars($hesklang['event_end_tooltip']); ?>"></i> title="<?php echo htmlspecialchars($hesklang['event_reminder_tooltip']); ?>"></i>
</label> </label>
<div class="col-sm-6"> <div class="col-sm-2">
<input type="text" name="end-date" class="form-control datepicker" <input type="text" name="reminder-value" class="form-control" placeholder="#">
placeholder="<?php echo htmlspecialchars($hesklang['event_end_date']); ?>" </div>
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>" <div class="col-sm-4">
required> <select name="reminder-unit" class="form-control">
<input type="text" name="end-time" class="form-control clockpicker" <option value="MINUTE"><?php echo $hesklang['event_min_before_event']; ?></option>
data-placement="left" data-align="top" data-autoclose="true" <option value="HOUR"><?php echo $hesklang['event_hours_before_event']; ?></option>
placeholder="<?php echo htmlspecialchars($hesklang['event_end_time']); ?>"> <option value="DAY"><?php echo $hesklang['event_days_before_event']; ?></option>
<div class="help-block with-errors"></div> <option value="WEEK"><?php echo $hesklang['event_weeks_before_event']; ?></option>
</select>
</div>
</div>
</div> </div>
</div> </div>
</div> <div class="row">
</div> <div class="col-md-12">
<div class="row"> <div class="form-group">
<div class="col-md-12"> <label for="comments" class="col-sm-3 control-label">
<div class="form-group"> <?php echo $hesklang['event_comments']; ?>
<label for="reminder" class="col-sm-3 control-label"> <i class="fa fa-question-circle settingsquestionmark"
<?php echo $hesklang['event_reminder']; ?> data-toggle="tooltip"
<i class="fa fa-question-circle settingsquestionmark" title="<?php echo htmlspecialchars($hesklang['event_comments_tooltip']); ?>"></i>
data-toggle="tooltip" </label>
title="<?php echo htmlspecialchars($hesklang['event_reminder_tooltip']); ?>"></i> <div class="col-sm-9">
</label> <textarea name="comments" class="form-control" placeholder="<?php echo htmlspecialchars($hesklang['event_comments']); ?>"></textarea>
<div class="col-sm-2"> </div>
<input type="text" name="reminder-value" class="form-control" placeholder="#"> </div>
</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> </div>
</div> </div>
</div> </div>
</div> <div role="tabpanel" class="tab-pane" id="edit-history">
<div class="row"> <br>
<div class="col-md-12"> <table class="table table-striped">
<div class="form-group"> <thead>
<label for="comments" class="col-sm-3 control-label"> <tr>
<?php echo $hesklang['event_comments']; ?> <th><?php echo $hesklang['date']; ?></th>
<i class="fa fa-question-circle settingsquestionmark" <th><?php echo $hesklang['description']; ?></th>
data-toggle="tooltip" </tr>
title="<?php echo htmlspecialchars($hesklang['event_comments_tooltip']); ?>"></i> </thead>
</label> <tbody id="history-table"></tbody>
<div class="col-sm-9"> </table>
<textarea name="comments" class="form-control" placeholder="<?php echo htmlspecialchars($hesklang['event_comments']); ?>"></textarea>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -545,22 +566,34 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<strong><?php echo $hesklang['category']; ?></strong> <strong><?php echo $hesklang['category']; ?></strong>
<span></span> <span></span>
</div> </div>
<div class="popover-status">
<strong><?php echo $hesklang['status']; ?></strong>
<span></span>
</div>
<div class="popover-priority"> <div class="popover-priority">
<strong><?php echo $hesklang['priority']; ?></strong> <strong><?php echo $hesklang['priority']; ?></strong>
<span></span> <span></span>
</div> </div>
</div> </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"> <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_first_day_of_week"><?php echo $modsForHesk_settings['first_day_of_week']; ?></p>
<p id="setting_default_view"> <p id="setting_default_view">
<?php <?php
@ -572,7 +605,21 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
echo $view_array[$_SESSION['default_calendar_view']]; echo $view_array[$_SESSION['default_calendar_view']];
?> ?>
</p> </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> </div>
<script type="text/html" id="audit-trail-template">
<tr>
<td data-property="date"></td>
<td data-property="description"></td>
</tr>
</script>
<?php <?php
require_once(HESK_PATH . 'inc/footer.inc.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']; ?> <?php echo $hesklang['email_custom_field_label']; ?>
</label> </label>
<div class="col-sm-8"> <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"> <div class="radio">
<label> <label>
<input type="radio" name="email_type" value="none" <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 'hidden':
case 'readonly': case 'readonly':
default: default:
if (strlen($k_value) != 0) { $k_value = hesk_msgToPlain($k_value,0,0);
$v['value']['default_value'] = $k_value;
}
$cls = in_array($k, $_SESSION['iserror']) ? ' isError' : ''; $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 . '"> <div class="form-group' . $cls . '">
<label for="' . $k . '" class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label> <label for="' . $k . '" class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label>
<div class="col-sm-9"> <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'])) { if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>'; 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>
<div class="form-group" style="text-align: center"> <div class="form-group">
<?php <div class="col-md-9 col-md-offset-3">
$html = $ticket['html'] ? 1 : 0; <?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"> <input type="hidden" name="html" value="<?php echo $html; ?>">
<?php if (isset($_REQUEST['isManager']) && $_REQUEST['isManager']): ?> <div class="btn-group">
<input type="hidden" name="isManager" value="1"> <input type="submit" value="<?php echo $hesklang['save_changes']; ?>" class="btn btn-primary">
<?php endif; ?> <a class="btn btn-default" href="javascript:history.go(-1)"><?php echo $hesklang['back']; ?></a>
<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> </div>
</form> </form>
</div> </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"); $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)) { while ($row = hesk_dbFetchAssoc($res2)) {
$my_cat[$row['id']] = hesk_msgToPlain($row['name'], 1); $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"' : ''; $cat_selected = ($row['id'] == $category) ? 'selected="selected"' : '';
$category_options .= '<option value="' . $row['id'] . '" ' . $cat_selected . '>' . $row['name'] . '</option>'; $category_options .= '<option value="' . $row['id'] . '" ' . $cat_selected . '>' . $row['name'] . '</option>';
} }

@ -278,6 +278,12 @@ function print_login()
<?php <?php
/* This will handle error, success and notice messages */ /* This will handle error, success and notice messages */
hesk_handle_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>
<div class="login-logo"> <div class="login-logo">
@ -469,6 +475,9 @@ function print_login()
</div> </div>
</div> </div>
</form> </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> </div>
</div> </div>

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

@ -32,7 +32,7 @@ $modsForHesk_settings = mfh_getSettings();
/* List of staff */ /* List of staff */
$admins = array(); $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)) { while ($row = hesk_dbFetchAssoc($res)) {
$admins[$row['id']] = $row['name']; $admins[$row['id']] = $row['name'];
} }

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

@ -80,14 +80,19 @@ while ($row = hesk_dbFetchAssoc($res)) {
</div> </div>
</div> </div>
<div class="box-body"> <div class="box-body">
<a href="#" data-toggle="modal" data-target="#modal-template-new" class="btn btn-success nu-floatRight"> <div class="text-right">
<i class="fa fa-plus-circle"></i> <?php echo $hesklang['create_new_group']; ?> <a href="#" data-toggle="modal" data-target="#modal-template-new" class="btn btn-success nu-floatRight">
</a> <i class="fa fa-plus-circle"></i> <?php echo $hesklang['create_new']; ?>
</a>
</div>
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<th><?php echo $hesklang['name']; ?></th> <tr>
<th><?php echo $hesklang['number_of_users']; ?></th> <th><?php echo $hesklang['name']; ?></th>
<th><?php echo $hesklang['actions']; ?></th> <th><?php echo $hesklang['number_of_users']; ?></th>
<th><?php echo $hesklang['actions']; ?></th>
</tr>
</thead> </thead>
<tbody> <tbody>
<?php foreach ($templates as $row): ?> <?php foreach ($templates as $row): ?>
@ -96,13 +101,13 @@ while ($row = hesk_dbFetchAssoc($res)) {
<td><?php echo getNumberOfUsersWithPermissionGroup($row['id']); ?></td> <td><?php echo getNumberOfUsersWithPermissionGroup($row['id']); ?></td>
<td> <td>
<a href="#" data-toggle="modal" data-target="#modal-template-<?php echo $row['id'] ?>"> <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> title="<?php echo $hesklang['view_permissions_for_this_group'] ?>"></i></a>
<?php <?php
if ($row['id'] != 1 && $row['id'] != 2): if ($row['id'] != 1 && $row['id'] != 2):
?> ?>
<a href="manage_permission_groups.php?a=delete&amp;id=<?php echo $row['id']; ?>"> <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> title="<?php echo $hesklang['delete']; ?>"></i></a>
<?php endif; ?> <?php endif; ?>
</td> </td>
@ -137,11 +142,9 @@ function createEditModal($template, $features, $categories)
{ {
global $hesklang; global $hesklang;
$disabled = 'checked="checked" disabled';
$enabledFeatures = array(); $enabledFeatures = array();
$enabledCategories = array(); $enabledCategories = array();
if ($template['heskprivileges'] != 'ALL') { if ($template['heskprivileges'] !== 'ALL') {
$disabled = '';
$enabledFeatures = explode(',', $template['heskprivileges']); $enabledFeatures = explode(',', $template['heskprivileges']);
$enabledCategories = explode(',', $template['categories']); $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> <h4 class="modal-title"><?php echo sprintf($hesklang['permissions_for_group'], $template['name']); ?></h4>
</div> </div>
<div class="modal-body"> <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="row">
<div class="form-group"> <div class="form-group">
<div class="col-sm-2"> <div class="col-sm-2">
@ -179,20 +188,32 @@ function createEditModal($template, $features, $categories)
<div class="footerWithBorder blankSpace"></div> <div class="footerWithBorder blankSpace"></div>
<div class="form-group"> <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"> <div class="checkbox">
<label> <label>
<?php
$checked = '';
if (in_array($category['id'], $enabledCategories)) {
$checked = 'checked';
} ?>
<input type="checkbox" name="categories[]" <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']; ?> <?php echo $category['name']; ?>
</label> </label>
</div> </div>
<?php endforeach; ?> <?php
endif;
endforeach; ?>
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>
</div> </div>
</div> </div>
@ -201,19 +222,30 @@ function createEditModal($template, $features, $categories)
<div class="footerWithBorder blankSpace"></div> <div class="footerWithBorder blankSpace"></div>
<div class="form-group"> <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"> <div class="checkbox">
<label><?php <label>
$checked = '';
if (in_array($feature, $enabledFeatures)) {
$checked = 'checked';
} ?>
<input type="checkbox" name="features[]" <input type="checkbox" name="features[]"
value="<?php echo $feature; ?>" <?php echo $checked . $disabled; ?>> value="<?php echo $feature; ?>" <?php echo $checked . $disabled; ?>>
<?php echo $hesklang[$feature]; ?> <?php echo $hesklang[$feature]; ?>
</label> </label>
</div> </div>
<?php endforeach; ?> <?php endif;
endforeach; ?>
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>
</div> </div>
</div> </div>
@ -270,7 +302,9 @@ function buildCreateModal($features, $categories)
<div class="footerWithBorder blankSpace"></div> <div class="footerWithBorder blankSpace"></div>
<div class="form-group"> <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"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="categories[]" <input type="checkbox" name="categories[]"
@ -280,7 +314,7 @@ function buildCreateModal($features, $categories)
<?php echo $category['name']; ?> <?php echo $category['name']; ?>
</label> </label>
</div> </div>
<?php endforeach; ?> <?php endif; endforeach; ?>
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>
</div> </div>
</div> </div>
@ -289,7 +323,9 @@ function buildCreateModal($features, $categories)
<div class="footerWithBorder blankSpace"></div> <div class="footerWithBorder blankSpace"></div>
<div class="form-group"> <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"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="features[]" <input type="checkbox" name="features[]"
@ -299,7 +335,7 @@ function buildCreateModal($features, $categories)
<?php echo $hesklang[$feature]; ?> <?php echo $hesklang[$feature]; ?>
</label> </label>
</div> </div>
<?php endforeach; ?> <?php endif; endforeach; ?>
<div class="help-block with-errors"></div> <div class="help-block with-errors"></div>
</div> </div>
</div> </div>
@ -334,7 +370,6 @@ function save()
WHERE `id` = " . intval($templateId)); WHERE `id` = " . intval($templateId));
$row = hesk_dbFetchAssoc($res); $row = hesk_dbFetchAssoc($res);
// Add 'can ban emails' if 'can unban emails' is set (but not added). Same with 'can ban ips' // Add 'can ban emails' if 'can unban emails' is set (but not added). Same with 'can ban ips'
$catArray = hesk_POST_array('categories'); $catArray = hesk_POST_array('categories');
$featArray = hesk_POST_array('features'); $featArray = hesk_POST_array('features');
@ -349,6 +384,41 @@ function save()
$features = implode(',', $featArray); $features = implode(',', $featArray);
$name = hesk_POST('name'); $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` hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates`
SET `categories` = '" . hesk_dbEscape($categories) . "', `heskprivileges` = '" . hesk_dbEscape($features) . "', SET `categories` = '" . hesk_dbEscape($categories) . "', `heskprivileges` = '" . hesk_dbEscape($features) . "',
`name` = '" . hesk_dbEscape($name) . "' `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>'; $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 */ /* This will handle error, success and notice messages */
hesk_handle_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): ?> if ($show_quick_help): ?>
<div class="box"> <div class="box">
<div class="box-header with-border"> <div class="box-header with-border">

@ -170,7 +170,7 @@ function update_profile()
$_SESSION['new']['signature'] = hesk_input(hesk_POST('signature')); $_SESSION['new']['signature'] = hesk_input(hesk_POST('signature'));
/* Signature */ /* Signature */
if (strlen($_SESSION['new']['signature']) > 1000) { if (hesk_mb_strlen($_SESSION['new']['signature']) > 1000) {
$hesk_error_buffer .= '<li>' . $hesklang['signature_long'] . '</li>'; $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; public $autoAssign;
/** /**
* @var int The type of Categories (1 = Private, 2 = Public) * @var int The type of Categories (1 = Private, 0 = Public)
*/ */
public $type; public $type;

@ -187,4 +187,17 @@ class CategoryHandler extends \BaseClass {
$this->categoryGateway->updateCategory($category, $heskSettings); $this->categoryGateway->updateCategory($category, $heskSettings);
$this->categoryGateway->resortAllCategories($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 * @var $cc string[]|null
*/ */
public $cc; public $cc = array();
/** /**
* @var $bcc string[]|null * @var $bcc string[]|null
*/ */
public $bcc; public $bcc = array();
} }

@ -5,10 +5,12 @@ namespace BusinessLogic\Emails;
use BusinessLogic\Exceptions\EmailTemplateNotFoundException; use BusinessLogic\Exceptions\EmailTemplateNotFoundException;
use BusinessLogic\Exceptions\InvalidEmailTemplateException; use BusinessLogic\Exceptions\InvalidEmailTemplateException;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Statuses\DefaultStatusForAction; use BusinessLogic\Statuses\DefaultStatusForAction;
use BusinessLogic\Tickets\Ticket; use BusinessLogic\Tickets\Ticket;
use Core\Constants\Priority; use Core\Constants\Priority;
use DataAccess\Categories\CategoryGateway; use DataAccess\Categories\CategoryGateway;
use DataAccess\Logging\LoggingGateway;
use DataAccess\Security\UserGateway; use DataAccess\Security\UserGateway;
use DataAccess\Statuses\StatusGateway; use DataAccess\Statuses\StatusGateway;
@ -34,14 +36,21 @@ class EmailTemplateParser extends \BaseClass {
*/ */
private $emailTemplateRetriever; private $emailTemplateRetriever;
/**
* @var $logger LoggingGateway
*/
private $logger;
function __construct(StatusGateway $statusGateway, function __construct(StatusGateway $statusGateway,
CategoryGateway $categoryGateway, CategoryGateway $categoryGateway,
UserGateway $userGateway, UserGateway $userGateway,
EmailTemplateRetriever $emailTemplateRetriever) { EmailTemplateRetriever $emailTemplateRetriever,
LoggingGateway $loggingGateway) {
$this->statusGateway = $statusGateway; $this->statusGateway = $statusGateway;
$this->categoryGateway = $categoryGateway; $this->categoryGateway = $categoryGateway;
$this->userGateway = $userGateway; $this->userGateway = $userGateway;
$this->emailTemplateRetriever = $emailTemplateRetriever; $this->emailTemplateRetriever = $emailTemplateRetriever;
$this->logger = $loggingGateway;
} }
/** /**
@ -129,7 +138,17 @@ class EmailTemplateParser extends \BaseClass {
// Status name and category name // Status name and category name
$defaultStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings); $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); $categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
$category = null; $category = null;
foreach ($categories as $innerCategory) { foreach ($categories as $innerCategory) {

@ -4,8 +4,8 @@ namespace BusinessLogic\Exceptions;
class MissingAuthenticationTokenException extends ApiFriendlyException { class MissingAuthenticationTokenException extends ApiFriendlyException {
function __construct() { 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', 'Security Exception',
400); 401);
} }
} }

@ -30,4 +30,8 @@ class Helpers extends \BaseClass {
static function boolval($val) { static function boolval($val) {
return $val == true; 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 */ /* @var $active bool */
public $active; public $active;
function isAnonymousUser() {
return $this->id === -1;
}
static function buildAnonymousUser() { static function buildAnonymousUser() {
$userContext = new UserContext(); $userContext = new UserContext();
$userContext->id = -1; $userContext->id = -1;

@ -15,4 +15,7 @@ class UserPrivilege extends \BaseClass {
const CAN_EDIT_TICKETS = 'can_edit_tickets'; const CAN_EDIT_TICKETS = 'can_edit_tickets';
const CAN_DELETE_TICKETS = 'can_del_tickets'; const CAN_DELETE_TICKETS = 'can_del_tickets';
const CAN_MANAGE_CATEGORIES = 'can_man_cat'; 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 { class AuditTrailEntityType extends \BaseClass {
const TICKET = 'TICKET'; 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\Exceptions\ValidationException;
use BusinessLogic\Statuses\DefaultStatusForAction; use BusinessLogic\Statuses\DefaultStatusForAction;
use DataAccess\AuditTrail\AuditTrailGateway; use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\CustomFields\CustomFieldsGateway;
use DataAccess\Security\UserGateway; use DataAccess\Security\UserGateway;
use DataAccess\Settings\ModsForHeskSettingsGateway; use DataAccess\Settings\ModsForHeskSettingsGateway;
use DataAccess\Statuses\StatusGateway; use DataAccess\Statuses\StatusGateway;
@ -61,6 +62,9 @@ class TicketCreator extends \BaseClass {
/* @var $auditTrailGateway AuditTrailGateway */ /* @var $auditTrailGateway AuditTrailGateway */
private $auditTrailGateway; private $auditTrailGateway;
/* @var $customFieldsGateway CustomFieldsGateway */
private $customFieldsGateway;
function __construct(NewTicketValidator $newTicketValidator, function __construct(NewTicketValidator $newTicketValidator,
TrackingIdGenerator $trackingIdGenerator, TrackingIdGenerator $trackingIdGenerator,
Autoassigner $autoassigner, Autoassigner $autoassigner,
@ -70,7 +74,8 @@ class TicketCreator extends \BaseClass {
EmailSenderHelper $emailSenderHelper, EmailSenderHelper $emailSenderHelper,
UserGateway $userGateway, UserGateway $userGateway,
ModsForHeskSettingsGateway $modsForHeskSettingsGateway, ModsForHeskSettingsGateway $modsForHeskSettingsGateway,
AuditTrailGateway $auditTrailGateway) { AuditTrailGateway $auditTrailGateway,
CustomFieldsGateway $customFieldsGateway) {
$this->newTicketValidator = $newTicketValidator; $this->newTicketValidator = $newTicketValidator;
$this->trackingIdGenerator = $trackingIdGenerator; $this->trackingIdGenerator = $trackingIdGenerator;
$this->autoassigner = $autoassigner; $this->autoassigner = $autoassigner;
@ -81,6 +86,7 @@ class TicketCreator extends \BaseClass {
$this->userGateway = $userGateway; $this->userGateway = $userGateway;
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway; $this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
$this->auditTrailGateway = $auditTrailGateway; $this->auditTrailGateway = $auditTrailGateway;
$this->customFieldsGateway = $customFieldsGateway;
} }
/** /**
@ -162,6 +168,19 @@ class TicketCreator extends \BaseClass {
$addressees = new Addressees(); $addressees = new Addressees();
$addressees->to = $ticket->email; $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) { if ($ticketRequest->sendEmailToCustomer && $emailVerified) {
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_TICKET, $ticketRequest->language, $addressees, $ticket, $heskSettings, $modsForHeskSettings); $this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_TICKET, $ticketRequest->language, $addressees, $ticket, $heskSettings, $modsForHeskSettings);
} else if ($modsForHeskSettings['customer_email_verification_required'] && !$emailVerified) { } else if ($modsForHeskSettings['customer_email_verification_required'] && !$emailVerified) {

@ -3,6 +3,7 @@
namespace BusinessLogic\Tickets; namespace BusinessLogic\Tickets;
use BusinessLogic\DateTimeHelpers;
use BusinessLogic\Exceptions\AccessViolationException; use BusinessLogic\Exceptions\AccessViolationException;
use BusinessLogic\Exceptions\ApiFriendlyException; use BusinessLogic\Exceptions\ApiFriendlyException;
use BusinessLogic\Exceptions\ValidationException; use BusinessLogic\Exceptions\ValidationException;
@ -13,6 +14,7 @@ use BusinessLogic\Tickets\CustomFields\CustomFieldValidator;
use BusinessLogic\ValidationModel; use BusinessLogic\ValidationModel;
use BusinessLogic\Validators; use BusinessLogic\Validators;
use Core\Constants\CustomField; use Core\Constants\CustomField;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\Tickets\TicketGateway; use DataAccess\Tickets\TicketGateway;
class TicketEditor extends \BaseClass { class TicketEditor extends \BaseClass {
@ -22,10 +24,15 @@ class TicketEditor extends \BaseClass {
/* @var $userToTicketChecker UserToTicketChecker */ /* @var $userToTicketChecker UserToTicketChecker */
private $userToTicketChecker; private $userToTicketChecker;
/* @var $auditTrailGateway AuditTrailGateway */
private $auditTrailGateway;
function __construct(TicketGateway $ticketGateway, function __construct(TicketGateway $ticketGateway,
UserToTicketChecker $userToTicketChecker) { UserToTicketChecker $userToTicketChecker,
AuditTrailGateway $auditTrailGateway) {
$this->ticketGateway = $ticketGateway; $this->ticketGateway = $ticketGateway;
$this->userToTicketChecker = $userToTicketChecker; $this->userToTicketChecker = $userToTicketChecker;
$this->auditTrailGateway = $auditTrailGateway;
} }
@ -135,4 +142,67 @@ class TicketEditor extends \BaseClass {
throw new ValidationException($validationModel); 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); $address = str_replace(';', ',', $address);
/* Check if addresses are valid */ /* Check if addresses are valid */
$all = explode(',', $address); $all = array_unique(explode(',',$address));
foreach ($all as $k => $v) { foreach ($all as $k => $v) {
if (!self::isValidEmail($v)) { if (!self::isValidEmail($v)) {
unset($all[$k]); 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\Helpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Tickets\EditTicketModel; use BusinessLogic\Tickets\EditTicketModel;
use BusinessLogic\Tickets\TicketDeleter; use BusinessLogic\Tickets\TicketDeleter;
use BusinessLogic\Tickets\TicketEditor; use BusinessLogic\Tickets\TicketEditor;
@ -45,6 +46,20 @@ class StaffTicketController extends \BaseClass {
return; 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) { private function getEditTicketModel($id, $jsonRequest) {
$editTicketModel = new EditTicketModel(); $editTicketModel = new EditTicketModel();
$editTicketModel->id = $id; $editTicketModel->id = $id;

@ -8,4 +8,19 @@ class Priority extends \BaseClass {
const HIGH = 1; const HIGH = 1;
const MEDIUM = 2; const MEDIUM = 2;
const LOW = 3; 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['type'] = 'ERROR';
$error['title'] = $title; $error['title'] = $title;
$error['message'] = $message; $error['message'] = $message;
$error['logId'] = $logId;
if ($logId !== null) {
$error['logId'] = $logId;
}
print output($error, $response_code); print output($error, $response_code);
return; 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() { function init() {
if (!function_exists('hesk_dbConnect')) { if (!function_exists('hesk_dbConnect')) {
throw new Exception('Database not loaded!'); throw new \BaseException('Database not loaded!');
} }
hesk_dbConnect(); 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(); $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 BusinessLogic\ValidationModel;
use Core\Constants\Priority; use Core\Constants\Priority;
use DataAccess\AuditTrail\AuditTrailGateway; use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\CustomFields\CustomFieldsGateway;
use DataAccess\Security\UserGateway; use DataAccess\Security\UserGateway;
use DataAccess\Settings\ModsForHeskSettingsGateway; use DataAccess\Settings\ModsForHeskSettingsGateway;
use DataAccess\Statuses\StatusGateway; use DataAccess\Statuses\StatusGateway;
@ -101,6 +102,9 @@ class CreateTicketTest extends TestCase {
/* @var $auditTrailGateway \PHPUnit_Framework_MockObject_MockObject|AuditTrailGateway */ /* @var $auditTrailGateway \PHPUnit_Framework_MockObject_MockObject|AuditTrailGateway */
private $auditTrailGateway; private $auditTrailGateway;
/* @var $customFieldsGateway \PHPUnit_Framework_MockObject_MockObject|CustomFieldsGateway */
private $customFieldsGateway;
protected function setUp() { protected function setUp() {
$this->ticketGateway = $this->createMock(TicketGateway::clazz()); $this->ticketGateway = $this->createMock(TicketGateway::clazz());
$this->newTicketValidator = $this->createMock(NewTicketValidator::clazz()); $this->newTicketValidator = $this->createMock(NewTicketValidator::clazz());
@ -112,10 +116,11 @@ class CreateTicketTest extends TestCase {
$this->userGateway = $this->createMock(UserGateway::clazz()); $this->userGateway = $this->createMock(UserGateway::clazz());
$this->modsForHeskSettingsGateway = $this->createMock(ModsForHeskSettingsGateway::clazz()); $this->modsForHeskSettingsGateway = $this->createMock(ModsForHeskSettingsGateway::clazz());
$this->auditTrailGateway = $this->createMock(AuditTrailGateway::clazz()); $this->auditTrailGateway = $this->createMock(AuditTrailGateway::clazz());
$this->customFieldsGateway = $this->createMock(CustomFieldsGateway::clazz());
$this->ticketCreator = new TicketCreator($this->newTicketValidator, $this->trackingIdGenerator, $this->ticketCreator = new TicketCreator($this->newTicketValidator, $this->trackingIdGenerator,
$this->autoassigner, $this->statusGateway, $this->ticketGateway, $this->verifiedEmailChecker, $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 = new CreateTicketByCustomerModel();
$this->ticketRequest->name = 'Name'; $this->ticketRequest->name = 'Name';

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

101
api/composer.lock generated

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

@ -45,8 +45,15 @@ function internalOrAuthHandler() {
function publicHandler() { function publicHandler() {
global $userContext; global $userContext;
//-- Create an "anonymous" UserContext // Check if we passed in a X-Auth-Token or X-Internal-Call header. Those take priority
$userContext = \BusinessLogic\Security\UserContext::buildAnonymousUser(); 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() { function assertApiIsEnabled() {
@ -105,7 +112,7 @@ function exceptionHandler($exception) {
/* @var $castedException \BusinessLogic\Exceptions\ApiFriendlyException */ /* @var $castedException \BusinessLogic\Exceptions\ApiFriendlyException */
$castedException = $exception; $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())) { } elseif (exceptionIsOfType($exception, \Core\Exceptions\SQLException::clazz())) {
/* @var $castedException \Core\Exceptions\SQLException */ /* @var $castedException \Core\Exceptions\SQLException */
$castedException = $exception; $castedException = $exception;
@ -194,6 +201,7 @@ Link::all(array(
'/v1/tickets' => action(\Controllers\Tickets\CustomerTicketController::clazz(), RequestMethod::all(), SecurityHandler::OPEN), '/v1/tickets' => action(\Controllers\Tickets\CustomerTicketController::clazz(), RequestMethod::all(), SecurityHandler::OPEN),
// Tickets - Staff // Tickets - Staff
'/v1/staff/tickets/{i}' => action(\Controllers\Tickets\StaffTicketController::clazz(), RequestMethod::all()), '/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 // Attachments
'/v1/tickets/{a}/attachments/{i}' => action(\Controllers\Attachments\PublicAttachmentController::clazz() . '::getRaw', RequestMethod::all()), '/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()), '/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()), '/v1/statuses' => action(\Controllers\Statuses\StatusController::clazz(), RequestMethod::all()),
// Settings // Settings
'/v1/settings' => action(\Controllers\Settings\SettingsController::clazz(), RequestMethod::all()), '/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 */ /* Internal use only routes */
// Resend email response // Resend email response

@ -111,8 +111,20 @@ require_once(HESK_PATH . 'inc/header.inc.php');
</div> </div>
</div> </div>
</div> </div>
<?php
echo mfh_get_hidden_fields_for_language(array(
'error_loading_events'
));
?>
<div style="display: none"> <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_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> <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'] . ')', 'staffreplies' => $hesklang['replies'] . ' (' . $hesklang['staff'] . ')',
'lastreplier' => $hesklang['last_replier'], 'lastreplier' => $hesklang['last_replier'],
'time_worked' => $hesklang['ts'], 'time_worked' => $hesklang['ts'],
'due_date' => $hesklang['due_date'],
); );
define('HESK_NO_ROBOTS', true); define('HESK_NO_ROBOTS', true);

@ -185,12 +185,34 @@ function hesk_service_message($sm)
?> ?>
<div class="<?php echo $style; ?>"> <div class="<?php echo $style; ?>">
<?php echo $faIcon == '' ? '' : '<i class="' . $faIcon . '"></i> '; ?> <?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> </div>
<br/> <br/>
<?php <?php
} // END hesk_service_message() } // 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) function hesk_isBannedIP($ip)
{ {
@ -357,6 +379,16 @@ function hesk_isREQUEST($in)
return isset($_GET[$in]) || isset($_POST[$in]) ? true : false; return isset($_GET[$in]) || isset($_POST[$in]) ? true : false;
} // END hesk_isREQUEST() } // 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) { function hesk_mb_strtolower($in) {
return function_exists('mb_strtolower') ? mb_strtolower($in) : strtolower($in); return function_exists('mb_strtolower') ? mb_strtolower($in) : strtolower($in);
} // END hesk_mb_strtolower() } // END hesk_mb_strtolower()
@ -455,7 +487,7 @@ function hesk_verifyEmailMatch($trackingID, $my_email = 0, $ticket_email = 0, $e
} // END hesk_verifyEmailMatch() } // 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; global $hesk_settings, $hesklang;
@ -494,6 +526,11 @@ function hesk_getCustomerEmail($can_remember = 0, $field = '')
// Remove unwanted side-effects // Remove unwanted side-effects
$my_email = hesk_emailCleanup($my_email); $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_param'] = '&e=' . rawurlencode($my_email);
$hesk_settings['e_query'] = '&amp;e=' . rawurlencode($my_email); $hesk_settings['e_query'] = '&amp;e=' . rawurlencode($my_email);
$hesk_settings['e_email'] = $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 // Check length
if ($max_length) { if ($max_length) {
$in = substr($in, 0, $max_length); $in = hesk_mb_substr($in, 0, $max_length);
} }
// Return processed value // Return processed value
@ -1663,7 +1700,7 @@ function hesk_validateEmail($address, $error, $required = 1)
$address = str_replace(';', ',', $address); $address = str_replace(';', ',', $address);
/* Check if addresses are valid */ /* Check if addresses are valid */
$all = explode(',', $address); $all = array_unique(explode(',',$address));
foreach ($all as $k => $v) { foreach ($all as $k => $v) {
if (!hesk_isValidEmail($v)) { if (!hesk_isValidEmail($v)) {
unset($all[$k]); unset($all[$k]);
@ -1777,7 +1814,7 @@ function hesk_session_start()
return true; return true;
} else { } else {
global $hesk_settings, $hesklang; 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() } // END hesk_session_start()
@ -2109,6 +2146,31 @@ function mfh_getNumberOfDownloadsForAttachment($att_id, $table = 'attachments')
return $rec['download_count']; 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() function mfh_getSettings()
{ {
global $hesk_settings; 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 // Name for display in ticket list; punctuation removed and shortened
$row['title'] = hesk_remove_punctuation($row['name']); $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 // A version with forced punctuation
$row['name:'] = in_array(substr($row['name'], -1), array(':', '?', '!', '.') ) ? $row['name'] : $row['name'] . ':'; $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(); $ccEmails = array();
$bccEmails = 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['use']) {
if ($v['type'] == 'email' && !empty($ticket[$k])) { if ($v['type'] == 'email' && !empty($ticket[$k])) {
if ($v['value'] == 'cc') { if ($v['value']['email_type'] == 'cc') {
$emails = explode(',', $ticket[$k]); $emails = explode(',', $ticket[$k]);
array_push($ccEmails, $emails); array_push($ccEmails, $emails);
} elseif ($v['value'] == 'bcc') { } elseif ($v['value']['email_type'] == 'bcc') {
$emails = explode(',', $ticket[$k]); $emails = explode(',', $ticket[$k]);
array_push($bccEmails, $emails); array_push($bccEmails, $emails);
} }
} }
} }
}*/ }
hesk_mail($ticket['email'], $subject, $message, $htmlMessage, $modsForHesk_settings, $ccEmails, $bccEmails, $hasMessage); 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(); $ccEmails = array();
$bccEmails = 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['use']) {
if ($v['type'] == 'email' && !empty($ticket[$k])) { if ($v['type'] == 'email' && !empty($ticket[$k]) && isset($v['value']['emails_to_receive'])) {
if ($v['value'] == 'cc') { if ($v['value']['email_type'] == 'cc') {
array_push($ccEmails, $ticket[$k]); $emails = explode(',', $ticket[$k]);
} elseif ($v['value'] == 'bcc') { array_push($ccEmails, $emails);
array_push($bccEmails, $ticket[$k]); } elseif ($v['value']['email_type'] == 'bcc') {
$emails = explode(',', $ticket[$k]);
array_push($bccEmails, $emails);
} }
} }
} }
}*/ }
// Send e-mail // Send e-mail
hesk_mail($ticket['email'], $subject, $message, $htmlMessage, $modsForHesk_settings, $ccEmails, $bccEmails, $hasMessage); 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 // Remove duplicate recipients
$to_arr = array_unique(explode(',', $to)); $to_arr = array_unique(explode(',', $to));
$to_arr = array_values($to_arr);
$to = implode(',', $to_arr); $to = implode(',', $to_arr);
// Use PHP's mail function // Use PHP's mail function

@ -175,7 +175,7 @@ header('X-UA-Compatible: IE=edge');
/* If page requires WYSIWYG editor include TinyMCE Javascript */ /* If page requires WYSIWYG editor include TinyMCE Javascript */
if (defined('WYSIWYG') && $hesk_settings['kb_wysiwyg']) { 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 <?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; ?>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/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/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 <?php
if (defined('EXTRA_JS')) { if (defined('EXTRA_JS')) {
echo EXTRA_JS; echo EXTRA_JS;

@ -26,12 +26,12 @@ function hesk_kbArticleContentPreview($txt)
$txt = strip_tags($txt); $txt = strip_tags($txt);
// If text is larger than article preview length, shorten it // 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) // 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 // 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; return $txt;

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

@ -23,7 +23,7 @@ function hesk_newTicket($ticket, $isVerified = true)
global $hesk_settings, $hesklang, $hesk_db_link; global $hesk_settings, $hesklang, $hesk_db_link;
// Generate a subject if necessary // 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']); $ticket['subject'] = sprintf($hesklang['default_subject'], $ticket['name']);
} }

@ -45,7 +45,8 @@ LEFT(`message`, 400) AS `message`,
`replierid`, `replierid`,
`archive`, `archive`,
`locked`, `locked`,
`merged` `merged`,
`due_date`
"; ";
foreach ($hesk_settings['custom_fields'] as $k => $v) { 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; ?>> <li <?php echo $active; ?>>
<a href="admin_main.php"> <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> </a>
</li> </li>
<?php <?php

@ -57,14 +57,14 @@ $can_view_unassigned = hesk_checkPermission('can_view_unassigned', 0);
$category_options = ''; $category_options = '';
if (isset($hesk_settings['categories']) && count($hesk_settings['categories'])) { if (isset($hesk_settings['categories']) && count($hesk_settings['categories'])) {
foreach ($hesk_settings['categories'] as $row['id'] => $row['name']) { 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"' : ''; $selected = ($row['id'] == $category) ? 'selected="selected"' : '';
$category_options .= '<option value="' . $row['id'] . '" ' . $selected . '>' . $row['name'] . '</option>'; $category_options .= '<option value="' . $row['id'] . '" ' . $selected . '>' . $row['name'] . '</option>';
} }
} else { } else {
$res2 = hesk_dbQuery('SELECT `id`, `name` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'categories` WHERE ' . hesk_myCategories('id') . ' ORDER BY `cat_order` ASC'); $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)) { 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"' : ''; $selected = ($row['id'] == $category) ? 'selected="selected"' : '';
$category_options .= '<option value="' . $row['id'] . '" ' . $selected . '>' . $row['name'] . '</option>'; $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'] = $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>'; echo '<option style="background: #ffffff" value="' . $k . '" ' . $selected . '>' . $v['name'] . '</option>';
} }
} }

@ -238,13 +238,15 @@ if ($total > 0) {
break; break;
case 2: 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>'; $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; break;
default: 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>'; $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) // 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 // Start ticket row
echo ' echo '
@ -373,6 +375,16 @@ if ($total > 0) {
echo '<td class="' . $color . '">' . $ticket['time_worked'] . '</td>'; 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 // Print custom fields
foreach ($hesk_settings['custom_fields'] as $key => $value) { foreach ($hesk_settings['custom_fields'] as $key => $value) {
if ($value['use'] && hesk_show_column($key)) { if ($value['use'] && hesk_show_column($key)) {

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

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

@ -5,6 +5,59 @@ require(HESK_PATH . 'install/install_functions.inc.php');
require(HESK_PATH . 'hesk_settings.inc.php'); require(HESK_PATH . 'hesk_settings.inc.php');
hesk_dbConnect(); 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> <html>
<head> <head>
@ -26,12 +79,11 @@ hesk_dbConnect();
<div class="container"> <div class="container">
<div class="page-header"> <div class="page-header">
<h1>Mods for HESK Database Validation</h1> <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. <p>The database validation tool will check your database setup to ensure that everything is set up correctly.</p>
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>
</div> </div>
<div class="panel panel-success" id="all-good" style="display: none"> <div class="panel panel-success" id="all-good" style="display: none">
<div class="panel-heading"> <div class="panel-heading">
<h4>Success</h4> <h4><i class="fa fa-check-circle"></i> Success</h4>
</div> </div>
<div class="panel-body text-center"> <div class="panel-body text-center">
<i class="fa fa-check-circle fa-4x" style="color: green"></i><br> <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> <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> </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 panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h4>Results</h4> <h4>Results</h4>
@ -61,157 +121,192 @@ hesk_dbConnect();
</thead> </thead>
<tbody> <tbody>
<?php <?php
$all_good = true; $validations = array();
output_header_row('1.0.0 - 1.3.x'); output_header_row('1.0.0 - 1.3.x');
$all_good = run_table_check('statuses'); $validations[] = run_table_check('statuses', 7);
$all_good &= run_column_check('statuses', 'ID'); $validations[] = run_column_check('statuses', 'ID', 7);
$all_good &= run_column_check('statuses', 'TextColor'); $validations[] = run_column_check('statuses', 'TextColor', 7);
$all_good &= run_column_check('statuses', 'IsNewTicketStatus'); $validations[] = run_column_check('statuses', 'IsNewTicketStatus', 7);
$all_good &= run_column_check('statuses', 'IsClosed'); $validations[] = run_column_check('statuses', 'IsClosed', 7);
$all_good &= run_column_check('statuses', 'IsClosedByClient'); $validations[] = run_column_check('statuses', 'IsClosedByClient', 7);
$all_good &= run_column_check('statuses', 'IsCustomerReplyStatus'); $validations[] = run_column_check('statuses', 'IsCustomerReplyStatus', 7);
$all_good &= run_column_check('statuses', 'IsStaffClosedOption'); $validations[] = run_column_check('statuses', 'IsStaffClosedOption', 7);
$all_good &= run_column_check('statuses', 'IsStaffReopenedStatus'); $validations[] = run_column_check('statuses', 'IsStaffReopenedStatus', 7);
$all_good &= run_column_check('statuses', 'IsDefaultStaffReplyStatus'); $validations[] = run_column_check('statuses', 'IsDefaultStaffReplyStatus', 7);
$all_good &= run_column_check('statuses', 'LockedTicketStatus'); $validations[] = run_column_check('statuses', 'LockedTicketStatus', 7);
output_header_row('1.5.0'); 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'); output_header_row('1.6.0');
$all_good &= run_column_check('users', 'notify_note_unassigned'); $validations[] = run_column_check('users', 'notify_note_unassigned', 14);
$all_good &= run_table_check('settings'); $validations[] = run_table_check('settings', 20);
output_header_row('1.7.0'); output_header_row('1.7.0');
$all_good &= run_table_check('verified_emails'); $validations[] = run_table_check('verified_emails', 23);
$all_good &= run_table_check('pending_verification_emails'); $validations[] = run_table_check('pending_verification_emails', 24);
$all_good &= run_table_check('stage_tickets'); $validations[] = run_table_check('stage_tickets', 25);
output_header_row('2.2.0'); output_header_row('2.2.0');
$all_good &= run_column_check('statuses', 'IsAutocloseOption'); $validations[] = run_column_check('statuses', 'IsAutocloseOption', 42);
$all_good &= run_column_check('statuses', 'Closable'); $validations[] = run_column_check('statuses', 'Closable', 44);
output_header_row('2.3.0'); output_header_row('2.3.0');
$all_good &= run_column_check('service_messages', 'icon'); $validations[] = run_column_check('service_messages', 'icon', 48);
$all_good &= run_column_check('statuses', 'Key'); $validations[] = run_column_check('statuses', 'Key', 49);
$all_good &= run_column_check('tickets', 'latitude'); $validations[] = run_column_check('tickets', 'latitude', 53);
$all_good &= run_column_check('tickets', 'longitude'); $validations[] = run_column_check('tickets', 'longitude', 54);
$all_good &= run_column_check('stage_tickets', 'latitude'); $validations[] = run_column_check('stage_tickets', 'latitude', 55);
$all_good &= run_column_check('stage_tickets', 'longitude'); $validations[] = run_column_check('stage_tickets', 'longitude', 56);
$all_good &= run_column_check('categories', 'manager'); $validations[] = run_column_check('categories', 'manager', 57);
$all_good &= run_column_check('users', 'permission_template'); $validations[] = run_column_check('users', 'permission_template', 62);
$all_good &= run_table_check('permission_templates'); $validations[] = run_table_check('permission_templates', 63);
$all_good &= run_column_check('permission_templates', 'id'); $validations[] = run_column_check('permission_templates', 'id', 63);
$all_good &= run_column_check('permission_templates', 'name'); $validations[] = run_column_check('permission_templates', 'name', 63);
$all_good &= run_column_check('permission_templates', 'heskprivileges'); $validations[] = run_column_check('permission_templates', 'heskprivileges', 63);
$all_good &= run_column_check('permission_templates', 'categories'); $validations[] = run_column_check('permission_templates', 'categories', 63);
output_header_row('2.4.0'); output_header_row('2.4.0');
$all_good &= run_table_check('quick_help_sections'); $validations[] = run_table_check('quick_help_sections', 70);
$all_good &= run_column_check('quick_help_sections', 'id'); $validations[] = run_column_check('quick_help_sections', 'id', 70);
$all_good &= run_column_check('quick_help_sections', 'location'); $validations[] = run_column_check('quick_help_sections', 'location', 70);
$all_good &= run_column_check('quick_help_sections', 'show'); $validations[] = run_column_check('quick_help_sections', 'show', 70);
$all_good &= run_table_check('text_to_status_xref'); $validations[] = run_table_check('text_to_status_xref', 76);
$all_good &= run_column_check('text_to_status_xref', 'id'); $validations[] = run_column_check('text_to_status_xref', 'id', 76);
$all_good &= run_column_check('text_to_status_xref', 'language'); $validations[] = run_column_check('text_to_status_xref', 'language', 76);
$all_good &= run_column_check('text_to_status_xref', 'text'); $validations[] = run_column_check('text_to_status_xref', 'text', 76);
$all_good &= run_column_check('text_to_status_xref', 'status_id'); $validations[] = run_column_check('text_to_status_xref', 'status_id', 76);
$all_good &= run_column_check('statuses', 'sort'); $validations[] = run_column_check('statuses', 'sort', 77);
$all_good &= run_column_check('attachments', 'download_count'); $validations[] = run_column_check('attachments', 'download_count', 80);
$all_good &= run_column_check('kb_attachments', 'download_count'); $validations[] = run_column_check('kb_attachments', 'download_count', 81);
$all_good &= run_column_check('tickets', 'html'); $validations[] = run_column_check('tickets', 'html', 82);
$all_good &= run_column_check('stage_tickets', 'html'); $validations[] = run_column_check('stage_tickets', 'html', 83);
$all_good &= run_column_check('replies', 'html'); $validations[] = run_column_check('replies', 'html', 84);
output_header_row('2.5.0'); output_header_row('2.5.0');
$all_good &= run_column_check('tickets', 'user_agent'); $validations[] = run_column_check('tickets', 'user_agent', 89);
$all_good &= run_column_check('tickets', 'screen_resolution_width'); $validations[] = run_column_check('tickets', 'screen_resolution_width', 91);
$all_good &= run_column_check('tickets', 'screen_resolution_height'); $validations[] = run_column_check('tickets', 'screen_resolution_height', 92);
$all_good &= run_column_check('stage_tickets', 'user_agent'); $validations[] = run_column_check('stage_tickets', 'user_agent', 90);
$all_good &= run_column_check('stage_tickets', 'screen_resolution_width'); $validations[] = run_column_check('stage_tickets', 'screen_resolution_width', 93);
$all_good &= run_column_check('stage_tickets', 'screen_resolution_height'); $validations[] = run_column_check('stage_tickets', 'screen_resolution_height', 94);
$validations[] = run_setting_check('navbar_title_url', 96);
output_header_row('2.6.0'); output_header_row('2.6.0');
$all_good &= run_table_check('logging'); $validations[] = run_table_check('logging', 105);
$all_good &= run_column_check('logging', 'id'); $validations[] = run_column_check('logging', 'id', 105);
$all_good &= run_column_check('logging', 'username'); $validations[] = run_column_check('logging', 'username', 105);
$all_good &= run_column_check('logging', 'message'); $validations[] = run_column_check('logging', 'message', 105);
$all_good &= run_column_check('logging', 'severity'); $validations[] = run_column_check('logging', 'severity', 105);
$all_good &= run_column_check('logging', 'location'); $validations[] = run_column_check('logging', 'location', 105);
$all_good &= run_column_check('logging', 'timestamp'); $validations[] = run_column_check('logging', 'timestamp', 105);
$all_good &= run_table_check('user_api_tokens'); $validations[] = run_table_check('user_api_tokens', 103);
$all_good &= run_column_check('user_api_tokens', 'id'); $validations[] = run_column_check('user_api_tokens', 'id', 103);
$all_good &= run_column_check('user_api_tokens', 'user_id'); $validations[] = run_column_check('user_api_tokens', 'user_id', 103);
$all_good &= run_column_check('user_api_tokens', 'token'); $validations[] = run_column_check('user_api_tokens', 'token', 103);
$all_good &= run_table_check('temp_attachment'); $validations[] = run_setting_check('public_api', 104);
$all_good &= run_column_check('temp_attachment', 'id'); $validations[] = run_table_check('temp_attachment', 106);
$all_good &= run_column_check('temp_attachment', 'file_name'); $validations[] = run_column_check('temp_attachment', 'id', 106);
$all_good &= run_column_check('temp_attachment', 'saved_name'); $validations[] = run_column_check('temp_attachment', 'file_name', 106);
$all_good &= run_column_check('temp_attachment', 'size'); $validations[] = run_column_check('temp_attachment', 'saved_name', 106);
$all_good &= run_column_check('temp_attachment', 'type'); $validations[] = run_column_check('temp_attachment', 'size', 106);
$all_good &= run_column_check('temp_attachment', 'date_uploaded'); $validations[] = run_column_check('temp_attachment', 'type', 106);
$all_good &= run_table_check('calendar_event'); $validations[] = run_column_check('temp_attachment', 'date_uploaded', 106);
$all_good &= run_column_check('calendar_event', 'id'); $validations[] = run_table_check('calendar_event', 107);
$all_good &= run_column_check('calendar_event', 'start'); $validations[] = run_column_check('calendar_event', 'id', 107);
$all_good &= run_column_check('calendar_event', 'end'); $validations[] = run_column_check('calendar_event', 'start', 107);
$all_good &= run_column_check('calendar_event', 'all_day'); $validations[] = run_column_check('calendar_event', 'end', 107);
$all_good &= run_column_check('calendar_event', 'name'); $validations[] = run_column_check('calendar_event', 'all_day', 107);
$all_good &= run_column_check('calendar_event', 'location'); $validations[] = run_column_check('calendar_event', 'name', 107);
$all_good &= run_column_check('calendar_event', 'comments'); $validations[] = run_column_check('calendar_event', 'location', 107);
$all_good &= run_column_check('calendar_event', 'category'); $validations[] = run_column_check('calendar_event', 'comments', 107);
$all_good &= run_table_check('calendar_event_reminder'); $validations[] = run_column_check('calendar_event', 'category', 107);
$all_good &= run_column_check('calendar_event_reminder', 'id'); $validations[] = run_table_check('calendar_event_reminder', 108);
$all_good &= run_column_check('calendar_event_reminder', 'user_id'); $validations[] = run_column_check('calendar_event_reminder', 'id', 108);
$all_good &= run_column_check('calendar_event_reminder', 'event_id'); $validations[] = run_column_check('calendar_event_reminder', 'user_id', 108);
$all_good &= run_column_check('calendar_event_reminder', 'amount'); $validations[] = run_column_check('calendar_event_reminder', 'event_id', 108);
$all_good &= run_column_check('calendar_event_reminder', 'unit'); $validations[] = run_column_check('calendar_event_reminder', 'amount', 108);
$all_good &= run_column_check('calendar_event_reminder', 'email_sent'); $validations[] = run_column_check('calendar_event_reminder', 'unit', 108);
$all_good &= run_column_check('tickets', 'due_date'); $validations[] = run_column_check('calendar_event_reminder', 'email_sent', 108);
$all_good &= run_column_check('tickets', 'overdue_email_sent'); $validations[] = run_column_check('tickets', 'due_date', 109);
$all_good &= run_column_check('categories', 'usage'); $validations[] = run_column_check('tickets', 'overdue_email_sent', 110);
$all_good &= run_column_check('users', 'notify_overdue_unassigned'); $validations[] = run_column_check('categories', 'usage', 112);
$all_good &= run_column_check('users', 'default_calendar_view'); $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'); output_header_row('2.6.2');
$all_good &= run_column_check('stage_tickets', 'due_date'); $validations[] = run_column_check('stage_tickets', 'due_date', 122);
$all_good &= run_column_check('stage_tickets', 'overdue_email_sent'); $validations[] = run_column_check('stage_tickets', 'overdue_email_sent', 123);
output_header_row('3.1.0'); output_header_row('3.1.0');
$all_good &= run_column_check('categories', 'background_color'); $validations[] = run_column_check('logging', 'stack_trace', 140);
$all_good &= run_column_check('categories', 'foreground_color'); $validations[] = run_column_check('categories', 'background_color', 145);
$all_good &= run_column_check('categories', 'display_border_outline'); $validations[] = run_column_check('categories', 'foreground_color', 143);
$all_good &= run_column_check('logging', 'stack_trace'); $validations[] = run_column_check('categories', 'display_border_outline', 144);
$all_good &= run_table_check('custom_nav_element'); $validations[] = run_table_check('custom_nav_element', 141);
$all_good &= run_column_check('custom_nav_element', 'id'); $validations[] = run_column_check('custom_nav_element', 'id', 141);
$all_good &= run_column_check('custom_nav_element', 'image_url'); $validations[] = run_column_check('custom_nav_element', 'image_url', 141);
$all_good &= run_column_check('custom_nav_element', 'font_icon'); $validations[] = run_column_check('custom_nav_element', 'font_icon', 141);
$all_good &= run_column_check('custom_nav_element', 'place'); $validations[] = run_column_check('custom_nav_element', 'place', 141);
$all_good &= run_column_check('custom_nav_element', 'url'); $validations[] = run_column_check('custom_nav_element', 'url', 141);
$all_good &= run_column_check('custom_nav_element', 'sort'); $validations[] = run_column_check('custom_nav_element', 'sort', 141);
$all_good &= run_table_check('custom_nav_element_to_text'); $validations[] = run_table_check('custom_nav_element_to_text', 142);
$all_good &= run_column_check('custom_nav_element_to_text', 'id'); $validations[] = run_column_check('custom_nav_element_to_text', 'id', 142);
$all_good &= run_column_check('custom_nav_element_to_text', 'nav_element_id'); $validations[] = run_column_check('custom_nav_element_to_text', 'nav_element_id', 142);
$all_good &= run_column_check('custom_nav_element_to_text', 'language'); $validations[] = run_column_check('custom_nav_element_to_text', 'language', 142);
$all_good &= run_column_check('custom_nav_element_to_text', 'text'); $validations[] = run_column_check('custom_nav_element_to_text', 'text', 142);
$all_good &= run_column_check('custom_nav_element_to_text', 'subtext'); $validations[] = run_column_check('custom_nav_element_to_text', 'subtext', 142);
$all_good &= run_setting_check('admin_navbar_background'); $validations[] = run_setting_check('admin_navbar_background', 151);
$all_good &= run_setting_check('admin_navbar_background_hover'); $validations[] = run_setting_check('admin_navbar_background_hover', 151);
$all_good &= run_setting_check('admin_navbar_text'); $validations[] = run_setting_check('admin_navbar_text', 151);
$all_good &= run_setting_check('admin_navbar_text_hover'); $validations[] = run_setting_check('admin_navbar_text_hover', 151);
$all_good &= run_setting_check('admin_navbar_brand_background'); $validations[] = run_setting_check('admin_navbar_brand_background', 151);
$all_good &= run_setting_check('admin_navbar_brand_background_hover'); $validations[] = run_setting_check('admin_navbar_brand_background_hover', 151);
$all_good &= run_setting_check('admin_navbar_brand_text'); $validations[] = run_setting_check('admin_navbar_brand_text', 151);
$all_good &= run_setting_check('admin_navbar_brand_text_hover'); $validations[] = run_setting_check('admin_navbar_brand_text_hover', 151);
$all_good &= run_setting_check('admin_sidebar_background'); $validations[] = run_setting_check('admin_sidebar_background', 151);
$all_good &= run_setting_check('admin_sidebar_background_hover'); $validations[] = run_setting_check('admin_sidebar_background_hover', 151);
$all_good &= run_setting_check('admin_sidebar_text'); $validations[] = run_setting_check('admin_sidebar_text', 151);
$all_good &= run_setting_check('admin_sidebar_text_hover'); $validations[] = run_setting_check('admin_sidebar_text_hover', 151);
$all_good &= run_setting_check('admin_sidebar_font_weight'); $validations[] = run_setting_check('admin_sidebar_font_weight', 151);
$all_good &= run_setting_check('admin_sidebar_header_background'); $validations[] = run_setting_check('admin_sidebar_header_background', 151);
$all_good &= run_setting_check('admin_sidebar_header_text'); $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'); output_header_row('3.2.0');
$all_good &= run_table_check('audit_trail'); $validations[] = run_table_check('audit_trail', 156);
$all_good &= run_table_check('audit_trail_to_replacement_values'); $validations[] = run_table_check('audit_trail_to_replacement_values', 157);
$all_good &= run_column_check('categories', 'mfh_description'); $validations[] = run_column_check('categories', 'mfh_description', 154);
$all_good &= run_column_check('custom_fields', 'mfh_description'); $validations[] = run_column_check('custom_fields', 'mfh_description', 155);
$all_good &= run_setting_check('migrationNumber'); $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>"; echo "<script>$('#all-good').show()</script>";
} else { } elseif ($failed) {
echo "<script>$('#not-good').show()</script>"; echo "<script>$('#not-good').show()</script>";
} }
if ($skipped) {
echo "<script>$('#some-skipped').show()</script>";
}
?> ?>
</tbody> </tbody>
</table> </table>
@ -220,39 +315,53 @@ hesk_dbConnect();
</body> </body>
</html> </html>
<?php <?php
function run_setting_check($setting_name) { function run_setting_check($setting_name, $minimumValidationNumber) {
global $hesk_settings; global $hesk_settings, $startingValidationNumber;
$res = run_check("SELECT 1 FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "settings` WHERE `Key` = '{$setting_name}'"); if ($startingValidationNumber < $minimumValidationNumber) {
$all_good = hesk_dbNumRows($res) > 0; $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) { function run_table_check($table_name, $minimumValidationNumber) {
return run_column_check($table_name, '1');
return run_column_check($table_name, '1', $minimumValidationNumber);
} }
function run_column_check($table_name, $column_name) { function run_column_check($table_name, $column_name, $minimumValidationNumber) {
global $hesk_settings; global $hesk_settings, $startingValidationNumber;
if ($column_name == '1') { 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, output_result('<b>Table Exists</b>: ' . $table_name,
$all_good); $checks);
} else { } 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, 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_last_query;
global $hesk_db_link; global $hesk_db_link;
if (function_exists('mysqli_connect')) { if (function_exists('mysqli_connect')) {
@ -261,23 +370,43 @@ function run_check($sql) {
} }
$hesk_last_query = $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 { } else {
if (!$hesk_db_link && !hesk_dbConnect()) { if (!$hesk_db_link && !hesk_dbConnect()) {
return false; return false;
} }
$hesk_last_query = $sql; $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) { function output_result($change_title, $status) {
$css_color = 'success'; switch ($status) {
$text = '<span data-toggle="tooltip" title="This looks good!"><i class="fa fa-check-circle"></i> Success</span>'; case 'PASS':
if (!$success) { $css_color = 'success';
$css_color = 'danger'; $text = '<span data-toggle="tooltip" title="This looks good!"><i class="fa fa-check-circle"></i> Success</span>';
$text = '<span data-toggle="tooltip" title="Oh no! Something isn\'t right."><i class="fa fa-times-circle"></i> Failure</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); $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, '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.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.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, '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.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.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.1.1' => 154 '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']]; $startingMigrationNumber = $migration_map[$versionRow['Value']];
} }

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

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

@ -7,10 +7,12 @@ use AbstractMigration;
class AddIntColumnUpDropTableDown extends AbstractMigration { class AddIntColumnUpDropTableDown extends AbstractMigration {
function up($hesk_settings) { 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) { 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) { 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 { class DropOldStatusColumn extends AbstractMigration {
function up($hesk_settings) { 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) { function down($hesk_settings) {
$ticketsRS = $this->executeQuery("SELECT `id`, `status_int` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets`;"); // We no longer need to do this thanks to HESK 2.7.0
while ($currentResult = hesk_dbFetchAssoc($ticketsRS)) { //$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']); //
} // $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 { class MoveStatusesToNewColumn extends AbstractMigration {
function up($hesk_settings) { function up($hesk_settings) {
$ticketsRS = $this->executeQuery("SELECT `id`, `status` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets`;"); // We no longer need to do this thanks to HESK 2.7.0
while ($currentResult = hesk_dbFetchAssoc($ticketsRS)) { //$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']); //
} // $this->executeQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status_int` = " . $currentResult['status'] . " WHERE `id` = " . $currentResult['id']);
//}
} }
function down($hesk_settings) { 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 { class RenameTempColumn extends \AbstractMigration {
function up($hesk_settings) { 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) { 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 //3.0.0
127 => new \v300\MigrateHeskCustomStatuses(), 127 => new \v300\MigrateHeskCustomStatuses(),
128 => new \v300\MigrateAutorefreshOption\UpdateFromOldValue(), 128 => new \v300\MigrateAutorefreshOption\UpdateFromOldValue(),
129 => new \v300\MigrateAutorefreshOption\DropOldColumn(), 129 => new \v300\AddColorSchemeSetting(),
130 => new \v300\AddColorSchemeSetting(), 130 => new \v300\MigrateAutorefreshOption\DropOldColumn(),
131 => new LegacyUpdateMigration('3.0.0', '2.6.4'), 131 => new LegacyUpdateMigration('3.0.0', '2.6.4'),
//3.0.1 //3.0.1
132 => new LegacyUpdateMigration('3.0.1', '3.0.0'), 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), 162 => new UpdateMigration('3.2.3', '3.2.2', 162),
163 => new UpdateMigration('3.2.4', '3.2.3', 163), 163 => new UpdateMigration('3.2.4', '3.2.3', 163),
164 => new UpdateMigration('3.2.5', '3.2.4', 164), 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']; $oldSetting = $hesk_settings['can_sel_lang'];
$hesk_settings['can_sel_lang'] = 1; $hesk_settings['can_sel_lang'] = 1;
while ($row = hesk_dbFetchAssoc($statusesRs)) { while ($row = hesk_dbFetchAssoc($statusesRs)) {
$englishText = '';
foreach ($languages as $language => $languageCode) { foreach ($languages as $language => $languageCode) {
hesk_setLanguage($language); 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`) $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); $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, eventLimit: true,
timeFormat: 'H:mm', timeFormat: 'H:mm',
axisFormat: '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(), firstDay: $('#setting_first_day_of_week').text(),
defaultView: $('#setting_default_view').text().trim(), defaultView: $('#setting_default_view').text().trim(),
events: function(start, end, timezone, callback) { events: function(start, end, timezone, callback) {
$.ajax({ $.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', method: 'GET',
dataType: 'json', dataType: 'json',
headers: { 'X-Internal-Call': true },
success: function(data) { success: function(data) {
var events = []; var events = [];
$(data).each(function() { $(data).each(function() {
@ -61,7 +100,8 @@ $(document).ready(function() {
.find('.popover-owner span').text(event.owner).end() .find('.popover-owner span').text(event.owner).end()
.find('.popover-subject span').text(event.subject).end() .find('.popover-subject span').text(event.subject).end()
.find('.popover-category span').text(event.categoryName).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 { } else {
if (event.location === '') { if (event.location === '') {
$contents.find('.popover-location').hide(); $contents.find('.popover-location').hide();
@ -124,7 +164,13 @@ $(document).ready(function() {
}); });
function buildEvent(id, dbObject) { 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 { return {
title: dbObject.title, title: dbObject.title,
subject: dbObject.subject, subject: dbObject.subject,
@ -140,8 +186,9 @@ function buildEvent(id, dbObject) {
categoryName: dbObject.categoryName, categoryName: dbObject.categoryName,
className: 'category-' + dbObject.categoryId, className: 'category-' + dbObject.categoryId,
owner: dbObject.owner, owner: dbObject.owner,
priority: dbObject.priority, priority: priorities[dbObject.priority],
fontIconMarkup: getIcon(dbObject) fontIconMarkup: getIcon(dbObject),
status: dbObject.status
}; };
} }

@ -12,11 +12,49 @@ $(document).ready(function() {
eventLimit: true, eventLimit: true,
timeFormat: 'H:mm', timeFormat: 'H:mm',
axisFormat: '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(), firstDay: $('#setting_first_day_of_week').text(),
defaultView: $('#setting_default_view').text().trim(), defaultView: $('#setting_default_view').text().trim(),
events: function(start, end, timezone, callback) { events: function(start, end, timezone, callback) {
$.ajax({ $.ajax({
url: heskPath + 'internal-api/calendar/?start=' + start + '&end=' + end, url: heskPath + 'api/index.php/v1/calendar/events/?start=' + start + '&end=' + end,
method: 'GET', method: 'GET',
dataType: 'json', dataType: 'json',
success: function(data) { success: function(data) {

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

Loading…
Cancel
Save