Merge branch '3-1-0' into 'master'
3.1.0 Update Closes #535, #428, #397, #565, #549, #561, #562, #560, #531, #395, #405, #456, #353, #551, #559, #557, #556, #524, #523, #527, #528, #525, #339, and #522 See merge request !62
This commit is contained in:
commit
535e48225d
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,3 +1,8 @@
|
||||
# Mods for HESK-specific files
|
||||
api/vendor
|
||||
api/Tests/integration_test_mfh_settings.php
|
||||
|
||||
# HESK Files
|
||||
admin/admin_suggest_articles.php
|
||||
admin/archive.php
|
||||
admin/custom_statuses.php
|
||||
@ -265,7 +270,7 @@ readme.html
|
||||
robots.txt
|
||||
.idea/
|
||||
attachments/__latest.txt
|
||||
attachments
|
||||
/attachments
|
||||
img/ban.png
|
||||
img/banned.png
|
||||
img/ico_tools.png
|
||||
|
@ -531,7 +531,7 @@ $modsForHesk_settings = mfh_getSettings();
|
||||
onclick="javascript:alert('<?php echo hesk_makeJsString($hesklang['settings_intro']) . '\n\n' . hesk_makeJsString($hesklang['all_req']); ?>')"><i
|
||||
class="fa fa-question-circle settingsquestionmark"></i></a>
|
||||
</h2>
|
||||
<form method="post" action="admin_settings_save.php" name="form1" onsubmit="return hesk_checkFields()"
|
||||
<form method="post" enctype="multipart/form-data" action="admin_settings_save.php" name="form1" onsubmit="return hesk_checkFields()"
|
||||
class="form-horizontal" role="form">
|
||||
|
||||
<!-- General Settings -->
|
||||
@ -3426,27 +3426,6 @@ $modsForHesk_settings = mfh_getSettings();
|
||||
value="<?php echo $hesk_settings['online_min']; ?>"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="rtl" class="col-sm-4 col-xs-12 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['displayRtl']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
title="<?php echo $hesklang['displayRtl']; ?>"
|
||||
data-content="<?php echo $hesklang['displayRtlHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input id="rtl" name="rtl" type="checkbox" <?php if ($modsForHesk_settings['rtl']) {
|
||||
echo 'checked';
|
||||
} ?>> <?php echo $hesklang['display_rtl']; ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="show-icons" class="col-sm-4 col-xs-12 control-label">
|
||||
<span class="label label-primary"
|
||||
@ -3527,7 +3506,7 @@ $modsForHesk_settings = mfh_getSettings();
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<h4>Common Properties</h4>
|
||||
<h4><?php echo $hesklang['common_properties']; ?></h4>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
@ -3548,249 +3527,362 @@ $modsForHesk_settings = mfh_getSettings();
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4>Customer View</h4>
|
||||
<h4><?php echo $hesklang['customer_view']; ?></h4>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="navbarBackgroundColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['navbarBackgroundColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['navbarBackgroundColor']; ?>"
|
||||
data-content="<?php echo $hesklang['navbarBackgroundColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="navbarBackgroundColor" name="navbarBackgroundColor"
|
||||
class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['navbarBackgroundColor']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('navbarBackgroundColor', 'navbarBackgroundColor', $modsForHesk_settings['navbarBackgroundColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="navbarBrandColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['navbarBrandColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['navbarBrandColor']; ?>"
|
||||
data-content="<?php echo $hesklang['navbarBrandColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="navbarBrandColor" name="navbarBrandColor"
|
||||
class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['navbarBrandColor']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('navbarBrandColor', 'navbarBrandColor', $modsForHesk_settings['navbarBrandColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="navbarBrandHoverColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['navbarBrandHoverColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['navbarBrandHoverColor']; ?>"
|
||||
data-content="<?php echo $hesklang['navbarBrandHoverColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="navbarBrandHoverColor" name="navbarBrandHoverColor"
|
||||
class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['navbarBrandHoverColor']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('navbarBrandHoverColor', 'navbarBrandHoverColor', $modsForHesk_settings['navbarBrandHoverColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="navbarItemTextColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['navbarItemTextColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['navbarItemTextColor']; ?>"
|
||||
data-content="<?php echo $hesklang['navbarItemTextColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="navbarItemTextColor" name="navbarItemTextColor"
|
||||
class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['navbarItemTextColor']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('navbarItemTextColor', 'navbarItemTextColor', $modsForHesk_settings['navbarItemTextColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="navbarItemTextHoverColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['navbarItemTextHoverColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['navbarItemTextHoverColor']; ?>"
|
||||
data-content="<?php echo $hesklang['navbarItemTextHoverColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="navbarItemTextHoverColor" name="navbarItemTextHoverColor"
|
||||
class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['navbarItemTextHoverColor']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('navbarItemTextHoverColor', 'navbarItemTextHoverColor', $modsForHesk_settings['navbarItemTextHoverColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="navbarItemTextSelectedColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['navbarItemTextSelectedColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['navbarItemTextSelectedColor']; ?>"
|
||||
data-content="<?php echo $hesklang['navbarItemTextSelectedColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="navbarItemTextSelectedColor"
|
||||
name="navbarItemTextSelectedColor" class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['navbarItemTextSelectedColor']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('navbarItemTextSelectedColor', 'navbarItemTextSelectedColor', $modsForHesk_settings['navbarItemTextSelectedColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="navbarItemSelectedBackgroundColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['navbarItemSelectedBackgroundColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['navbarItemSelectedBackgroundColor']; ?>"
|
||||
data-content="<?php echo $hesklang['navbarItemSelectedBackgroundColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="navbarItemSelectedBackgroundColor"
|
||||
name="navbarItemSelectedBackgroundColor" class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['navbarItemSelectedBackgroundColor']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('navbarItemSelectedBackgroundColor', 'navbarItemSelectedBackgroundColor', $modsForHesk_settings['navbarItemSelectedBackgroundColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="dropdownItemTextColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['dropdownItemTextColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['dropdownItemTextColor']; ?>"
|
||||
data-content="<?php echo $hesklang['dropdownItemTextColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="dropdownItemTextColor" name="dropdownItemTextColor"
|
||||
class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['dropdownItemTextColor']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('dropdownItemTextColor', 'dropdownItemTextColor', $modsForHesk_settings['dropdownItemTextColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="dropdownItemTextHoverColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['dropdownItemTextHoverColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['dropdownItemTextHoverColor']; ?>"
|
||||
data-content="<?php echo $hesklang['dropdownItemTextHoverColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="dropdownItemTextHoverColor" name="dropdownItemTextHoverColor"
|
||||
class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['dropdownItemTextHoverColor']; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('dropdownItemTextHoverColor', 'dropdownItemTextHoverColor', $modsForHesk_settings['dropdownItemTextHoverColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="dropdownItemTextHoverBackgroundColor"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['dropdownItemTextHoverBackgroundColor']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['dropdownItemTextHoverBackgroundColor']; ?>"
|
||||
data-content="<?php echo $hesklang['dropdownItemTextHoverBackgroundColorHelp']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<input type="text" id="dropdownItemTextHoverBackgroundColor"
|
||||
name="dropdownItemTextHoverBackgroundColor" class="form-control"
|
||||
value="<?php echo $modsForHesk_settings['dropdownItemTextHoverBackgroundColor']; ?>">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('dropdownItemTextHoverBackgroundColor', 'dropdownItemTextHoverBackgroundColor', $modsForHesk_settings['dropdownItemTextHoverBackgroundColor'], 'Help');
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h4>Admin Panel</h4>
|
||||
<h4><?php echo $hesklang['admin_panel']; ?></h4>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="admin-color-scheme"
|
||||
class="col-sm-3 col-xs-5 control-label"><?php echo $hesklang['color_scheme']; ?>
|
||||
class="col-sm-3 col-xs-5 control-label"><?php echo $hesklang['color_preset']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="left"
|
||||
title="<?php echo $hesklang['color_scheme']; ?>"
|
||||
data-content="<?php echo $hesklang['color_scheme_help']; ?>"></i>
|
||||
title="<?php echo $hesklang['color_preset']; ?>"
|
||||
data-content="<?php echo $hesklang['color_preset_help']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-9 col-xs-7">
|
||||
<select name="admin-color-scheme" class="form-control">
|
||||
<option value="skin-blue"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-blue') { echo 'selected'; } ?>>Blue</option>
|
||||
<option value="skin-blue-light"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-blue-light') { echo 'selected'; } ?>>Blue (Light)</option>
|
||||
<option value="skin-yellow"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-yellow') { echo 'selected'; } ?>>Yellow</option>
|
||||
<option value="skin-yellow-light"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-yellow-light') { echo 'selected'; } ?>>Yellow (Light)</option>
|
||||
<option value="skin-green"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-green') { echo 'selected'; } ?>>Green</option>
|
||||
<option value="skin-green-light"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-green-light') { echo 'selected'; } ?>>Green (Light)</option>
|
||||
<option value="skin-purple"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-purple') { echo 'selected'; } ?>>Purple</option>
|
||||
<option value="skin-purple-light"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-purple-light') { echo 'selected'; } ?>>Purple (Light)</option>
|
||||
<option value="skin-red"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-red') { echo 'selected'; } ?>>Red</option>
|
||||
<option value="skin-red-light"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-red-light') { echo 'selected'; } ?>>Red (Light)</option>
|
||||
<option value="skin-black"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-black') { echo 'selected'; } ?>>Black</option>
|
||||
<option value="skin-black-light"
|
||||
<?php if ($modsForHesk_settings['admin_color_scheme'] == 'skin-black-light') { echo 'selected'; } ?>>Black (Light)</option>
|
||||
<select name="admin-color-scheme" id="admin-color-scheme" class="form-control">
|
||||
<option value="SELECT"><?php echo $hesklang['select_a_preset']; ?></option>
|
||||
<option value="blue"><?php echo $hesklang['preset_blue']; ?></option>
|
||||
<option value="blue-light"><?php echo $hesklang['preset_blue_light']; ?></option>
|
||||
<option value="yellow"><?php echo $hesklang['preset_yellow']; ?></option>
|
||||
<option value="yellow-light"><?php echo $hesklang['preset_yellow_light']; ?></option>
|
||||
<option value="green"><?php echo $hesklang['preset_green']; ?></option>
|
||||
<option value="green-light"><?php echo $hesklang['preset_green_light']; ?></option>
|
||||
<option value="purple"><?php echo $hesklang['preset_purple']; ?></option>
|
||||
<option value="purple-light"><?php echo $hesklang['preset_purple_light']; ?></option>
|
||||
<option value="red"><?php echo $hesklang['preset_red']; ?></option>
|
||||
<option value="red-light"><?php echo $hesklang['preset_red_light']; ?></option>
|
||||
<option value="black"><?php echo $hesklang['preset_black']; ?></option>
|
||||
<option value="black-light"><?php echo $hesklang['preset_black_light']; ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<script>
|
||||
$('select[name="admin-color-scheme"]').change(function() {
|
||||
$('body').removeClass('skin-blue')
|
||||
.removeClass('skin-blue-light')
|
||||
.removeClass('skin-yellow')
|
||||
.removeClass('skin-yellow-light')
|
||||
.removeClass('skin-green')
|
||||
.removeClass('skin-green-light')
|
||||
.removeClass('skin-purple')
|
||||
.removeClass('skin-purple-light')
|
||||
.removeClass('skin-red')
|
||||
.removeClass('skin-red-light')
|
||||
.removeClass('skin-black')
|
||||
.removeClass('skin-black-light')
|
||||
.addClass($(this).val());
|
||||
var val = $(this).val();
|
||||
|
||||
if (val === 'SELECT') {
|
||||
return;
|
||||
}
|
||||
|
||||
var lightTheme = val.match(/.+-light/i);
|
||||
|
||||
$('#cpadmin-sidebar-background-color').colorpicker('setValue', lightTheme ? '#f9fafc' : '#222d32');
|
||||
$('#cpadmin-sidebar-header-background-color').colorpicker('setValue', lightTheme ? '#f9fafc' : '#1a2226');
|
||||
$('#cpadmin-sidebar-text-color').colorpicker('setValue', lightTheme ? '#444' : '#b8c7ce');
|
||||
$('#cpadmin-sidebar-header-text-color').colorpicker('setValue', lightTheme ? '#848484' : '#4b646f');
|
||||
$('#cpadmin-sidebar-text-hover-color').colorpicker('setValue', lightTheme ? '#444' : '#fff');
|
||||
$('#cpadmin-sidebar-background-hover-color').colorpicker('setValue', lightTheme ? '#f4f4f5' : '#1e282c');
|
||||
$('input[name="admin-sidebar-font-weight"]').val(lightTheme ? ['bold'] : ['normal']);
|
||||
|
||||
$('#cpadmin-navbar-text-color').colorpicker('setValue', '#fff');
|
||||
$('#cpadmin-navbar-text-hover-color').colorpicker('setValue', '#fff');
|
||||
$('#cpadmin-navbar-brand-text-color').colorpicker('setValue', '#fff');
|
||||
$('#cpadmin-navbar-brand-text-hover-color').colorpicker('setValue', '#fff');
|
||||
if (val.match(/blue.*/i)) {
|
||||
$('#cpadmin-navbar-background-color').colorpicker('setValue', '#3c8dbc');
|
||||
$('#cpadmin-navbar-background-hover-color').colorpicker('setValue', '#367fa9');
|
||||
|
||||
$('#cpadmin-navbar-brand-background-color').colorpicker('setValue', lightTheme ? '#3c8dbc' : '#367fa9');
|
||||
$('#cpadmin-navbar-brand-background-hover-color').colorpicker('setValue', lightTheme ? '#3b8ab8' : '#357ca5');
|
||||
} else if (val.match(/yellow.*/i)) {
|
||||
$('#cpadmin-navbar-background-color').colorpicker('setValue', '#f39c12');
|
||||
$('#cpadmin-navbar-background-hover-color').colorpicker('setValue', '#da8c10');
|
||||
|
||||
$('#cpadmin-navbar-brand-background-color').colorpicker('setValue', lightTheme ? '#f39c12' : '#e08e0b');
|
||||
$('#cpadmin-navbar-brand-background-hover-color').colorpicker('setValue', lightTheme ? '#f39a0d' : '#db8b0b');
|
||||
} else if (val.match(/green.*/i)) {
|
||||
$('#cpadmin-navbar-background-color').colorpicker('setValue', '#00a65a');
|
||||
$('#cpadmin-navbar-background-hover-color').colorpicker('setValue', '#009551');
|
||||
|
||||
$('#cpadmin-navbar-brand-background-color').colorpicker('setValue', lightTheme ? '#00a65a' : '#008d4c');
|
||||
$('#cpadmin-navbar-brand-background-hover-color').colorpicker('setValue', lightTheme ? '#00a157' : '#008749');
|
||||
} else if (val.match(/purple.*/i)) {
|
||||
$('#cpadmin-navbar-background-color').colorpicker('setValue', '#605ca8');
|
||||
$('#cpadmin-navbar-background-hover-color').colorpicker('setValue', '#565397');
|
||||
|
||||
$('#cpadmin-navbar-brand-background-color').colorpicker('setValue', lightTheme ? '#605ca8' : '#555299');
|
||||
$('#cpadmin-navbar-brand-background-hover-color').colorpicker('setValue', lightTheme ? '#5d59a6' : '#545096');
|
||||
} else if (val.match(/red.*/i)) {
|
||||
$('#cpadmin-navbar-background-color').colorpicker('setValue', '#dd4b39');
|
||||
$('#cpadmin-navbar-background-hover-color').colorpicker('setValue', '#c64333');
|
||||
|
||||
$('#cpadmin-navbar-brand-background-color').colorpicker('setValue', lightTheme ? '#dd4b39' : '#d73925');
|
||||
$('#cpadmin-navbar-brand-background-hover-color').colorpicker('setValue', lightTheme ? '#dc4735' : '#d33724');
|
||||
} else {
|
||||
//-- Black
|
||||
$('#cpadmin-navbar-background-color').colorpicker('setValue', '#fff');
|
||||
$('#cpadmin-navbar-background-hover-color').colorpicker('setValue', '#eee');
|
||||
|
||||
$('#cpadmin-navbar-brand-background-color').colorpicker('setValue', '#fff');
|
||||
$('#cpadmin-navbar-brand-background-hover-color').colorpicker('setValue', '#fcfcfc');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="col-sm-5 col-sm-offset-7 col-xs-12">
|
||||
<h4><?php echo $hesklang['navbar']; ?></h4>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-navbar-background-color', 'background_color', $modsForHesk_settings['admin_navbar_background']);
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="col-sm-5 col-sm-offset-7 col-xs-12">
|
||||
<h4><?php echo $hesklang['navbar_brand']; ?></h4>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-navbar-brand-background-color', 'background_color', $modsForHesk_settings['admin_navbar_brand_background']);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-navbar-text-color', 'text_color', $modsForHesk_settings['admin_navbar_text']);
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-navbar-brand-text-color', 'text_color', $modsForHesk_settings['admin_navbar_brand_text']);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-navbar-text-hover-color', 'text_hover_color', $modsForHesk_settings['admin_navbar_text_hover']);
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-navbar-brand-text-hover-color', 'text_hover_color', $modsForHesk_settings['admin_navbar_brand_text_hover']);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-navbar-background-hover-color', 'background_hover_color', $modsForHesk_settings['admin_navbar_background_hover']);
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-navbar-brand-background-hover-color', 'background_hover_color', $modsForHesk_settings['admin_navbar_brand_background_hover']);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="col-sm-5 col-sm-offset-7 col-xs-12">
|
||||
<h4><?php echo $hesklang['sidebar']; ?></h4>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-sidebar-background-color', 'background_color', $modsForHesk_settings['admin_sidebar_background']);
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="col-sm-5 col-sm-offset-7 col-xs-12">
|
||||
<h4><?php echo $hesklang['sidebar_header']; ?></h4>
|
||||
</div>
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-sidebar-header-background-color', 'background_color', $modsForHesk_settings['admin_sidebar_header_background']);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-sidebar-text-color', 'text_color', $modsForHesk_settings['admin_sidebar_text']);
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-sidebar-header-text-color', 'text_color', $modsForHesk_settings['admin_sidebar_header_text']);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-sidebar-text-hover-color', 'text_hover_color', $modsForHesk_settings['admin_sidebar_text_hover']);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<?php
|
||||
buildColorSchemeColorpicker('admin-sidebar-background-hover-color', 'background_hover_color', $modsForHesk_settings['admin_sidebar_background_hover']);
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="admin-sidebar-font-weight"
|
||||
class="col-sm-7 col-xs-12 control-label"><?php echo $hesklang['font_weight']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="top"
|
||||
title="<?php echo $hesklang['font_weight']; ?>"
|
||||
data-content="<?php echo $hesklang['font_weight_help']; ?>"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12 form-inline">
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="admin-sidebar-font-weight" value="normal"
|
||||
<?php echo $modsForHesk_settings['admin_sidebar_font_weight'] == 'normal' ? 'checked' : ''; ?>>
|
||||
<?php echo $hesklang['normal']; ?>
|
||||
</label>
|
||||
</div><br>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="admin-sidebar-font-weight" value="bold"
|
||||
<?php echo $modsForHesk_settings['admin_sidebar_font_weight'] == 'bold' ? 'checked' : ''; ?>>
|
||||
<?php echo $hesklang['bold']; ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h4><?php echo $hesklang['login_page']; ?></h4>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="login-background" class="col-sm-3 col-xs-5 control-label">
|
||||
<?php echo $hesklang['login_background']; ?>
|
||||
</label>
|
||||
<div class="col-sm-9 col-xs-7 form-inline">
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="login-background"
|
||||
data-activate="input[name='login-background-color']" data-deactivate="input[name='login-background-image']"
|
||||
value="color" <?php if ($modsForHesk_settings['login_background_type'] == 'color') { echo 'checked'; } ?>>
|
||||
<?php echo $hesklang['solid_color']; ?>
|
||||
</label>
|
||||
</div>
|
||||
<input title="<?php echo $hesklang['login_background_color']; ?>" type="text"
|
||||
name="login-background-color" class="form-control"
|
||||
<?php if ($modsForHesk_settings['login_background_type'] == 'image') { echo 'disabled'; } ?>>
|
||||
<br>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="login-background"
|
||||
data-activate="input[name='login-background-image']" data-deactivate="input[name='login-background-color']"
|
||||
value="image" <?php if ($modsForHesk_settings['login_background_type'] == 'image') { echo 'checked'; } ?>>
|
||||
<?php echo $hesklang['image']; ?>
|
||||
</label>
|
||||
</div>
|
||||
<input title="<?php echo $hesklang['login_background_image']; ?>" type="file" name="login-background-image" style="display: inline;vertical-align: bottom" <?php if ($modsForHesk_settings['login_background_type'] == 'color') { echo 'disabled'; } ?>>
|
||||
<?php if ($modsForHesk_settings['login_background_type'] == 'image'): ?>
|
||||
<br>
|
||||
<img src="<?php echo HESK_PATH . $hesk_settings['cache_dir']; ?>/lb_<?php echo $modsForHesk_settings['login_background']; ?>" alt="<?php echo $hesklang['login_background']; ?>" title="<?php echo $hesklang['login_background']; ?>" height="125" width="125" class="push-down-10">
|
||||
<?php endif; ?>
|
||||
<script type="text/javascript">
|
||||
$('input[name="login-background-color"]').colorpicker({
|
||||
format: 'hex',
|
||||
color: <?php if ($modsForHesk_settings['login_background_type'] == 'color') { echo "'{$modsForHesk_settings['login_background']}'"; } else { echo 'false'; } ?>
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="form-group">
|
||||
<label for="login-box-header" class="col-sm-3 col-xs-5 control-label">
|
||||
<?php echo $hesklang['login_box_header']; ?>
|
||||
</label>
|
||||
<div class="col-sm-9 col-xs-7 form-inline">
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="login-box-header" value="helpdesk-title" data-deactivate="input[name='login-box-header-image']" <?php if ($modsForHesk_settings['login_box_header'] == 'helpdesk-title') { echo 'checked'; } ?>>
|
||||
<?php echo $hesklang['hesk_title']; ?>
|
||||
</label>
|
||||
</div><br>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="login-box-header" value="image" data-activate="input[name='login-box-header-image']" <?php if ($modsForHesk_settings['login_box_header'] == 'image') { echo 'checked'; } ?>>
|
||||
<?php echo $hesklang['image']; ?>
|
||||
</label>
|
||||
<input title="<?php echo $hesklang['login_header_image']; ?>" type="file" name="login-box-header-image" style="display: inline;vertical-align: bottom" <?php if ($modsForHesk_settings['login_box_header'] == 'helpdesk-title') { echo 'disabled'; } ?>>
|
||||
<?php if ($modsForHesk_settings['login_box_header'] == 'image'): ?>
|
||||
<br>
|
||||
<img src="<?php echo HESK_PATH . $hesk_settings['cache_dir']; ?>/lbh_<?php echo $modsForHesk_settings['login_box_header_image']; ?>" title="<?php echo $modsForHesk_settings['login_box_header_image']; ?>" alt="<?php echo $modsForHesk_settings['login_box_header_image']; ?>" style="height: 75px" class="push-down-10">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" style="margin-left: 10px">
|
||||
@ -3811,6 +3903,37 @@ $modsForHesk_settings = mfh_getSettings();
|
||||
require_once(HESK_PATH . 'inc/footer.inc.php');
|
||||
exit();
|
||||
|
||||
function buildColorSchemeColorpicker($field_name, $label_key, $color, $help_suffix = '_help') {
|
||||
global $hesklang;
|
||||
|
||||
echo '
|
||||
<div class="form-group">
|
||||
<label for="admin-navbar-background-color"
|
||||
class="col-sm-7 col-xs-12 control-label">'. $hesklang[$label_key] . '
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
data-placement="top"
|
||||
title="' . htmlspecialchars($hesklang[$label_key]) . '"
|
||||
data-content="' . htmlspecialchars($hesklang[$label_key . $help_suffix]) . '"></i>
|
||||
</label>
|
||||
|
||||
<div class="col-sm-5 col-xs-12">
|
||||
<div id="cp' . $field_name . '" class="input-group">
|
||||
<input type="text" id="' . $field_name . '" name="' . $field_name . '"
|
||||
class="form-control"
|
||||
value="' . $color . '">
|
||||
<span class="input-group-addon"><i></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$("#cp' . $field_name . '").colorpicker({
|
||||
color: "' . $color . '",
|
||||
format: "hex"
|
||||
});
|
||||
</script>
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
function hesk_checkVersion()
|
||||
{
|
||||
@ -4064,7 +4187,7 @@ $modsForHesk_settings = mfh_getSettings();
|
||||
background: #fff;
|
||||
color: black;
|
||||
font: 68.8%/1.5 Verdana, Geneva, Arial, Helvetica, sans-serif;
|
||||
text-align: <?php if ($modsForHesk_settings['rtl']) { echo 'right'; } else { echo 'left'; } ?>;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p {
|
||||
|
@ -39,6 +39,8 @@ hesk_checkPermission('can_manage_settings');
|
||||
// A security check
|
||||
hesk_token_check('POST');
|
||||
|
||||
$modsForHesk_settings = mfh_getSettings();
|
||||
|
||||
// Demo mode
|
||||
if (defined('HESK_DEMO')) {
|
||||
hesk_process_messages($hesklang['sdemo'], 'admin_settings.php');
|
||||
@ -447,7 +449,6 @@ foreach ($postArray as $value) {
|
||||
}
|
||||
|
||||
// Save the modsForHesk_settings.inc.php file
|
||||
$set['rtl'] = empty($_POST['rtl']) ? 0 : 1;
|
||||
$set['show-icons'] = empty($_POST['show-icons']) ? 0 : 1;
|
||||
$set['custom-field-setting'] = empty($_POST['custom-field-setting']) ? 0 : 1;
|
||||
$set['customer-email-verification-required'] = empty($_POST['email-verification']) ? 0 : 1;
|
||||
@ -494,8 +495,115 @@ $set['dropdownItemTextColor'] = hesk_input(hesk_POST('dropdownItemTextColor'));
|
||||
$set['dropdownItemTextHoverColor'] = hesk_input(hesk_POST('dropdownItemTextHoverColor'));
|
||||
$set['questionMarkColor'] = hesk_input(hesk_POST('questionMarkColor'));
|
||||
$set['dropdownItemTextHoverBackgroundColor'] = hesk_input(hesk_POST('dropdownItemTextHoverBackgroundColor'));
|
||||
$set['admin_color_scheme'] = hesk_input(hesk_POST('admin-color-scheme'));
|
||||
mfh_updateSetting('rtl', $set['rtl']);
|
||||
$set['admin_navbar_background'] = hesk_input(hesk_POST('admin-navbar-background-color'));
|
||||
$set['admin_navbar_background_hover'] = hesk_input(hesk_POST('admin-navbar-background-hover-color'));
|
||||
$set['admin_navbar_brand_background'] = hesk_input(hesk_POST('admin-navbar-brand-background-color'));
|
||||
$set['admin_navbar_brand_background_hover'] = hesk_input(hesk_POST('admin-navbar-brand-background-hover-color'));
|
||||
$set['admin_navbar_brand_text'] = hesk_input(hesk_POST('admin-navbar-brand-text-color'));
|
||||
$set['admin_navbar_brand_text_hover'] = hesk_input(hesk_POST('admin-navbar-brand-text-hover-color'));
|
||||
$set['admin_navbar_text'] = hesk_input(hesk_POST('admin-navbar-text-color'));
|
||||
$set['admin_navbar_text_hover'] = hesk_input(hesk_POST('admin-navbar-text-hover-color'));
|
||||
$set['admin_sidebar_background'] = hesk_input(hesk_POST('admin-sidebar-background-color'));
|
||||
$set['admin_sidebar_background_hover'] = hesk_input(hesk_POST('admin-sidebar-header-background-color'));
|
||||
$set['admin_sidebar_font_weight'] = hesk_input(hesk_POST('admin-sidebar-font-weight'));
|
||||
$set['admin_sidebar_header_background'] = hesk_input(hesk_POST('admin-sidebar-header-background-color'));
|
||||
$set['admin_sidebar_header_text'] = hesk_input(hesk_POST('admin-sidebar-header-text-color'));
|
||||
$set['admin_sidebar_text'] = hesk_input(hesk_POST('admin-sidebar-text-color'));
|
||||
$set['admin_sidebar_text_hover'] = hesk_input(hesk_POST('admin-sidebar-text-hover-color'));
|
||||
|
||||
$set['login_background_type'] = hesk_input(hesk_POST('login-background'));
|
||||
$set['login_box_header'] = hesk_input(hesk_POST('login-box-header'));
|
||||
|
||||
$changedBackground = false;
|
||||
$loadedAttachmentFuncs = false;
|
||||
if ($set['login_background_type'] == 'color') {
|
||||
if (file_exists($hesk_settings['cache_dir'] . '/lb_' . $set['login_background'])) {
|
||||
unlink($hesk_settings['cache_dir'] . '/lb_' . $set['login_background']);
|
||||
}
|
||||
$set['login_background'] = hesk_input(hesk_POST('login-background-color'));
|
||||
if ($set['login_background'] == '') {
|
||||
$set['login_background'] = '#d2d6de';
|
||||
}
|
||||
|
||||
$changedBackground = true;
|
||||
} else {
|
||||
if (!$loadedAttachmentFuncs) {
|
||||
include(HESK_PATH . 'inc/attachments.inc.php');
|
||||
include(HESK_PATH . 'inc/posting_functions.inc.php');
|
||||
$loadedAttachmentFuncs = true;
|
||||
}
|
||||
|
||||
|
||||
$file_name = hesk_cleanFileName($_FILES['login-background-image']['name']);
|
||||
|
||||
|
||||
if (!empty($_FILES['login-background-image']['name'])) {
|
||||
$file_size = $_FILES['login-background-image']['size'];
|
||||
if ($file_size > $hesk_settings['attachments']['max_size']) {
|
||||
return hesk_fileError(sprintf($hesklang['file_too_large'], $file_name));
|
||||
}
|
||||
$ext = strtolower(strrchr($file_name, "."));
|
||||
|
||||
if (file_exists($hesk_settings['cache_dir'] . '/lb_' . $modsForHesk_settings['login_background'])) {
|
||||
unlink($hesk_settings['cache_dir'] . '/lb_' . $modsForHesk_settings['login_background']);
|
||||
}
|
||||
|
||||
$saved_name = 'login-background' . $ext;
|
||||
|
||||
$file_to_move = $_FILES['login-background-image']['tmp_name'];
|
||||
|
||||
|
||||
if (!move_uploaded_file($file_to_move, dirname(dirname(__FILE__)) . '/' . $hesk_settings['cache_dir'] . '/lb_' . $saved_name)) {
|
||||
hesk_error($hesklang['cannot_move_tmp']);
|
||||
}
|
||||
|
||||
$set['login_background'] = $saved_name;
|
||||
$changedBackground = true;
|
||||
}
|
||||
}
|
||||
$changedLoginImage = false;
|
||||
if ($set['login_box_header'] == 'image') {
|
||||
if (!$loadedAttachmentFuncs) {
|
||||
include(HESK_PATH . 'inc/attachments.inc.php');
|
||||
include(HESK_PATH . 'inc/posting_functions.inc.php');
|
||||
$loadedAttachmentFuncs = true;
|
||||
}
|
||||
|
||||
|
||||
$file_name = hesk_cleanFileName($_FILES['login-box-header-image']['name']);
|
||||
|
||||
if (!empty($_FILES['login-box-header-image']['name'])) {
|
||||
$file_size = $_FILES['login-box-header-image']['size'];
|
||||
if ($file_size > $hesk_settings['attachments']['max_size']) {
|
||||
return hesk_fileError(sprintf($hesklang['file_too_large'], $file_name));
|
||||
}
|
||||
$ext = strtolower(strrchr($file_name, "."));
|
||||
|
||||
if (file_exists($hesk_settings['cache_dir'] . '/lbh_' . $modsForHesk_settings['login_box_header_image'])) {
|
||||
unlink($hesk_settings['cache_dir'] . '/lbh_' . $modsForHesk_settings['login_box_header_image']);
|
||||
}
|
||||
|
||||
$saved_name = 'login-box-header-image' . $ext;
|
||||
|
||||
$file_to_move = $_FILES['login-box-header-image']['tmp_name'];
|
||||
|
||||
|
||||
if (!move_uploaded_file($file_to_move, dirname(dirname(__FILE__)) . '/' . $hesk_settings['cache_dir'] . '/lbh_' . $saved_name)) {
|
||||
hesk_error($hesklang['cannot_move_tmp']);
|
||||
}
|
||||
|
||||
$set['login_box_header_image'] = $saved_name;
|
||||
$changedLoginImage = true;
|
||||
}
|
||||
} else {
|
||||
if (file_exists($hesk_settings['cache_dir'] . '/lbh_' . $set['login_box_header_image'])) {
|
||||
unlink($hesk_settings['cache_dir'] . '/lbh_' . $set['login_box_header_image']);
|
||||
}
|
||||
|
||||
$set['login_box_header_image'] = '';
|
||||
$changedLoginImage = true;
|
||||
}
|
||||
|
||||
mfh_updateSetting('show_icons', $set['show-icons']);
|
||||
mfh_updateSetting('custom_field_setting', $set['custom-field-setting']);
|
||||
mfh_updateSetting('customer_email_verification_required', $set['customer-email-verification-required']);
|
||||
@ -521,6 +629,21 @@ mfh_updateSetting('dropdownItemTextColor', $set['dropdownItemTextColor'], true);
|
||||
mfh_updateSetting('dropdownItemTextHoverColor', $set['dropdownItemTextHoverColor'], true);
|
||||
mfh_updateSetting('questionMarkColor', $set['questionMarkColor'], true);
|
||||
mfh_updateSetting('dropdownItemTextHoverBackgroundColor', $set['dropdownItemTextHoverBackgroundColor'], true);
|
||||
mfh_updateSetting('admin_navbar_background', $set['admin_navbar_background'], true);
|
||||
mfh_updateSetting('admin_navbar_background_hover', $set['admin_navbar_background_hover'], true);
|
||||
mfh_updateSetting('admin_navbar_brand_background', $set['admin_navbar_brand_background'], true);
|
||||
mfh_updateSetting('admin_navbar_brand_background_hover', $set['admin_navbar_brand_background_hover'], true);
|
||||
mfh_updateSetting('admin_navbar_brand_text', $set['admin_navbar_brand_text'], true);
|
||||
mfh_updateSetting('admin_navbar_brand_text_hover', $set['admin_navbar_brand_text_hover'], true);
|
||||
mfh_updateSetting('admin_navbar_text', $set['admin_navbar_text'], true);
|
||||
mfh_updateSetting('admin_navbar_text_hover', $set['admin_navbar_text_hover'], true);
|
||||
mfh_updateSetting('admin_sidebar_background', $set['admin_sidebar_background'], true);
|
||||
mfh_updateSetting('admin_sidebar_background_hover', $set['admin_sidebar_background_hover'], true);
|
||||
mfh_updateSetting('admin_sidebar_font_weight', $set['admin_sidebar_font_weight'], true);
|
||||
mfh_updateSetting('admin_sidebar_header_background', $set['admin_sidebar_header_background'], true);
|
||||
mfh_updateSetting('admin_sidebar_header_text', $set['admin_sidebar_header_text'], true);
|
||||
mfh_updateSetting('admin_sidebar_text', $set['admin_sidebar_text'], true);
|
||||
mfh_updateSetting('admin_sidebar_text_hover', $set['admin_sidebar_text_hover'], true);
|
||||
mfh_updateSetting('display_user_agent_information', $set['display_user_agent_information']);
|
||||
mfh_updateSetting('navbar_title_url', $set['navbar_title_url'], true);
|
||||
if ($set['use_mailgun'] == 1) {
|
||||
@ -533,6 +656,16 @@ mfh_updateSetting('first_day_of_week', $set['first_day_of_week'], false);
|
||||
mfh_updateSetting('default_calendar_view', $set['default_view'], true);
|
||||
mfh_updateSetting('admin_color_scheme', $set['admin_color_scheme'], true);
|
||||
|
||||
mfh_updateSetting('login_background_type', $set['login_background_type'], true);
|
||||
if ($changedBackground) {
|
||||
mfh_updateSetting('login_background', $set['login_background'], true);
|
||||
}
|
||||
|
||||
mfh_updateSetting('login_box_header', $set['login_box_header'], true);
|
||||
if ($changedLoginImage) {
|
||||
mfh_updateSetting('login_box_header_image', $set['login_box_header_image'], true);
|
||||
}
|
||||
|
||||
// Prepare settings file and save it
|
||||
$settings_file_content = '<?php
|
||||
// Settings file for HESK ' . $set['hesk_version'] . '
|
||||
|
@ -17,7 +17,7 @@ define('WYSIWYG', 1);
|
||||
define('VALIDATOR', 1);
|
||||
define('MFH_PAGE_LAYOUT', 'TOP_AND_SIDE');
|
||||
|
||||
define('EXTRA_JS', '<script src="'.HESK_PATH.'internal-api/js/admin-ticket.js"></script>');
|
||||
define('EXTRA_JS', '<script src="'.HESK_PATH.'internal-api/js/admin-ticket.js"></script><script src="'.HESK_PATH.'js/jquery.dirtyforms.min.js"></script>');
|
||||
|
||||
/* Get all the required files and functions */
|
||||
require(HESK_PATH . 'hesk_settings.inc.php');
|
||||
@ -470,7 +470,7 @@ if (($can_reply || $can_edit) && isset($_POST['childTrackingId'])) {
|
||||
}
|
||||
|
||||
//-- Check if the ticket is already a child.
|
||||
$childRs = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `parent` = ' . intval($ticket['id']) . ' AND `trackid` = \'' . hesk_dbEscape(hesk_POST(['childTrackingId'])) . '\'');
|
||||
$childRs = hesk_dbQuery('SELECT * FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'tickets` WHERE `parent` = ' . intval($ticket['id']) . ' AND `trackid` = \'' . hesk_dbEscape(hesk_POST('childTrackingId')) . '\'');
|
||||
if (hesk_dbNumRows($childRs) > 0) {
|
||||
hesk_process_messages(sprintf($hesklang['is_already_linked'], $_POST['childTrackingId']), 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . mt_rand(10000, 99999), 'NOTICE');
|
||||
}
|
||||
@ -1167,7 +1167,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
<?php build_dropzone_markup(true, 'notesFiledrop'); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/ticket/upload-attachment.php', 'notesFiledrop'); ?>
|
||||
<?php display_dropzone_field(HESK_PATH . 'internal-api/ticket/upload-attachment.php', 'notesFiledrop'); ?>
|
||||
<div class="text-right">
|
||||
<i><?php echo $hesklang['nhid']; ?></i>
|
||||
<div class="btn-group">
|
||||
@ -1500,6 +1500,22 @@ function hesk_getAdminButtonsInTicket($reply = 0, $white = 1)
|
||||
|
||||
$options = $reply ? '' : '<div class="pull-right">';
|
||||
|
||||
// Resend email notification
|
||||
$replyDataAttribute = '';
|
||||
if ($reply) {
|
||||
$replyDataAttribute = 'data-reply-id="' . $reply['id'] . '"';
|
||||
}
|
||||
|
||||
if ($ticket['email'] !== '') {
|
||||
$options .= '
|
||||
<button class="btn btn-default" data-action="resend-email-notification" ' . $replyDataAttribute . ' data-ticket-id="' . $ticket['id'] . '">
|
||||
<i class="fa fa-envelope navy-blue"></i> ' . $hesklang['resend_email_notification'] . '
|
||||
</button>
|
||||
<span id="lang_email_notification_sent" style="display: none">' . $hesklang['email_notification_sent'] . '</span>
|
||||
<span id="lang_email_notification_resend_failed" style="display: none">' . $hesklang['email_notification_resend_failed'] . '</span>
|
||||
';
|
||||
}
|
||||
|
||||
/* Edit post */
|
||||
if ($can_edit) {
|
||||
$tmp = $reply ? '&reply=' . $reply['id'] : '';
|
||||
@ -1870,7 +1886,7 @@ function hesk_printReplyForm()
|
||||
$onsubmit = 'onsubmit="force_stop();return validateRichText(\'message-help-block\', \'message-group\', \'message\', \''.htmlspecialchars($hesklang['this_field_is_required']).'\')"';
|
||||
}
|
||||
?>
|
||||
<form role="form" data-toggle="validator" class="form-horizontal" method="post" action="admin_reply_ticket.php"
|
||||
<form id="reply-form" role="form" data-toggle="validator" class="form-horizontal" method="post" action="admin_reply_ticket.php"
|
||||
enctype="multipart/form-data" name="form1" <?php echo $onsubmit; ?>>
|
||||
<?php
|
||||
|
||||
@ -1963,7 +1979,7 @@ function hesk_printReplyForm()
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/ticket/upload-attachment.php');
|
||||
display_dropzone_field(HESK_PATH . 'internal-api/ticket/upload-attachment.php');
|
||||
}
|
||||
?>
|
||||
<div class="form-group">
|
||||
@ -2046,6 +2062,7 @@ function hesk_printReplyForm()
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<script>$('form#reply-form').dirtyForms();</script>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END REPLY FORM -->
|
||||
|
@ -1,37 +1,9 @@
|
||||
<?php
|
||||
/*******************************************************************************
|
||||
* Title: Help Desk Software HESK
|
||||
* Version: 2.6.5 from 28th August 2015
|
||||
* Author: Klemen Stirn
|
||||
* Website: https://www.hesk.com
|
||||
********************************************************************************
|
||||
* COPYRIGHT AND TRADEMARK NOTICE
|
||||
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
|
||||
* HESK is a registered trademark of Klemen Stirn.
|
||||
* The HESK may be used and modified free of charge by anyone
|
||||
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
|
||||
* By using this code you agree to indemnify Klemen Stirn from any
|
||||
* liability that might arise from it's use.
|
||||
* Selling the code for this program, in part or full, without prior
|
||||
* written consent is expressly forbidden.
|
||||
* Using this code, in part or full, to create derivate work,
|
||||
* new scripts or products is expressly forbidden. Obtain permission
|
||||
* before redistributing this software over the Internet or in
|
||||
* any other medium. In all cases copyright and header must remain intact.
|
||||
* This Copyright is in full effect in any country that has International
|
||||
* Trade Agreements with the United States of America or
|
||||
* with the European Union.
|
||||
* Removing any of the copyright notices without purchasing a license
|
||||
* is expressly forbidden. To remove HESK copyright notice you must purchase
|
||||
* a license for this script. For more information on how to obtain
|
||||
* a license please visit the page below:
|
||||
* https://www.hesk.com/buy.php
|
||||
*******************************************************************************/
|
||||
|
||||
define('IN_SCRIPT', 1);
|
||||
define('HESK_PATH', '../');
|
||||
define('PAGE_TITLE', 'ADMIN_SETTINGS');
|
||||
define('MFH_PAGE_LAYOUT', 'TOP_AND_SIDE');
|
||||
define('PAGE_TITLE', 'ADMIN_API_SETTINGS');
|
||||
define('MFH_PAGE_LAYOUT', 'TOP_ONLY');
|
||||
|
||||
// Make sure the install folder is deleted
|
||||
if (is_dir(HESK_PATH . 'install')) {
|
||||
@ -120,7 +92,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#general" data-toggle="tab"><?php echo $hesklang['tab_1']; ?></a></li>
|
||||
<li><a href="#user-security" data-toggle="tab"><?php echo $hesklang['user_security']; ?></a></li>
|
||||
<li><a href="#" target="_blank"><?php echo $hesklang['api_documentation']; ?> <i class="fa fa-external-link"></i></a></li>
|
||||
<li><a href="https://mods-for-hesk.readme.io/reference" target="_blank"><?php echo $hesklang['api_documentation']; ?> <i class="fa fa-external-link"></i></a></li>
|
||||
</ul>
|
||||
<div class="tab-content summaryList tabPadding">
|
||||
<div class="tab-pane fade in active" id="general">
|
||||
|
@ -1,32 +1,15 @@
|
||||
<?php
|
||||
/*******************************************************************************
|
||||
* Title: Help Desk Software HESK
|
||||
* Version: 2.6.1 from 26th February 2015
|
||||
* Author: Klemen Stirn
|
||||
* Website: https://www.hesk.com
|
||||
********************************************************************************
|
||||
* COPYRIGHT AND TRADEMARK NOTICE
|
||||
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
|
||||
* HESK is a registered trademark of Klemen Stirn.
|
||||
* The HESK may be used and modified free of charge by anyone
|
||||
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
|
||||
* By using this code you agree to indemnify Klemen Stirn from any
|
||||
* liability that might arise from it's use.
|
||||
* Selling the code for this program, in part or full, without prior
|
||||
* written consent is expressly forbidden.
|
||||
* Using this code, in part or full, to create derivate work,
|
||||
* new scripts or products is expressly forbidden. Obtain permission
|
||||
* before redistributing this software over the Internet or in
|
||||
* any other medium. In all cases copyright and header must remain intact.
|
||||
* This Copyright is in full effect in any country that has International
|
||||
* Trade Agreements with the United States of America or
|
||||
* with the European Union.
|
||||
* Removing any of the copyright notices without purchasing a license
|
||||
* is expressly forbidden. To remove HESK copyright notice you must purchase
|
||||
* a license for this script. For more information on how to obtain
|
||||
* a license please visit the page below:
|
||||
* https://www.hesk.com/buy.php
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
define('IN_SCRIPT', 1);
|
||||
define('HESK_PATH', '../');
|
||||
|
@ -1,32 +1,4 @@
|
||||
<?php
|
||||
/*******************************************************************************
|
||||
* Title: Help Desk Software HESK
|
||||
* Version: 2.6.5 from 28th August 2015
|
||||
* Author: Klemen Stirn
|
||||
* Website: https://www.hesk.com
|
||||
********************************************************************************
|
||||
* COPYRIGHT AND TRADEMARK NOTICE
|
||||
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
|
||||
* HESK is a registered trademark of Klemen Stirn.
|
||||
* The HESK may be used and modified free of charge by anyone
|
||||
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
|
||||
* By using this code you agree to indemnify Klemen Stirn from any
|
||||
* liability that might arise from it's use.
|
||||
* Selling the code for this program, in part or full, without prior
|
||||
* written consent is expressly forbidden.
|
||||
* Using this code, in part or full, to create derivate work,
|
||||
* new scripts or products is expressly forbidden. Obtain permission
|
||||
* before redistributing this software over the Internet or in
|
||||
* any other medium. In all cases copyright and header must remain intact.
|
||||
* This Copyright is in full effect in any country that has International
|
||||
* Trade Agreements with the United States of America or
|
||||
* with the European Union.
|
||||
* Removing any of the copyright notices without purchasing a license
|
||||
* is expressly forbidden. To remove HESK copyright notice you must purchase
|
||||
* a license for this script. For more information on how to obtain
|
||||
* a license please visit the page below:
|
||||
* https://www.hesk.com/buy.php
|
||||
*******************************************************************************/
|
||||
|
||||
define('IN_SCRIPT', 1);
|
||||
define('VALIDATOR', 1);
|
||||
@ -61,14 +33,26 @@ if ($modsForHesk_settings['enable_calendar'] == '0') {
|
||||
|
||||
// Get categories for the dropdown
|
||||
$order_by = $modsForHesk_settings['category_order_column'];
|
||||
$rs = hesk_dbQuery("SELECT `id`, `name`, `color` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE `usage` <> 1 ORDER BY `" . hesk_dbEscape($order_by) . "`");
|
||||
$rs = hesk_dbQuery("SELECT `id`, `name`, `background_color`, `foreground_color`, `display_border_outline`
|
||||
FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories`
|
||||
WHERE `usage` <> 1 ORDER BY `" . hesk_dbEscape($order_by) . "`");
|
||||
$categories = array();
|
||||
while ($row = hesk_dbFetchAssoc($rs)) {
|
||||
if (!$_SESSION['isadmin'] && !in_array($row['id'], $_SESSION['categories'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$row['css_style'] = $row['color'] == null ? 'background: white; color: black; border: solid 1px #000;' : 'border: solid 1px ' . $row['color'] . '; background: ' . $row['color'];
|
||||
$row['css_style'] = "background: {$row['background_color']};";
|
||||
$row['background_volatile'] = 'background-volatile';
|
||||
if ($row['foreground_color'] != 'AUTO') {
|
||||
$row['background_volatile'] = '';
|
||||
$row['css_style'] .= " color: {$row['foreground_color']};";
|
||||
|
||||
if ($row['display_border_outline'] == '1') {
|
||||
$row['css_style'] .= " border: solid 1px {$row['foreground_color']};";
|
||||
}
|
||||
}
|
||||
|
||||
$categories[] = $row;
|
||||
}
|
||||
|
||||
@ -85,7 +69,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
<?php foreach ($categories as $category): ?>
|
||||
<li>
|
||||
<div class="ticket-info">
|
||||
<div class="hide-on-overflow no-wrap event-category background-volatile"
|
||||
<div class="hide-on-overflow no-wrap event-category <?php echo $category['background_volatile']; ?>"
|
||||
data-select-toggle="category-toggle" data-name="category-toggle" data-category-value="<?php echo $category['id']; ?>"
|
||||
data-checked="1"
|
||||
data-toggle="tooltip"
|
||||
@ -223,7 +207,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
echo '<option value="">'.$hesklang['select'].'</option>';
|
||||
}
|
||||
foreach ($categories as $category): ?>
|
||||
<option value="<?php echo $category['id']; ?>" data-color="<?php echo htmlspecialchars($category['color']); ?>">
|
||||
<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; ?>
|
||||
@ -393,7 +379,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
echo '<option value="">'.$hesklang['select'].'</option>';
|
||||
}
|
||||
foreach ($categories as $category): ?>
|
||||
<option value="<?php echo $category['id']; ?>" data-color="<?php echo $category['color']; ?>">
|
||||
<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; ?>
|
||||
|
@ -608,7 +608,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/ticket/upload-attachment.php',
|
||||
display_dropzone_field(HESK_PATH . 'internal-api/ticket/upload-attachment.php',
|
||||
'filedrop',
|
||||
$hesk_settings['attachments']['max_number'] - $number_of_attachments);
|
||||
endif; ?>
|
||||
|
@ -246,7 +246,7 @@ function do_login()
|
||||
|
||||
function print_login()
|
||||
{
|
||||
global $hesk_settings, $hesklang;
|
||||
global $hesk_settings, $hesklang, $modsForHesk_settings;
|
||||
|
||||
// Tell header to load reCaptcha API if needed
|
||||
if ($hesk_settings['recaptcha_use'] == 2)
|
||||
@ -269,9 +269,8 @@ function print_login()
|
||||
|
||||
?>
|
||||
<div class="login-box">
|
||||
<div class="login-logo">
|
||||
<?php echo $hesk_settings['hesk_title']; ?>
|
||||
</div>
|
||||
<div class="login-box-container">
|
||||
<div class="login-box-background"></div>
|
||||
<div class="login-box-body">
|
||||
<div class="loginError">
|
||||
<?php
|
||||
@ -279,6 +278,14 @@ function print_login()
|
||||
hesk_handle_messages();
|
||||
?>
|
||||
</div>
|
||||
<div class="login-logo">
|
||||
<?php if ($modsForHesk_settings['login_box_header'] == 'image'): ?>
|
||||
<img src="<?php echo HESK_PATH . $hesk_settings['cache_dir'] . '/lbh_' . $modsForHesk_settings['login_box_header_image']; ?>"
|
||||
style="height: 75px">
|
||||
<?php else:
|
||||
echo $hesk_settings['hesk_title'];
|
||||
endif; ?>
|
||||
</div>
|
||||
<h4 class="login-box-msg">
|
||||
<?php echo $hesklang['staff_login_title']; ?>
|
||||
</h4>
|
||||
@ -462,6 +469,7 @@ function print_login()
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
hesk_cleanSessionVars('a_iserror');
|
||||
|
||||
|
@ -1,32 +1,15 @@
|
||||
<?php
|
||||
/*******************************************************************************
|
||||
* Title: Help Desk Software HESK
|
||||
* Version: 2.6.8 from 10th August 2016
|
||||
* Author: Klemen Stirn
|
||||
* Website: https://www.hesk.com
|
||||
********************************************************************************
|
||||
* COPYRIGHT AND TRADEMARK NOTICE
|
||||
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
|
||||
* HESK is a registered trademark of Klemen Stirn.
|
||||
* The HESK may be used and modified free of charge by anyone
|
||||
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
|
||||
* By using this code you agree to indemnify Klemen Stirn from any
|
||||
* liability that might arise from it's use.
|
||||
* Selling the code for this program, in part or full, without prior
|
||||
* written consent is expressly forbidden.
|
||||
* Using this code, in part or full, to create derivate work,
|
||||
* new scripts or products is expressly forbidden. Obtain permission
|
||||
* before redistributing this software over the Internet or in
|
||||
* any other medium. In all cases copyright and header must remain intact.
|
||||
* This Copyright is in full effect in any country that has International
|
||||
* Trade Agreements with the United States of America or
|
||||
* with the European Union.
|
||||
* Removing any of the copyright notices without purchasing a license
|
||||
* is expressly forbidden. To remove HESK copyright notice you must purchase
|
||||
* a license for this script. For more information on how to obtain
|
||||
* a license please visit the page below:
|
||||
* https://www.hesk.com/buy.php
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
define('IN_SCRIPT',1);
|
||||
define('HESK_PATH','../');
|
||||
|
@ -107,8 +107,7 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
<div class="box-body">
|
||||
<form action="manage_categories.php" method="post" role="form" class="form-horizontal" data-toggle="validator">
|
||||
<div class="form-group">
|
||||
<p class="col-sm-4 control-label" style="font-size: .87em">
|
||||
<b><?php echo $hesklang['cat_name']; ?></b> (<?php echo $hesklang['max_chars']; ?>)</p>
|
||||
<label for="name" class="col-sm-4 control-label"><?php echo $hesklang['cat_name']; ?></label>
|
||||
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control"
|
||||
@ -121,12 +120,12 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
?>
|
||||
data-error="<?php echo htmlspecialchars($hesklang['enter_cat_name']); ?>"
|
||||
required>
|
||||
<div class="help-block"><?php echo $hesklang['max_chars']; ?></div>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="priority" class="col-sm-4 control-label"
|
||||
style="font-size: .87em"><?php echo $hesklang['def_pri']; ?> <a href="#"
|
||||
<label for="priority" class="col-sm-4 control-label"><?php echo $hesklang['def_pri']; ?> <a href="#"
|
||||
onclick="alert('<?php echo hesk_makeJsString($hesklang['cat_pri']); ?>')"><i
|
||||
class="fa fa-question-circle settingsquestionmark"></i> </a> </label>
|
||||
|
||||
@ -149,15 +148,51 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-sm-4 control-label">
|
||||
<?php echo $hesklang['category_color']; ?>
|
||||
<?php echo $hesklang['category_background_color']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
title="<?php echo htmlspecialchars($hesklang['category_color']); ?>"
|
||||
data-content="<?php echo htmlspecialchars($hesklang['category_color_help']); ?>"></i>
|
||||
title="<?php echo htmlspecialchars($hesklang['category_background_color']); ?>"
|
||||
data-content="<?php echo htmlspecialchars($hesklang['category_background_color_help']); ?>"></i>
|
||||
</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control colorpicker-trigger"
|
||||
placeholder="<?php echo htmlspecialchars($hesklang['category_color']); ?>" type="text"
|
||||
name="color" maxlength="7">
|
||||
placeholder="<?php echo htmlspecialchars($hesklang['category_background_color']); ?>" type="text"
|
||||
name="background-color" maxlength="7" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-sm-4 control-label">
|
||||
<?php echo $hesklang['category_foreground_color']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
title="<?php echo htmlspecialchars($hesklang['category_foreground_color']); ?>"
|
||||
data-content="<?php echo htmlspecialchars($hesklang['category_foreground_color_help']); ?>"></i>
|
||||
</label>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control colorpicker-trigger"
|
||||
placeholder="<?php echo htmlspecialchars($hesklang['category_foreground_color']); ?>" type="text"
|
||||
name="foreground-color" maxlength="7">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="display-border" class="col-sm-4 control-label">
|
||||
<?php echo $hesklang['category_display_border']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
|
||||
title="<?php echo htmlspecialchars($hesklang['category_display_border']); ?>"
|
||||
data-content="<?php echo htmlspecialchars($hesklang['category_display_border_help']); ?>"></i>
|
||||
</label>
|
||||
<div class="col-sm-8 form-inline">
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="display-border" value="1">
|
||||
<?php echo $hesklang['yes']; ?>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="display-border" value="0" checked>
|
||||
<?php echo $hesklang['no']; ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@ -194,11 +229,13 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-9 col-sm-offset-4">
|
||||
<input type="hidden" name="a" value="new"/>
|
||||
<input type="hidden" name="token" value="<?php hesk_token_echo(); ?>"/>
|
||||
<input type="submit" value="<?php echo $hesklang['create_cat']; ?>" class="btn btn-default"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@ -277,12 +314,21 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
}
|
||||
|
||||
$tmp = $i ? 'White' : 'Blue';
|
||||
$style = '';
|
||||
if ($mycat['color'] == null) {
|
||||
$style .= 'color: black; border: solid 1px #000';
|
||||
} else {
|
||||
$style .= 'background: ' . $mycat['color'];
|
||||
$style = 'background: ' . $mycat['background_color'];
|
||||
$backgroundVolatile = 'background-volatile';
|
||||
if ($mycat['foreground_color'] != 'AUTO') {
|
||||
$style .= '; color: ' . $mycat['foreground_color'];
|
||||
$backgroundVolatile = '';
|
||||
|
||||
if ($mycat['display_border_outline']) {
|
||||
$style .= '; border: solid 1px ' . $mycat['foreground_color'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($mycat['foreground_color'] == 'AUTO') {
|
||||
$mycat['foreground_color'] = '';
|
||||
}
|
||||
|
||||
$i = $i ? 0 : 1;
|
||||
|
||||
/* Number of tickets and graph width */
|
||||
@ -319,16 +365,18 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
|
||||
echo '
|
||||
<tr data-category-id="' . $mycat['id'] . '" data-name="' . htmlspecialchars($mycat['name']) . '"
|
||||
data-color="'. htmlspecialchars($mycat['color']) . '" data-priority="' . $mycat['priority'] . '"
|
||||
data-foreground-color="' . htmlspecialchars($mycat['foreground_color']) . '"
|
||||
data-border="' . $mycat['display_border_outline'] . '"
|
||||
data-background-color="'. htmlspecialchars($mycat['background_color']) . '"
|
||||
data-priority="' . $mycat['priority'] . '"
|
||||
data-manager="' . $mycat['manager'] . '" data-usage="'. $mycat['usage'] .'">
|
||||
<td style="display: none">' . $mycat['id'] . '</td>
|
||||
<td><span class="label background-volatile category-label" style="'.$style.'">' . $mycat['name'] . '</span></td>
|
||||
<td><span class="label ' . $backgroundVolatile . ' category-label" style="'.$style.'">' . $mycat['name'] . '</span></td>
|
||||
<td width="1" style="white-space: nowrap;">' . $priorities[$mycat['priority']]['formatted'] . '</td>
|
||||
<td><a href="show_tickets.php?category=' . $mycat['id'] . '&s_all=1&s_my=1&s_ot=1&s_un=1" alt="' . $hesklang['list_tickets_cat'] . '" title="' . $hesklang['list_tickets_cat'] . '">' . $all . '</a></td>
|
||||
<td>
|
||||
<div class="progress" style="width: 160px; margin-bottom: 0" title="' . sprintf($hesklang['perat'], $width_all . '%') . '" data-toggle="tooltip">
|
||||
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: ' . $width_all . '%">
|
||||
<span class="sr-only">40% Complete (success)</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
@ -351,7 +399,7 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
';
|
||||
}
|
||||
}
|
||||
echo '<a href="javascript:;" class="category-modal-trigger" data-category-id="' . $mycat['id'] . '"><i class="fa fa-pencil icon-link orange" data-toggle="tooltip" title="Edit"></i></a>';
|
||||
echo '<a href="javascript:;" class="category-modal-trigger" data-category-id="' . $mycat['id'] . '"><i class="fa fa-pencil icon-link orange" data-toggle="tooltip" title="' . $hesklang['edit'] . '"></i></a>';
|
||||
echo $remove_code . '</td>
|
||||
</tr>
|
||||
';
|
||||
@ -370,34 +418,71 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="cursor: move">
|
||||
<button type="button" class="close cancel-callback" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="myModalLabel">Edit Category</h4>
|
||||
<h4 class="modal-title" id="myModalLabel"><?php echo $hesklang['edit_category']; ?></h4>
|
||||
</div>
|
||||
<form action="manage_categories.php" class="form-horizontal" data-toggle="validator" method="post">
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="name" class="col-sm-3 control-label"><?php echo $hesklang['name']; ?></label>
|
||||
<label for="name" class="col-sm-3 control-label"><?php echo $hesklang['cat_name']; ?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="name" class="form-control" placeholder="<?php echo $hesklang['name']; ?>"
|
||||
<input type="text" name="name" class="form-control" placeholder="<?php echo $hesklang['cat_name']; ?>"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="color" class="col-sm-3 control-label">
|
||||
<?php echo $hesklang['category_color']; ?>
|
||||
<label for="background-color" class="col-sm-3 control-label">
|
||||
<?php echo $hesklang['category_background_color']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
title="<?php echo htmlspecialchars($hesklang['category_color']); ?>"
|
||||
data-content="<?php echo htmlspecialchars($hesklang['category_color_help']); ?>"></i>
|
||||
title="<?php echo htmlspecialchars($hesklang['category_background_color']); ?>"
|
||||
data-content="<?php echo htmlspecialchars($hesklang['category_background_color_help']); ?>"></i>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="color" class="form-control category-colorpicker"
|
||||
placeholder="<?php echo $hesklang['category_color']; ?>">
|
||||
<input type="text" name="background-color" class="form-control category-colorpicker"
|
||||
placeholder="<?php echo $hesklang['category_background_color']; ?>"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="foreground-color" class="col-sm-3 control-label">
|
||||
<?php echo $hesklang['category_foreground_color']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
|
||||
title="<?php echo htmlspecialchars($hesklang['category_foreground_color']); ?>"
|
||||
data-content="<?php echo htmlspecialchars($hesklang['category_foreground_color_help']); ?>"></i>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" name="foreground-color" class="form-control category-colorpicker"
|
||||
placeholder="<?php echo $hesklang['category_foreground_color']; ?>">
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="display-border" class="col-sm-3 control-label">
|
||||
<?php echo $hesklang['category_display_border']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
|
||||
title="<?php echo htmlspecialchars($hesklang['category_display_border']); ?>"
|
||||
data-content="<?php echo htmlspecialchars($hesklang['category_display_border_help']); ?>"></i>
|
||||
</label>
|
||||
<div class="col-sm-9 form-inline">
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="display-border" value="1">
|
||||
<?php echo $hesklang['yes']; ?>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="display-border" value="0" checked>
|
||||
<?php echo $hesklang['no']; ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="priority" class="col-sm-3 control-label">
|
||||
<?php echo $hesklang['priority']; ?>
|
||||
@ -471,7 +556,8 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
var name = tempNameElement.value;
|
||||
|
||||
var id = $row.attr('data-category-id');
|
||||
var color = $row.attr('data-color');
|
||||
var backgroundColor = $row.attr('data-background-color');
|
||||
var foregroundColor = $row.attr('data-foreground-color');
|
||||
var priority = $row.attr('data-priority');
|
||||
var manager = $row.attr('data-manager');
|
||||
var usage = $row.attr('data-usage');
|
||||
@ -482,29 +568,32 @@ while ($mycat = hesk_dbFetchAssoc($res)) {
|
||||
.find('select[name="manager"]').val(manager).end()
|
||||
.find('input[name="id"]').val(id).end()
|
||||
.find('select[name="usage"]').val(usage).end()
|
||||
.find('input[name="color"]').val(color).end();
|
||||
.find('input[name="background-color"]').val(backgroundColor).end()
|
||||
.find('input[name="foreground-color"]').val(foregroundColor).end();
|
||||
|
||||
var colorpickerOptions = {
|
||||
format: 'hex',
|
||||
color: backgroundColor
|
||||
};
|
||||
$modal.find('input[name="background-color"]')
|
||||
.colorpicker(colorpickerOptions).end().modal('show');
|
||||
|
||||
var colorpickerOptions = null;
|
||||
if (color == '') {
|
||||
colorpickerOptions = {
|
||||
format: 'hex'
|
||||
};
|
||||
} else {
|
||||
colorpickerOptions = {
|
||||
format: 'hex',
|
||||
color: color
|
||||
};
|
||||
if (foregroundColor != '') {
|
||||
colorpickerOptions.color = foregroundColor;
|
||||
}
|
||||
$modal.find('input[name="color"]')
|
||||
.colorpicker(colorpickerOptions).end().modal('show');
|
||||
|
||||
if (color == '') {
|
||||
$modal.find('input[name="color"]').val('');
|
||||
}
|
||||
$modal.find('input[name="foreground-color"]')
|
||||
.colorpicker(colorpickerOptions).end().modal('show');
|
||||
});
|
||||
|
||||
$('.cancel-callback').click(function() {
|
||||
$('#edit-category-modal').find('input[name="color"]').val('').colorpicker('destroy').end();
|
||||
var $editCategoryModal = $('#edit-category-modal');
|
||||
|
||||
$editCategoryModal.find('input[name="background-color"]').val('').colorpicker('destroy').end();
|
||||
$editCategoryModal.find('input[name="foreground-color"]').val('').colorpicker('destroy').end();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@ -629,9 +718,13 @@ function new_cat()
|
||||
/* Category name */
|
||||
$catname = hesk_input(hesk_POST('name'), $hesklang['enter_cat_name'], 'manage_categories.php');
|
||||
|
||||
$color = hesk_POST('color', null);
|
||||
$color = str_replace('#', '', $color);
|
||||
$color = $color != null ? "'#" . hesk_dbEscape($color) . "'" : 'NULL';
|
||||
$background_color = hesk_POST('background-color', '#ffffff');
|
||||
$foreground_color = hesk_POST('foreground-color', '#000000');
|
||||
$display_border = hesk_POST('display-border', 0);
|
||||
if ($foreground_color == '') {
|
||||
$foreground_color = 'AUTO';
|
||||
$display_border = 0;
|
||||
}
|
||||
|
||||
$usage = hesk_POST('usage', 0);
|
||||
|
||||
@ -647,7 +740,11 @@ function new_cat()
|
||||
$row = hesk_dbFetchRow($res);
|
||||
$my_order = $row[0] + 10;
|
||||
|
||||
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` (`name`,`cat_order`,`autoassign`,`type`, `priority`, `color`, `usage`) VALUES ('" . hesk_dbEscape($catname) . "','" . intval($my_order) . "','" . intval($_SESSION['cat_autoassign']) . "','" . intval($_SESSION['cat_type']) . "','{$_SESSION['cat_priority']}', {$color}, " . intval($usage) . ")");
|
||||
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories`
|
||||
(`name`,`cat_order`,`autoassign`,`type`, `priority`, `background_color`, `foreground_color`, `display_border_outline`, `usage`) VALUES
|
||||
('" . hesk_dbEscape($catname) . "','" . intval($my_order) . "','" . intval($_SESSION['cat_autoassign']) . "',
|
||||
'" . intval($_SESSION['cat_type']) . "','{$_SESSION['cat_priority']}', '" . hesk_dbEscape($background_color) . "',
|
||||
'" . hesk_dbEscape($foreground_color) . "', '" . intval($display_border) . "', " . intval($usage) . ")");
|
||||
|
||||
hesk_cleanSessionVars('catname');
|
||||
hesk_cleanSessionVars('cat_autoassign');
|
||||
@ -676,9 +773,13 @@ function update_category()
|
||||
$catname = hesk_input(hesk_POST('name'), $hesklang['cat_ren_name'], $_SERVER['PHP_SELF']);
|
||||
$_SESSION['catname2'] = $catname;
|
||||
|
||||
$color = hesk_POST('color', null);
|
||||
$color = str_replace('#', '', $color);
|
||||
$color = $color != null ? "'#" . hesk_dbEscape($color) . "'" : 'NULL';
|
||||
$background_color = hesk_POST('background-color', '#ffffff');
|
||||
$foreground_color = hesk_POST('foreground-color', '#000000');
|
||||
$display_border = hesk_POST('display-border', 0);
|
||||
if ($foreground_color == '') {
|
||||
$foreground_color = 'AUTO';
|
||||
$display_border = 0;
|
||||
}
|
||||
$manager = hesk_POST('manager', 0);
|
||||
$priority = hesk_POST('priority', 0);
|
||||
$usage = hesk_POST('usage', 0);
|
||||
@ -687,7 +788,9 @@ function update_category()
|
||||
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` SET `name`='" . hesk_dbEscape($catname) . "',
|
||||
`priority` = '" . hesk_dbEscape($priority) . "',
|
||||
`manager` = " . intval($manager) . ",
|
||||
`color` = " . $color . ",
|
||||
`background_color` = '" . hesk_dbEscape($background_color) . "',
|
||||
`foreground_color` = '" . hesk_dbEscape($foreground_color) . "',
|
||||
`display_border_outline` = '" . intval($display_border) . "',
|
||||
`usage` = " . intval($usage) . "
|
||||
WHERE `id`='" . intval($catid) . "'");
|
||||
|
||||
@ -847,6 +950,8 @@ function get_manager($user_id, $user_array) {
|
||||
return $user['name'];
|
||||
}
|
||||
}
|
||||
|
||||
return 'Error!';
|
||||
}
|
||||
|
||||
?>
|
||||
|
275
admin/manage_custom_nav_elements.php
Normal file
275
admin/manage_custom_nav_elements.php
Normal file
@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
define('IN_SCRIPT', 1);
|
||||
define('HESK_PATH', '../');
|
||||
define('PAGE_TITLE', 'ADMIN_CUSTOM_NAV_ELEMENTS');
|
||||
define('MFH_PAGE_LAYOUT', 'TOP_ONLY');
|
||||
define('EXTRA_JS', '<script src="'.HESK_PATH.'internal-api/js/manage-custom-nav-elements.js"></script>');
|
||||
|
||||
/* Get all the required files and functions */
|
||||
require(HESK_PATH . 'hesk_settings.inc.php');
|
||||
require(HESK_PATH . 'inc/common.inc.php');
|
||||
require(HESK_PATH . 'inc/admin_functions.inc.php');
|
||||
require(HESK_PATH . 'inc/mail_functions.inc.php');
|
||||
hesk_load_database_functions();
|
||||
|
||||
hesk_session_start();
|
||||
hesk_dbConnect();
|
||||
hesk_isLoggedIn();
|
||||
|
||||
//hesk_checkPermission('can_man_custom_nav');
|
||||
|
||||
/* Print header */
|
||||
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
|
||||
|
||||
/* Print main manage users page */
|
||||
require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
?>
|
||||
<div class="content-wrapper">
|
||||
<section class="content">
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h1 class="box-title">
|
||||
<?php echo $hesklang['custom_nav_menu_elements']; ?>
|
||||
</h1>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse">
|
||||
<i class="fa fa-minus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-right">
|
||||
<button id="create-button" class="btn btn-success">
|
||||
<i class="fa fa-plus-circle"></i>
|
||||
<?php echo $hesklang['create_new']; ?>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo $hesklang['id']; ?></th>
|
||||
<th><?php echo $hesklang['custom_nav_text']; ?></th>
|
||||
<th><?php echo $hesklang['custom_nav_subtext']; ?></th>
|
||||
<th><?php echo $hesklang['image_url_slash_font_icon']; ?></th>
|
||||
<th><?php echo $hesklang['url']; ?></th>
|
||||
<th><?php echo $hesklang['actions']; ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="table-body">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay" id="overlay">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="modal fade" id="nav-element-modal" tabindex="-1" role="dialog" style="overflow: hidden">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header" style="cursor: move">
|
||||
<button type="button" class="close cancel-callback" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="edit-label">
|
||||
<?php echo $hesklang['edit_custom_nav_element_title_case']; ?>
|
||||
</h4>
|
||||
<h4 class="modal-title" id="create-label">
|
||||
<?php echo $hesklang['create_custom_nav_element_title_case']; ?>
|
||||
</h4>
|
||||
</div>
|
||||
<form id="manage-nav-element" class="form-horizontal" data-toggle="validator">
|
||||
<input type="hidden" name="id">
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="form-group">
|
||||
<label for="place" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $hesklang['place']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
|
||||
title="<?php echo $hesklang['place']; ?>"
|
||||
data-content="<?php echo $hesklang['place_help']; ?>"></i>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<select name="place" id="place" class="form-control"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<option value="1"><?php echo $hesklang['homepage_block']; ?></option>
|
||||
<option value="2"><?php echo $hesklang['customer_navigation']; ?></option>
|
||||
<option value="3"><?php echo $hesklang['staff_navigation']; ?></option>
|
||||
</select>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<h4><?php echo $hesklang['custom_nav_text']; ?></h4>
|
||||
<?php foreach ($hesk_settings['languages'] as $language => $value): ?>
|
||||
<div class="form-group">
|
||||
<label for="text[<?php echo $language; ?>]" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $language; ?>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<input type="text" name="text" class="form-control"
|
||||
data-text-language="<?php echo $language; ?>"
|
||||
id="text[<?php echo $language; ?>" placeholder="<?php echo $hesklang['custom_nav_text']; ?>"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<div id="subtext">
|
||||
<h4><?php echo $hesklang['custom_nav_subtext']; ?></h4>
|
||||
<?php foreach ($hesk_settings['languages'] as $language => $value): ?>
|
||||
<div class="form-group">
|
||||
<label for="subtext[<?php echo $language; ?>]" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $language; ?>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<input type="text" name="subtext" class="form-control"
|
||||
data-subtext-language="<?php echo $language; ?>"
|
||||
id="subtext[<?php echo $language; ?>" placeholder="<?php echo $hesklang['custom_nav_subtext']; ?>"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<h4><?php echo $hesklang['url']; ?></h4>
|
||||
<div class="form-group">
|
||||
<label for="image-type" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $hesklang['url']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
|
||||
title="<?php echo $hesklang['url']; ?>"
|
||||
data-content="<?php echo $hesklang['url_help']; ?>"></i>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<input type="text" name="url" class="form-control"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
placeholder="<?php echo $hesklang['url']; ?>" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<h4><?php echo $hesklang['image']; ?></h4>
|
||||
<div class="form-group">
|
||||
<label for="image-type" class="col-md-4 col-sm-12 control-label"><?php echo $hesklang['image_type']; ?></label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<select name="image-type" id="image-type" class="form-control"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
required>
|
||||
<option value="image-url"><?php echo $hesklang['image_url']; ?></option>
|
||||
<option value="font-icon"><?php echo $hesklang['font_icon']; ?></option>
|
||||
</select>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="image-url-group">
|
||||
<label for="image-url" class="col-md-4 col-sm-12 control-label">
|
||||
<?php echo $hesklang['image_url']; ?>
|
||||
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
|
||||
title="<?php echo $hesklang['image_url']; ?>"
|
||||
data-content="<?php echo $hesklang['image_url_help']; ?>"></i>
|
||||
</label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<input type="text" name="image-url" class="form-control"
|
||||
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
|
||||
placeholder="<?php echo $hesklang['image_url']; ?>" required>
|
||||
<div class="help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" id="font-icon-group">
|
||||
<p style="display:none" id="no-icon"><?php echo $hesklang['sm_no_icon']; ?></p>
|
||||
|
||||
<p style="display:none" id="search-icon"><?php echo $hesklang['sm_search_icon']; ?></p>
|
||||
|
||||
<p style="display:none"
|
||||
id="footer-icon"><?php echo $hesklang['sm_iconpicker_footer_label']; ?></p>
|
||||
<label for="font-icon" class="col-md-4 col-sm-12 control-label"><?php echo $hesklang['font_icon']; ?></label>
|
||||
<div class="col-md-8 col-sm-12">
|
||||
<div class="btn btn-default iconpicker-container" data-toggle="nav-iconpicker">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="btn-group" id="action-buttons">
|
||||
<button type="button" class="btn btn-default cancel-button" data-dismiss="modal">
|
||||
<i class="fa fa-times-circle"></i>
|
||||
<span><?php echo $hesklang['cancel']; ?></span>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-success save-button">
|
||||
<i class="fa fa-check-circle"></i>
|
||||
<span><?php echo $hesklang['save']; ?></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
echo mfh_get_hidden_fields_for_language(
|
||||
array(
|
||||
'edit',
|
||||
'delete',
|
||||
'no_custom_nav_elements_found',
|
||||
'failed_to_load_custom_nav_elements',
|
||||
'custom_nav_element_deleted',
|
||||
'error_deleting_custom_nav_element',
|
||||
'error_sorting_custom_nav_elements',
|
||||
'custom_nav_element_created',
|
||||
'custom_nav_element_saved',
|
||||
'homepage_block',
|
||||
'customer_navigation',
|
||||
'staff_navigation',
|
||||
'error_saving_custom_nav_element',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<script type="text/html" id="nav-element-template">
|
||||
<tr>
|
||||
<td><span data-property="id" data-value="x"></span></td>
|
||||
<td><span>
|
||||
<ul data-property="text" class="list-unstyled"></ul>
|
||||
</span></td>
|
||||
<td><span>
|
||||
<ul data-property="subtext" class="list-unstyled"></ul>
|
||||
</span></td>
|
||||
<td><span data-property="image-or-font"></span></td>
|
||||
<td><span data-property="url"></span></td>
|
||||
<td>
|
||||
<a href="#" data-action="sort"
|
||||
data-direction="up">
|
||||
<i class="fa fa-fw fa-arrow-up icon-link green"
|
||||
data-toggle="tooltip" title="<?php echo $hesklang['move_up']; ?>"></i>
|
||||
</a>
|
||||
<a href="#" data-action="sort"
|
||||
data-direction="down">
|
||||
<i class="fa fa-fw fa-arrow-down icon-link green"
|
||||
data-toggle="tooltip" title="<?php echo $hesklang['move_dn'] ?>"></i>
|
||||
</a>
|
||||
<a href="#" data-action="edit">
|
||||
<i class="fa fa-fw fa-pencil icon-link orange"
|
||||
data-toggle="tooltip" title="<?php echo $hesklang['edit']; ?>"></i>
|
||||
</a>
|
||||
<a href="#" data-action="delete">
|
||||
<i class="fa fa-fw fa-times icon-link red"
|
||||
data-toggle="tooltip" title="<?php echo $hesklang['delete']; ?>"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
<?php
|
||||
require_once(HESK_PATH . 'inc/footer.inc.php');
|
@ -10,6 +10,7 @@ require(HESK_PATH . 'hesk_settings.inc.php');
|
||||
require(HESK_PATH . 'inc/common.inc.php');
|
||||
require(HESK_PATH . 'inc/admin_functions.inc.php');
|
||||
require(HESK_PATH . 'inc/mail_functions.inc.php');
|
||||
require(HESK_PATH . 'inc/custom_fields.inc.php');
|
||||
hesk_load_database_functions();
|
||||
|
||||
hesk_session_start();
|
||||
|
@ -1,32 +1,15 @@
|
||||
<?php
|
||||
/*******************************************************************************
|
||||
* Title: Help Desk Software HESK
|
||||
* Version: 2.6.8 from 10th August 2016
|
||||
* Author: Klemen Stirn
|
||||
* Website: https://www.hesk.com
|
||||
********************************************************************************
|
||||
* COPYRIGHT AND TRADEMARK NOTICE
|
||||
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
|
||||
* HESK is a registered trademark of Klemen Stirn.
|
||||
* The HESK may be used and modified free of charge by anyone
|
||||
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
|
||||
* By using this code you agree to indemnify Klemen Stirn from any
|
||||
* liability that might arise from it's use.
|
||||
* Selling the code for this program, in part or full, without prior
|
||||
* written consent is expressly forbidden.
|
||||
* Using this code, in part or full, to create derivate work,
|
||||
* new scripts or products is expressly forbidden. Obtain permission
|
||||
* before redistributing this software over the Internet or in
|
||||
* any other medium. In all cases copyright and header must remain intact.
|
||||
* This Copyright is in full effect in any country that has International
|
||||
* Trade Agreements with the United States of America or
|
||||
* with the European Union.
|
||||
* Removing any of the copyright notices without purchasing a license
|
||||
* is expressly forbidden. To remove HESK copyright notice you must purchase
|
||||
* a license for this script. For more information on how to obtain
|
||||
* a license please visit the page below:
|
||||
* https://www.hesk.com/buy.php
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
define('IN_SCRIPT',1);
|
||||
define('HESK_PATH','../');
|
||||
@ -476,7 +459,7 @@ if (!isset($_SESSION['hide']['new_article']))
|
||||
<?php build_dropzone_markup(true); ?>
|
||||
</div>
|
||||
<?php
|
||||
display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/admin/knowledgebase/upload-attachment.php');
|
||||
display_dropzone_field(HESK_PATH . 'internal-api/admin/knowledgebase/upload-attachment.php');
|
||||
endif; // End attachments
|
||||
|
||||
?>
|
||||
@ -1534,7 +1517,7 @@ function edit_article()
|
||||
|
||||
<?php
|
||||
build_dropzone_markup(true);
|
||||
display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/admin/knowledgebase/upload-attachment.php');
|
||||
display_dropzone_field(HESK_PATH . 'internal-api/admin/knowledgebase/upload-attachment.php');
|
||||
?>
|
||||
</div>
|
||||
<?php endif; //End attachments ?>
|
||||
|
@ -132,7 +132,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo $hesklang['name']; ?></th>
|
||||
<th><?php echo $hesklang['status_name_title']; ?></th>
|
||||
<th><?php echo $hesklang['closable_question']; ?></th>
|
||||
<th><?php echo $hesklang['closedQuestionMark']; ?></th>
|
||||
<th><?php echo $hesklang['actions']; ?></th>
|
||||
|
@ -1,32 +1,15 @@
|
||||
<?php
|
||||
/*******************************************************************************
|
||||
* Title: Help Desk Software HESK
|
||||
* Version: 2.6.1 from 26th February 2015
|
||||
* Author: Klemen Stirn
|
||||
* Website: https://www.hesk.com
|
||||
********************************************************************************
|
||||
* COPYRIGHT AND TRADEMARK NOTICE
|
||||
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
|
||||
* HESK is a registered trademark of Klemen Stirn.
|
||||
* The HESK may be used and modified free of charge by anyone
|
||||
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
|
||||
* By using this code you agree to indemnify Klemen Stirn from any
|
||||
* liability that might arise from it's use.
|
||||
* Selling the code for this program, in part or full, without prior
|
||||
* written consent is expressly forbidden.
|
||||
* Using this code, in part or full, to create derivate work,
|
||||
* new scripts or products is expressly forbidden. Obtain permission
|
||||
* before redistributing this software over the Internet or in
|
||||
* any other medium. In all cases copyright and header must remain intact.
|
||||
* This Copyright is in full effect in any country that has International
|
||||
* Trade Agreements with the United States of America or
|
||||
* with the European Union.
|
||||
* Removing any of the copyright notices without purchasing a license
|
||||
* is expressly forbidden. To remove HESK copyright notice you must purchase
|
||||
* a license for this script. For more information on how to obtain
|
||||
* a license please visit the page below:
|
||||
* https://www.hesk.com/buy.php
|
||||
*******************************************************************************/
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
define('IN_SCRIPT', 1);
|
||||
define('HESK_PATH', '../');
|
||||
|
@ -879,7 +879,7 @@ $show_quick_help = $show['show'];
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/ticket/upload-attachment.php');
|
||||
display_dropzone_field(HESK_PATH . 'internal-api/ticket/upload-attachment.php');
|
||||
}
|
||||
|
||||
if (!isset($_SESSION['as_notify'])) {
|
||||
|
@ -97,6 +97,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
|
||||
<th><?php echo $hesklang['user']; ?></th>
|
||||
<th><?php echo $hesklang['custom_place']; ?></th>
|
||||
<th><?php echo $hesklang['message']; ?></th>
|
||||
<th><?php echo $hesklang['stack_trace_header']; ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
|
142
api/ApplicationContext.php
Normal file
142
api/ApplicationContext.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
// Responsible for loading in all necessary classes. AKA a poor man's DI solution.
|
||||
use BusinessLogic\Attachments\AttachmentHandler;
|
||||
use BusinessLogic\Attachments\AttachmentRetriever;
|
||||
use BusinessLogic\Categories\CategoryRetriever;
|
||||
use BusinessLogic\Emails\BasicEmailSender;
|
||||
use BusinessLogic\Emails\EmailSenderHelper;
|
||||
use BusinessLogic\Emails\EmailTemplateParser;
|
||||
use BusinessLogic\Emails\EmailTemplateRetriever;
|
||||
use BusinessLogic\Emails\MailgunEmailSender;
|
||||
use BusinessLogic\Navigation\CustomNavElementHandler;
|
||||
use BusinessLogic\Security\BanRetriever;
|
||||
use BusinessLogic\Security\UserContextBuilder;
|
||||
use BusinessLogic\Security\UserToTicketChecker;
|
||||
use BusinessLogic\Settings\ApiChecker;
|
||||
use BusinessLogic\Settings\SettingsRetriever;
|
||||
use BusinessLogic\Statuses\StatusRetriever;
|
||||
use BusinessLogic\Tickets\Autoassigner;
|
||||
use BusinessLogic\Tickets\TicketDeleter;
|
||||
use BusinessLogic\Tickets\TicketEditor;
|
||||
use BusinessLogic\Tickets\TicketRetriever;
|
||||
use BusinessLogic\Tickets\TicketCreator;
|
||||
use BusinessLogic\Tickets\NewTicketValidator;
|
||||
use BusinessLogic\Tickets\TicketValidators;
|
||||
use BusinessLogic\Tickets\TrackingIdGenerator;
|
||||
use BusinessLogic\Tickets\VerifiedEmailChecker;
|
||||
use DataAccess\Attachments\AttachmentGateway;
|
||||
use DataAccess\Categories\CategoryGateway;
|
||||
use DataAccess\Files\FileDeleter;
|
||||
use DataAccess\Files\FileReader;
|
||||
use DataAccess\Files\FileWriter;
|
||||
use DataAccess\Logging\LoggingGateway;
|
||||
use DataAccess\Navigation\CustomNavElementGateway;
|
||||
use DataAccess\Security\BanGateway;
|
||||
use DataAccess\Security\UserGateway;
|
||||
use DataAccess\Settings\ModsForHeskSettingsGateway;
|
||||
use DataAccess\Statuses\StatusGateway;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
use DataAccess\Tickets\VerifiedEmailGateway;
|
||||
|
||||
|
||||
class ApplicationContext {
|
||||
public $get;
|
||||
|
||||
/**
|
||||
* ApplicationContext constructor.
|
||||
*/
|
||||
function __construct() {
|
||||
$this->get = array();
|
||||
|
||||
// Settings
|
||||
$this->get[ModsForHeskSettingsGateway::class] = new ModsForHeskSettingsGateway();
|
||||
|
||||
// API Checker
|
||||
$this->get[ApiChecker::class] = new ApiChecker($this->get[ModsForHeskSettingsGateway::class]);
|
||||
|
||||
// Custom Navigation
|
||||
$this->get[CustomNavElementGateway::class] = new CustomNavElementGateway();
|
||||
$this->get[CustomNavElementHandler::class] = new CustomNavElementHandler($this->get[CustomNavElementGateway::class]);
|
||||
|
||||
// Logging
|
||||
$this->get[LoggingGateway::class] = new LoggingGateway();
|
||||
|
||||
// Verified Email Checker
|
||||
$this->get[VerifiedEmailGateway::class] = new VerifiedEmailGateway();
|
||||
$this->get[VerifiedEmailChecker::class] = new VerifiedEmailChecker($this->get[VerifiedEmailGateway::class]);
|
||||
|
||||
// Users
|
||||
$this->get[UserGateway::class] = new UserGateway();
|
||||
$this->get[UserContextBuilder::class] = new UserContextBuilder($this->get[UserGateway::class]);
|
||||
|
||||
// Categories
|
||||
$this->get[CategoryGateway::class] = new CategoryGateway();
|
||||
$this->get[CategoryRetriever::class] = new CategoryRetriever($this->get[CategoryGateway::class]);
|
||||
|
||||
// Bans
|
||||
$this->get[BanGateway::class] = new BanGateway();
|
||||
$this->get[BanRetriever::class] = new BanRetriever($this->get[BanGateway::class]);
|
||||
|
||||
// Statuses
|
||||
$this->get[StatusGateway::class] = new StatusGateway();
|
||||
|
||||
// Email Sender
|
||||
$this->get[EmailTemplateRetriever::class] = new EmailTemplateRetriever();
|
||||
$this->get[EmailTemplateParser::class] = new EmailTemplateParser($this->get[StatusGateway::class],
|
||||
$this->get[CategoryGateway::class],
|
||||
$this->get[UserGateway::class],
|
||||
$this->get[EmailTemplateRetriever::class]);
|
||||
$this->get[BasicEmailSender::class] = new BasicEmailSender();
|
||||
$this->get[MailgunEmailSender::class] = new MailgunEmailSender();
|
||||
$this->get[EmailSenderHelper::class] = new EmailSenderHelper($this->get[EmailTemplateParser::class],
|
||||
$this->get[BasicEmailSender::class],
|
||||
$this->get[MailgunEmailSender::class]);
|
||||
|
||||
// Tickets
|
||||
$this->get[UserToTicketChecker::class] = new UserToTicketChecker($this->get[UserGateway::class]);
|
||||
$this->get[TicketGateway::class] = new TicketGateway();
|
||||
$this->get[TicketRetriever::class] = new TicketRetriever($this->get[TicketGateway::class],
|
||||
$this->get[UserToTicketChecker::class]);
|
||||
$this->get[TicketValidators::class] = new TicketValidators($this->get[TicketGateway::class]);
|
||||
$this->get[TrackingIdGenerator::class] = new TrackingIdGenerator($this->get[TicketGateway::class]);
|
||||
$this->get[Autoassigner::class] = new Autoassigner($this->get[CategoryGateway::class], $this->get[UserGateway::class]);
|
||||
$this->get[NewTicketValidator::class] = new NewTicketValidator($this->get[CategoryRetriever::class],
|
||||
$this->get[BanRetriever::class],
|
||||
$this->get[TicketValidators::class]);
|
||||
$this->get[TicketCreator::class] = new TicketCreator($this->get[NewTicketValidator::class],
|
||||
$this->get[TrackingIdGenerator::class],
|
||||
$this->get[Autoassigner::class],
|
||||
$this->get[StatusGateway::class],
|
||||
$this->get[TicketGateway::class],
|
||||
$this->get[VerifiedEmailChecker::class],
|
||||
$this->get[EmailSenderHelper::class],
|
||||
$this->get[UserGateway::class],
|
||||
$this->get[ModsForHeskSettingsGateway::class]);
|
||||
$this->get[FileWriter::class] = new FileWriter();
|
||||
$this->get[FileReader::class] = new FileReader();
|
||||
$this->get[FileDeleter::class] = new FileDeleter();
|
||||
$this->get[AttachmentGateway::class] = new AttachmentGateway();
|
||||
$this->get[AttachmentHandler::class] = new AttachmentHandler($this->get[TicketGateway::class],
|
||||
$this->get[AttachmentGateway::class],
|
||||
$this->get[FileWriter::class],
|
||||
$this->get[UserToTicketChecker::class],
|
||||
$this->get[FileDeleter::class]);
|
||||
$this->get[AttachmentRetriever::class] = new AttachmentRetriever($this->get[AttachmentGateway::class],
|
||||
$this->get[FileReader::class],
|
||||
$this->get[TicketGateway::class],
|
||||
$this->get[UserToTicketChecker::class]);
|
||||
$this->get[TicketDeleter::class] =
|
||||
new TicketDeleter($this->get[TicketGateway::class],
|
||||
$this->get[UserToTicketChecker::class],
|
||||
$this->get[AttachmentHandler::class]);
|
||||
$this->get[TicketEditor::class] =
|
||||
new TicketEditor($this->get[TicketGateway::class], $this->get[UserToTicketChecker::class]);
|
||||
|
||||
// Statuses
|
||||
$this->get[StatusRetriever::class] = new StatusRetriever($this->get[StatusGateway::class]);
|
||||
|
||||
// Settings
|
||||
$this->get[SettingsRetriever::class] = new SettingsRetriever($this->get[ModsForHeskSettingsGateway::class]);
|
||||
}
|
||||
}
|
21
api/BusinessLogic/Attachments/Attachment.php
Normal file
21
api/BusinessLogic/Attachments/Attachment.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class Attachment {
|
||||
/* @var $id int */
|
||||
public $id;
|
||||
|
||||
/* @var $savedName string */
|
||||
public $savedName;
|
||||
|
||||
/* @var $displayName string */
|
||||
public $displayName;
|
||||
|
||||
/* @var $id int */
|
||||
public $fileSize;
|
||||
|
||||
/* @var $downloadCount int */
|
||||
public $downloadCount;
|
||||
}
|
475
api/BusinessLogic/Attachments/AttachmentHandler.php
Normal file
475
api/BusinessLogic/Attachments/AttachmentHandler.php
Normal file
@ -0,0 +1,475 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\AccessViolationException;
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Exceptions\ValidationException;
|
||||
use BusinessLogic\Security\UserContext;
|
||||
use BusinessLogic\Security\UserPrivilege;
|
||||
use BusinessLogic\Security\UserToTicketChecker;
|
||||
use BusinessLogic\Tickets\Attachment;
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use BusinessLogic\ValidationModel;
|
||||
use DataAccess\Attachments\AttachmentGateway;
|
||||
use DataAccess\Files\FileDeleter;
|
||||
use DataAccess\Files\FileWriter;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class AttachmentHandler {
|
||||
/* @var $ticketGateway TicketGateway */
|
||||
private $ticketGateway;
|
||||
|
||||
/* @var $attachmentGateway AttachmentGateway */
|
||||
private $attachmentGateway;
|
||||
|
||||
/* @var $fileWriter FileWriter */
|
||||
private $fileWriter;
|
||||
|
||||
/* @var $fileDeleter FileDeleter */
|
||||
private $fileDeleter;
|
||||
|
||||
/* @var $userToTicketChecker UserToTicketChecker */
|
||||
private $userToTicketChecker;
|
||||
|
||||
function __construct($ticketGateway, $attachmentGateway, $fileWriter, $userToTicketChecker, $fileDeleter) {
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
$this->attachmentGateway = $attachmentGateway;
|
||||
$this->fileWriter = $fileWriter;
|
||||
$this->userToTicketChecker = $userToTicketChecker;
|
||||
$this->fileDeleter = $fileDeleter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $createAttachmentModel CreateAttachmentForTicketModel
|
||||
* @param $userContext UserContext
|
||||
* @param $heskSettings array
|
||||
* @return TicketAttachment the newly created attachment
|
||||
* @throws \Exception
|
||||
*/
|
||||
function createAttachmentForTicket($createAttachmentModel, $userContext, $heskSettings) {
|
||||
$this->validate($createAttachmentModel, $heskSettings);
|
||||
|
||||
$decodedAttachment = base64_decode($createAttachmentModel->attachmentContents);
|
||||
|
||||
$ticket = $this->ticketGateway->getTicketById($createAttachmentModel->ticketId, $heskSettings);
|
||||
|
||||
if ($ticket === null) {
|
||||
throw new ApiFriendlyException("Ticket {$createAttachmentModel->ticketId} not found", "Ticket Not Found", 404);
|
||||
}
|
||||
|
||||
$extraPermissions = $createAttachmentModel->isEditing
|
||||
? array(UserPrivilege::CAN_EDIT_TICKETS)
|
||||
: array();
|
||||
|
||||
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings, $extraPermissions)) {
|
||||
throw new AccessViolationException("User does not have access to ticket {$ticket->id} being created / edited!");
|
||||
}
|
||||
|
||||
$cleanedFileName = $this->cleanFileName($createAttachmentModel->displayName);
|
||||
$fileParts = pathinfo($cleanedFileName);
|
||||
|
||||
$ticketAttachment = new TicketAttachment();
|
||||
$ticketAttachment->savedName = $this->generateSavedName($ticket->trackingId,
|
||||
$cleanedFileName, $fileParts['extension']);
|
||||
$ticketAttachment->displayName = $cleanedFileName;
|
||||
$ticketAttachment->ticketTrackingId = $ticket->trackingId;
|
||||
$ticketAttachment->type = 0;
|
||||
$ticketAttachment->downloadCount = 0;
|
||||
|
||||
$ticketAttachment->fileSize =
|
||||
$this->fileWriter->writeToFile($ticketAttachment->savedName, $heskSettings['attach_dir'], $decodedAttachment);
|
||||
|
||||
$attachmentId = $this->attachmentGateway->createAttachmentForTicket($ticketAttachment, $heskSettings);
|
||||
|
||||
$this->updateAttachmentsOnTicket($ticket, $ticketAttachment, $attachmentId, $heskSettings);
|
||||
|
||||
$ticketAttachment->id = $attachmentId;
|
||||
|
||||
return $ticketAttachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports deleting attachments from both ticket messages AND replies
|
||||
*
|
||||
* @param $ticketId int The ticket ID
|
||||
* @param $attachmentId int The attachment ID
|
||||
* @param $userContext UserContext
|
||||
* @param $heskSettings array
|
||||
* @throws ApiFriendlyException
|
||||
* @throws \Exception
|
||||
*/
|
||||
function deleteAttachmentFromTicket($ticketId, $attachmentId, $userContext, $heskSettings) {
|
||||
$ticket = $this->ticketGateway->getTicketById($ticketId, $heskSettings);
|
||||
|
||||
if ($ticket === null) {
|
||||
throw new ApiFriendlyException("Ticket {$ticketId} not found!", "Ticket Not Found", 404);
|
||||
}
|
||||
|
||||
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings, array(UserPrivilege::CAN_EDIT_TICKETS))) {
|
||||
throw new AccessViolationException("User does not have access to ticket {$ticketId} being created / edited!");
|
||||
}
|
||||
|
||||
$indexToRemove = -1;
|
||||
$attachmentType = AttachmentType::MESSAGE;
|
||||
$replyId = -1;
|
||||
for ($i = 0; $i < count($ticket->attachments); $i++) {
|
||||
$attachment = $ticket->attachments[$i];
|
||||
if ($attachment->id === $attachmentId) {
|
||||
$indexToRemove = $i;
|
||||
$this->fileDeleter->deleteFile($attachment->savedName, $heskSettings['attach_dir']);
|
||||
$this->attachmentGateway->deleteAttachment($attachment->id, $heskSettings);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($ticket->replies as $reply) {
|
||||
for ($i = 0; $i < count($reply->attachments); $i++) {
|
||||
$attachment = $reply->attachments[$i];
|
||||
if ($attachment->id === $attachmentId) {
|
||||
$indexToRemove = $i;
|
||||
$replyId = $reply->id;
|
||||
$attachmentType = AttachmentType::REPLY;
|
||||
$this->fileDeleter->deleteFile($attachment->savedName, $heskSettings['attach_dir']);
|
||||
$this->attachmentGateway->deleteAttachment($attachment->id, $heskSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($indexToRemove === -1) {
|
||||
throw new ApiFriendlyException("Attachment not found for ticket or reply! ID: {$attachmentId}", "Attachment not found", 404);
|
||||
}
|
||||
|
||||
if ($attachmentType == AttachmentType::MESSAGE) {
|
||||
$attachments = $ticket->attachments;
|
||||
unset($attachments[$indexToRemove]);
|
||||
$this->ticketGateway->updateAttachmentsForTicket($ticketId, $attachments, $heskSettings);
|
||||
} else {
|
||||
$attachments = $ticket->replies[$replyId]->attachments;
|
||||
unset($attachments[$indexToRemove]);
|
||||
$this->ticketGateway->updateAttachmentsForReply($replyId, $attachments, $heskSettings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $createAttachmentModel CreateAttachmentForTicketModel
|
||||
* @param $heskSettings array
|
||||
* @throws ValidationException
|
||||
*/
|
||||
private function validate($createAttachmentModel, $heskSettings) {
|
||||
$errorKeys = array();
|
||||
if ($createAttachmentModel->attachmentContents === null ||
|
||||
trim($createAttachmentModel->attachmentContents) === '') {
|
||||
$errorKeys[] = 'CONTENTS_EMPTY';
|
||||
}
|
||||
|
||||
if (base64_decode($createAttachmentModel->attachmentContents, true) === false) {
|
||||
$errorKeys[] = 'CONTENTS_NOT_BASE_64';
|
||||
}
|
||||
|
||||
if ($createAttachmentModel->displayName === null ||
|
||||
trim($createAttachmentModel->displayName === '')) {
|
||||
$errorKeys[] = 'DISPLAY_NAME_EMPTY';
|
||||
}
|
||||
|
||||
if ($createAttachmentModel->ticketId === null ||
|
||||
$createAttachmentModel->ticketId < 1) {
|
||||
$errorKeys[] = 'TICKET_ID_MISSING';
|
||||
}
|
||||
|
||||
$fileParts = pathinfo($createAttachmentModel->displayName);
|
||||
if (!isset($fileParts['extension']) || !in_array(".{$fileParts['extension']}", $heskSettings['attachments']['allowed_types'])) {
|
||||
$errorKeys[] = 'EXTENSION_NOT_PERMITTED';
|
||||
}
|
||||
|
||||
$fileContents = base64_decode($createAttachmentModel->attachmentContents);
|
||||
if (function_exists('mb_strlen')) {
|
||||
$fileSize = mb_strlen($fileContents, '8bit');
|
||||
} else {
|
||||
$fileSize = strlen($fileContents);
|
||||
}
|
||||
|
||||
if ($fileSize > $heskSettings['attachments']['max_size']) {
|
||||
$errorKeys[] = 'FILE_SIZE_TOO_LARGE';
|
||||
}
|
||||
|
||||
if (count($errorKeys) > 0) {
|
||||
$validationModel = new ValidationModel();
|
||||
$validationModel->errorKeys = $errorKeys;
|
||||
throw new ValidationException($validationModel);
|
||||
}
|
||||
}
|
||||
|
||||
private function generateSavedName($trackingId, $displayName, $fileExtension) {
|
||||
$fileExtension = ".{$fileExtension}";
|
||||
$useChars = 'AEUYBDGHJLMNPQRSTVWXZ123456789';
|
||||
$tmp = uniqid();
|
||||
for ($j = 1; $j < 10; $j++) {
|
||||
$tmp .= $useChars{mt_rand(0, 29)};
|
||||
}
|
||||
|
||||
|
||||
return substr($trackingId . '_' . md5($tmp . $displayName), 0, 200) . $fileExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $displayName string original file name
|
||||
* @return string The cleaned file name
|
||||
*/
|
||||
private function cleanFileName($displayName) {
|
||||
$filename = str_replace(array('%20', '+'), '-', $displayName);
|
||||
$filename = preg_replace('/[\s-]+/', '-', $filename);
|
||||
$filename = $this->removeAccents($filename);
|
||||
$filename = preg_replace('/[^A-Za-z0-9\.\-_]/', '', $filename);
|
||||
$filename = trim($filename, '-_');
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
// The following code has been borrowed from Wordpress, and also from posting_functions.inc.php :P
|
||||
// Credits: http://wordpress.org
|
||||
private function removeAccents($string)
|
||||
{
|
||||
if (!preg_match('/[\x80-\xff]/', $string)) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
if ($this->seemsUtf8($string)) {
|
||||
$chars = array(
|
||||
// Decompositions for Latin-1 Supplement
|
||||
chr(194) . chr(170) => 'a', chr(194) . chr(186) => 'o',
|
||||
chr(195) . chr(128) => 'A', chr(195) . chr(129) => 'A',
|
||||
chr(195) . chr(130) => 'A', chr(195) . chr(131) => 'A',
|
||||
chr(195) . chr(132) => 'A', chr(195) . chr(133) => 'A',
|
||||
chr(195) . chr(134) => 'AE', chr(195) . chr(135) => 'C',
|
||||
chr(195) . chr(136) => 'E', chr(195) . chr(137) => 'E',
|
||||
chr(195) . chr(138) => 'E', chr(195) . chr(139) => 'E',
|
||||
chr(195) . chr(140) => 'I', chr(195) . chr(141) => 'I',
|
||||
chr(195) . chr(142) => 'I', chr(195) . chr(143) => 'I',
|
||||
chr(195) . chr(144) => 'D', chr(195) . chr(145) => 'N',
|
||||
chr(195) . chr(146) => 'O', chr(195) . chr(147) => 'O',
|
||||
chr(195) . chr(148) => 'O', chr(195) . chr(149) => 'O',
|
||||
chr(195) . chr(150) => 'O', chr(195) . chr(153) => 'U',
|
||||
chr(195) . chr(154) => 'U', chr(195) . chr(155) => 'U',
|
||||
chr(195) . chr(156) => 'U', chr(195) . chr(157) => 'Y',
|
||||
chr(195) . chr(158) => 'TH', chr(195) . chr(159) => 's',
|
||||
chr(195) . chr(160) => 'a', chr(195) . chr(161) => 'a',
|
||||
chr(195) . chr(162) => 'a', chr(195) . chr(163) => 'a',
|
||||
chr(195) . chr(164) => 'a', chr(195) . chr(165) => 'a',
|
||||
chr(195) . chr(166) => 'ae', chr(195) . chr(167) => 'c',
|
||||
chr(195) . chr(168) => 'e', chr(195) . chr(169) => 'e',
|
||||
chr(195) . chr(170) => 'e', chr(195) . chr(171) => 'e',
|
||||
chr(195) . chr(172) => 'i', chr(195) . chr(173) => 'i',
|
||||
chr(195) . chr(174) => 'i', chr(195) . chr(175) => 'i',
|
||||
chr(195) . chr(176) => 'd', chr(195) . chr(177) => 'n',
|
||||
chr(195) . chr(178) => 'o', chr(195) . chr(179) => 'o',
|
||||
chr(195) . chr(180) => 'o', chr(195) . chr(181) => 'o',
|
||||
chr(195) . chr(182) => 'o', chr(195) . chr(184) => 'o',
|
||||
chr(195) . chr(185) => 'u', chr(195) . chr(186) => 'u',
|
||||
chr(195) . chr(187) => 'u', chr(195) . chr(188) => 'u',
|
||||
chr(195) . chr(189) => 'y', chr(195) . chr(190) => 'th',
|
||||
chr(195) . chr(191) => 'y', chr(195) . chr(152) => 'O',
|
||||
// Decompositions for Latin Extended-A
|
||||
chr(196) . chr(128) => 'A', chr(196) . chr(129) => 'a',
|
||||
chr(196) . chr(130) => 'A', chr(196) . chr(131) => 'a',
|
||||
chr(196) . chr(132) => 'A', chr(196) . chr(133) => 'a',
|
||||
chr(196) . chr(134) => 'C', chr(196) . chr(135) => 'c',
|
||||
chr(196) . chr(136) => 'C', chr(196) . chr(137) => 'c',
|
||||
chr(196) . chr(138) => 'C', chr(196) . chr(139) => 'c',
|
||||
chr(196) . chr(140) => 'C', chr(196) . chr(141) => 'c',
|
||||
chr(196) . chr(142) => 'D', chr(196) . chr(143) => 'd',
|
||||
chr(196) . chr(144) => 'D', chr(196) . chr(145) => 'd',
|
||||
chr(196) . chr(146) => 'E', chr(196) . chr(147) => 'e',
|
||||
chr(196) . chr(148) => 'E', chr(196) . chr(149) => 'e',
|
||||
chr(196) . chr(150) => 'E', chr(196) . chr(151) => 'e',
|
||||
chr(196) . chr(152) => 'E', chr(196) . chr(153) => 'e',
|
||||
chr(196) . chr(154) => 'E', chr(196) . chr(155) => 'e',
|
||||
chr(196) . chr(156) => 'G', chr(196) . chr(157) => 'g',
|
||||
chr(196) . chr(158) => 'G', chr(196) . chr(159) => 'g',
|
||||
chr(196) . chr(160) => 'G', chr(196) . chr(161) => 'g',
|
||||
chr(196) . chr(162) => 'G', chr(196) . chr(163) => 'g',
|
||||
chr(196) . chr(164) => 'H', chr(196) . chr(165) => 'h',
|
||||
chr(196) . chr(166) => 'H', chr(196) . chr(167) => 'h',
|
||||
chr(196) . chr(168) => 'I', chr(196) . chr(169) => 'i',
|
||||
chr(196) . chr(170) => 'I', chr(196) . chr(171) => 'i',
|
||||
chr(196) . chr(172) => 'I', chr(196) . chr(173) => 'i',
|
||||
chr(196) . chr(174) => 'I', chr(196) . chr(175) => 'i',
|
||||
chr(196) . chr(176) => 'I', chr(196) . chr(177) => 'i',
|
||||
chr(196) . chr(178) => 'IJ', chr(196) . chr(179) => 'ij',
|
||||
chr(196) . chr(180) => 'J', chr(196) . chr(181) => 'j',
|
||||
chr(196) . chr(182) => 'K', chr(196) . chr(183) => 'k',
|
||||
chr(196) . chr(184) => 'k', chr(196) . chr(185) => 'L',
|
||||
chr(196) . chr(186) => 'l', chr(196) . chr(187) => 'L',
|
||||
chr(196) . chr(188) => 'l', chr(196) . chr(189) => 'L',
|
||||
chr(196) . chr(190) => 'l', chr(196) . chr(191) => 'L',
|
||||
chr(197) . chr(128) => 'l', chr(197) . chr(129) => 'L',
|
||||
chr(197) . chr(130) => 'l', chr(197) . chr(131) => 'N',
|
||||
chr(197) . chr(132) => 'n', chr(197) . chr(133) => 'N',
|
||||
chr(197) . chr(134) => 'n', chr(197) . chr(135) => 'N',
|
||||
chr(197) . chr(136) => 'n', chr(197) . chr(137) => 'N',
|
||||
chr(197) . chr(138) => 'n', chr(197) . chr(139) => 'N',
|
||||
chr(197) . chr(140) => 'O', chr(197) . chr(141) => 'o',
|
||||
chr(197) . chr(142) => 'O', chr(197) . chr(143) => 'o',
|
||||
chr(197) . chr(144) => 'O', chr(197) . chr(145) => 'o',
|
||||
chr(197) . chr(146) => 'OE', chr(197) . chr(147) => 'oe',
|
||||
chr(197) . chr(148) => 'R', chr(197) . chr(149) => 'r',
|
||||
chr(197) . chr(150) => 'R', chr(197) . chr(151) => 'r',
|
||||
chr(197) . chr(152) => 'R', chr(197) . chr(153) => 'r',
|
||||
chr(197) . chr(154) => 'S', chr(197) . chr(155) => 's',
|
||||
chr(197) . chr(156) => 'S', chr(197) . chr(157) => 's',
|
||||
chr(197) . chr(158) => 'S', chr(197) . chr(159) => 's',
|
||||
chr(197) . chr(160) => 'S', chr(197) . chr(161) => 's',
|
||||
chr(197) . chr(162) => 'T', chr(197) . chr(163) => 't',
|
||||
chr(197) . chr(164) => 'T', chr(197) . chr(165) => 't',
|
||||
chr(197) . chr(166) => 'T', chr(197) . chr(167) => 't',
|
||||
chr(197) . chr(168) => 'U', chr(197) . chr(169) => 'u',
|
||||
chr(197) . chr(170) => 'U', chr(197) . chr(171) => 'u',
|
||||
chr(197) . chr(172) => 'U', chr(197) . chr(173) => 'u',
|
||||
chr(197) . chr(174) => 'U', chr(197) . chr(175) => 'u',
|
||||
chr(197) . chr(176) => 'U', chr(197) . chr(177) => 'u',
|
||||
chr(197) . chr(178) => 'U', chr(197) . chr(179) => 'u',
|
||||
chr(197) . chr(180) => 'W', chr(197) . chr(181) => 'w',
|
||||
chr(197) . chr(182) => 'Y', chr(197) . chr(183) => 'y',
|
||||
chr(197) . chr(184) => 'Y', chr(197) . chr(185) => 'Z',
|
||||
chr(197) . chr(186) => 'z', chr(197) . chr(187) => 'Z',
|
||||
chr(197) . chr(188) => 'z', chr(197) . chr(189) => 'Z',
|
||||
chr(197) . chr(190) => 'z', chr(197) . chr(191) => 's',
|
||||
// Decompositions for Latin Extended-B
|
||||
chr(200) . chr(152) => 'S', chr(200) . chr(153) => 's',
|
||||
chr(200) . chr(154) => 'T', chr(200) . chr(155) => 't',
|
||||
// Euro Sign
|
||||
chr(226) . chr(130) . chr(172) => 'E',
|
||||
// GBP (Pound) Sign
|
||||
chr(194) . chr(163) => '',
|
||||
// Vowels with diacritic (Vietnamese)
|
||||
// unmarked
|
||||
chr(198) . chr(160) => 'O', chr(198) . chr(161) => 'o',
|
||||
chr(198) . chr(175) => 'U', chr(198) . chr(176) => 'u',
|
||||
// grave accent
|
||||
chr(225) . chr(186) . chr(166) => 'A', chr(225) . chr(186) . chr(167) => 'a',
|
||||
chr(225) . chr(186) . chr(176) => 'A', chr(225) . chr(186) . chr(177) => 'a',
|
||||
chr(225) . chr(187) . chr(128) => 'E', chr(225) . chr(187) . chr(129) => 'e',
|
||||
chr(225) . chr(187) . chr(146) => 'O', chr(225) . chr(187) . chr(147) => 'o',
|
||||
chr(225) . chr(187) . chr(156) => 'O', chr(225) . chr(187) . chr(157) => 'o',
|
||||
chr(225) . chr(187) . chr(170) => 'U', chr(225) . chr(187) . chr(171) => 'u',
|
||||
chr(225) . chr(187) . chr(178) => 'Y', chr(225) . chr(187) . chr(179) => 'y',
|
||||
// hook
|
||||
chr(225) . chr(186) . chr(162) => 'A', chr(225) . chr(186) . chr(163) => 'a',
|
||||
chr(225) . chr(186) . chr(168) => 'A', chr(225) . chr(186) . chr(169) => 'a',
|
||||
chr(225) . chr(186) . chr(178) => 'A', chr(225) . chr(186) . chr(179) => 'a',
|
||||
chr(225) . chr(186) . chr(186) => 'E', chr(225) . chr(186) . chr(187) => 'e',
|
||||
chr(225) . chr(187) . chr(130) => 'E', chr(225) . chr(187) . chr(131) => 'e',
|
||||
chr(225) . chr(187) . chr(136) => 'I', chr(225) . chr(187) . chr(137) => 'i',
|
||||
chr(225) . chr(187) . chr(142) => 'O', chr(225) . chr(187) . chr(143) => 'o',
|
||||
chr(225) . chr(187) . chr(148) => 'O', chr(225) . chr(187) . chr(149) => 'o',
|
||||
chr(225) . chr(187) . chr(158) => 'O', chr(225) . chr(187) . chr(159) => 'o',
|
||||
chr(225) . chr(187) . chr(166) => 'U', chr(225) . chr(187) . chr(167) => 'u',
|
||||
chr(225) . chr(187) . chr(172) => 'U', chr(225) . chr(187) . chr(173) => 'u',
|
||||
chr(225) . chr(187) . chr(182) => 'Y', chr(225) . chr(187) . chr(183) => 'y',
|
||||
// tilde
|
||||
chr(225) . chr(186) . chr(170) => 'A', chr(225) . chr(186) . chr(171) => 'a',
|
||||
chr(225) . chr(186) . chr(180) => 'A', chr(225) . chr(186) . chr(181) => 'a',
|
||||
chr(225) . chr(186) . chr(188) => 'E', chr(225) . chr(186) . chr(189) => 'e',
|
||||
chr(225) . chr(187) . chr(132) => 'E', chr(225) . chr(187) . chr(133) => 'e',
|
||||
chr(225) . chr(187) . chr(150) => 'O', chr(225) . chr(187) . chr(151) => 'o',
|
||||
chr(225) . chr(187) . chr(160) => 'O', chr(225) . chr(187) . chr(161) => 'o',
|
||||
chr(225) . chr(187) . chr(174) => 'U', chr(225) . chr(187) . chr(175) => 'u',
|
||||
chr(225) . chr(187) . chr(184) => 'Y', chr(225) . chr(187) . chr(185) => 'y',
|
||||
// acute accent
|
||||
chr(225) . chr(186) . chr(164) => 'A', chr(225) . chr(186) . chr(165) => 'a',
|
||||
chr(225) . chr(186) . chr(174) => 'A', chr(225) . chr(186) . chr(175) => 'a',
|
||||
chr(225) . chr(186) . chr(190) => 'E', chr(225) . chr(186) . chr(191) => 'e',
|
||||
chr(225) . chr(187) . chr(144) => 'O', chr(225) . chr(187) . chr(145) => 'o',
|
||||
chr(225) . chr(187) . chr(154) => 'O', chr(225) . chr(187) . chr(155) => 'o',
|
||||
chr(225) . chr(187) . chr(168) => 'U', chr(225) . chr(187) . chr(169) => 'u',
|
||||
// dot below
|
||||
chr(225) . chr(186) . chr(160) => 'A', chr(225) . chr(186) . chr(161) => 'a',
|
||||
chr(225) . chr(186) . chr(172) => 'A', chr(225) . chr(186) . chr(173) => 'a',
|
||||
chr(225) . chr(186) . chr(182) => 'A', chr(225) . chr(186) . chr(183) => 'a',
|
||||
chr(225) . chr(186) . chr(184) => 'E', chr(225) . chr(186) . chr(185) => 'e',
|
||||
chr(225) . chr(187) . chr(134) => 'E', chr(225) . chr(187) . chr(135) => 'e',
|
||||
chr(225) . chr(187) . chr(138) => 'I', chr(225) . chr(187) . chr(139) => 'i',
|
||||
chr(225) . chr(187) . chr(140) => 'O', chr(225) . chr(187) . chr(141) => 'o',
|
||||
chr(225) . chr(187) . chr(152) => 'O', chr(225) . chr(187) . chr(153) => 'o',
|
||||
chr(225) . chr(187) . chr(162) => 'O', chr(225) . chr(187) . chr(163) => 'o',
|
||||
chr(225) . chr(187) . chr(164) => 'U', chr(225) . chr(187) . chr(165) => 'u',
|
||||
chr(225) . chr(187) . chr(176) => 'U', chr(225) . chr(187) . chr(177) => 'u',
|
||||
chr(225) . chr(187) . chr(180) => 'Y', chr(225) . chr(187) . chr(181) => 'y',
|
||||
// Vowels with diacritic (Chinese, Hanyu Pinyin)
|
||||
chr(201) . chr(145) => 'a',
|
||||
// macron
|
||||
chr(199) . chr(149) => 'U', chr(199) . chr(150) => 'u',
|
||||
// acute accent
|
||||
chr(199) . chr(151) => 'U', chr(199) . chr(152) => 'u',
|
||||
// caron
|
||||
chr(199) . chr(141) => 'A', chr(199) . chr(142) => 'a',
|
||||
chr(199) . chr(143) => 'I', chr(199) . chr(144) => 'i',
|
||||
chr(199) . chr(145) => 'O', chr(199) . chr(146) => 'o',
|
||||
chr(199) . chr(147) => 'U', chr(199) . chr(148) => 'u',
|
||||
chr(199) . chr(153) => 'U', chr(199) . chr(154) => 'u',
|
||||
// grave accent
|
||||
chr(199) . chr(155) => 'U', chr(199) . chr(156) => 'u',
|
||||
);
|
||||
|
||||
$string = strtr($string, $chars);
|
||||
} else {
|
||||
// Assume ISO-8859-1 if not UTF-8
|
||||
$chars['in'] = chr(128) . chr(131) . chr(138) . chr(142) . chr(154) . chr(158)
|
||||
. chr(159) . chr(162) . chr(165) . chr(181) . chr(192) . chr(193) . chr(194)
|
||||
. chr(195) . chr(196) . chr(197) . chr(199) . chr(200) . chr(201) . chr(202)
|
||||
. chr(203) . chr(204) . chr(205) . chr(206) . chr(207) . chr(209) . chr(210)
|
||||
. chr(211) . chr(212) . chr(213) . chr(214) . chr(216) . chr(217) . chr(218)
|
||||
. chr(219) . chr(220) . chr(221) . chr(224) . chr(225) . chr(226) . chr(227)
|
||||
. chr(228) . chr(229) . chr(231) . chr(232) . chr(233) . chr(234) . chr(235)
|
||||
. chr(236) . chr(237) . chr(238) . chr(239) . chr(241) . chr(242) . chr(243)
|
||||
. chr(244) . chr(245) . chr(246) . chr(248) . chr(249) . chr(250) . chr(251)
|
||||
. chr(252) . chr(253) . chr(255);
|
||||
|
||||
$chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
|
||||
|
||||
$string = strtr($string, $chars['in'], $chars['out']);
|
||||
$double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
|
||||
$double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
|
||||
$string = str_replace($double_chars['in'], $double_chars['out'], $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function seemsUtf8($str)
|
||||
{
|
||||
$length = strlen($str);
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$c = ord($str[$i]);
|
||||
if ($c < 0x80) $n = 0; # 0bbbbbbb
|
||||
elseif (($c & 0xE0) == 0xC0) $n = 1; # 110bbbbb
|
||||
elseif (($c & 0xF0) == 0xE0) $n = 2; # 1110bbbb
|
||||
elseif (($c & 0xF8) == 0xF0) $n = 3; # 11110bbb
|
||||
elseif (($c & 0xFC) == 0xF8) $n = 4; # 111110bb
|
||||
elseif (($c & 0xFE) == 0xFC) $n = 5; # 1111110b
|
||||
else return false; # Does not match any model
|
||||
for ($j = 0; $j < $n; $j++) { # n bytes matching 10bbbbbb follow ?
|
||||
if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ticket Ticket
|
||||
* @param $ticketAttachment TicketAttachment
|
||||
* @param $attachmentId int
|
||||
* @param $heskSettings array
|
||||
*/
|
||||
private function updateAttachmentsOnTicket($ticket, $ticketAttachment, $attachmentId, $heskSettings) {
|
||||
$attachments = $ticket->attachments === null ? array() : $ticket->attachments;
|
||||
$newAttachment = new Attachment();
|
||||
$newAttachment->savedName = $ticketAttachment->savedName;
|
||||
$newAttachment->fileName = $ticketAttachment->displayName;
|
||||
$newAttachment->id = $attachmentId;
|
||||
$attachments[] = $newAttachment;
|
||||
$this->ticketGateway->updateAttachmentsForTicket($ticket->id, $attachments, $heskSettings);
|
||||
}
|
||||
}
|
50
api/BusinessLogic/Attachments/AttachmentRetriever.php
Normal file
50
api/BusinessLogic/Attachments/AttachmentRetriever.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\AccessViolationException;
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Security\UserToTicketChecker;
|
||||
use DataAccess\Attachments\AttachmentGateway;
|
||||
use DataAccess\Files\FileReader;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class AttachmentRetriever {
|
||||
/* @var $attachmentGateway AttachmentGateway */
|
||||
private $attachmentGateway;
|
||||
|
||||
/* @var $fileReader FileReader */
|
||||
private $fileReader;
|
||||
|
||||
/* @var $ticketGateway TicketGateway */
|
||||
private $ticketGateway;
|
||||
|
||||
/* @var $userToTicketChecker UserToTicketChecker */
|
||||
private $userToTicketChecker;
|
||||
|
||||
function __construct($attachmentGateway, $fileReader, $ticketGateway, $userToTicketChecker) {
|
||||
$this->attachmentGateway = $attachmentGateway;
|
||||
$this->fileReader = $fileReader;
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
$this->userToTicketChecker = $userToTicketChecker;
|
||||
}
|
||||
|
||||
function getAttachmentContentsForTicket($ticketId, $attachmentId, $userContext, $heskSettings) {
|
||||
$ticket = $this->ticketGateway->getTicketById($ticketId, $heskSettings);
|
||||
|
||||
if ($ticket === null) {
|
||||
throw new ApiFriendlyException("Ticket {$ticketId} not found!", "Ticket Not Found", 404);
|
||||
}
|
||||
|
||||
if ($this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings)) {
|
||||
throw new AccessViolationException("User does not have access to attachment {$attachmentId}!");
|
||||
}
|
||||
|
||||
$attachment = $this->attachmentGateway->getAttachmentById($attachmentId, $heskSettings);
|
||||
$contents = base64_encode($this->fileReader->readFromFile(
|
||||
$attachment->savedName, $heskSettings['attach_dir']));
|
||||
|
||||
return $contents;
|
||||
}
|
||||
}
|
9
api/BusinessLogic/Attachments/AttachmentType.php
Normal file
9
api/BusinessLogic/Attachments/AttachmentType.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class AttachmentType {
|
||||
const MESSAGE = 0;
|
||||
const REPLY = 1;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class CreateAttachmentForTicketModel extends CreateAttachmentModel {
|
||||
/* @var $ticketId int */
|
||||
public $ticketId;
|
||||
}
|
21
api/BusinessLogic/Attachments/CreateAttachmentModel.php
Normal file
21
api/BusinessLogic/Attachments/CreateAttachmentModel.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class CreateAttachmentModel {
|
||||
/* @var $savedName string */
|
||||
public $savedName;
|
||||
|
||||
/* @var $displayName string */
|
||||
public $displayName;
|
||||
|
||||
/* @var $id int */
|
||||
public $fileSize;
|
||||
|
||||
/* @var $attachmentContents string */
|
||||
public $attachmentContents;
|
||||
|
||||
/* @var $isEditing bool */
|
||||
public $isEditing;
|
||||
}
|
12
api/BusinessLogic/Attachments/TicketAttachment.php
Normal file
12
api/BusinessLogic/Attachments/TicketAttachment.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class TicketAttachment extends Attachment {
|
||||
/* @var $ticketTrackingId string */
|
||||
public $ticketTrackingId;
|
||||
|
||||
/* @var $type int [use <code>AttachmentType</code>] */
|
||||
public $type;
|
||||
}
|
63
api/BusinessLogic/Categories/Category.php
Normal file
63
api/BusinessLogic/Categories/Category.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Categories;
|
||||
|
||||
class Category {
|
||||
/**
|
||||
* @var int The Categories ID
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/* @var $name string */
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var int Categories order number
|
||||
*/
|
||||
public $catOrder;
|
||||
|
||||
/**
|
||||
* @var bool Tickets autoassigned in this Categories
|
||||
*/
|
||||
public $autoAssign;
|
||||
|
||||
/**
|
||||
* @var int The type of Categories (1 = Private, 2 = Public)
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* @var int The Categories's usage (0 = Tickets and Events, 1 = Tickets, 2 = Events)
|
||||
*/
|
||||
public $usage;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $backgroundColor;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $foregroundColor;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $displayBorder;
|
||||
|
||||
/**
|
||||
* @var int The default Tickets priority
|
||||
*/
|
||||
public $priority;
|
||||
|
||||
/**
|
||||
* @var int|null The manager for the Categories, if applicable
|
||||
*/
|
||||
public $manager;
|
||||
|
||||
/**
|
||||
* @var bool Indication if the user has access to the Categories
|
||||
*/
|
||||
public $accessible;
|
||||
}
|
33
api/BusinessLogic/Categories/CategoryRetriever.php
Normal file
33
api/BusinessLogic/Categories/CategoryRetriever.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Categories;
|
||||
|
||||
use BusinessLogic\Security\UserContext;
|
||||
use DataAccess\Categories\CategoryGateway;
|
||||
|
||||
class CategoryRetriever {
|
||||
/**
|
||||
* @var CategoryGateway
|
||||
*/
|
||||
private $categoryGateway;
|
||||
|
||||
function __construct($categoryGateway) {
|
||||
$this->categoryGateway = $categoryGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $heskSettings array
|
||||
* @param $userContext UserContext
|
||||
* @return array
|
||||
*/
|
||||
function getAllCategories($heskSettings, $userContext) {
|
||||
$categories = $this->categoryGateway->getAllCategories($heskSettings);
|
||||
|
||||
foreach ($categories as $category) {
|
||||
$category->accessible = $userContext->admin ||
|
||||
in_array($category->id, $userContext->categories);
|
||||
}
|
||||
|
||||
return $categories;
|
||||
}
|
||||
}
|
21
api/BusinessLogic/Emails/Addressees.php
Normal file
21
api/BusinessLogic/Emails/Addressees.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
class Addressees {
|
||||
/**
|
||||
* @var $to string[]
|
||||
*/
|
||||
public $to;
|
||||
|
||||
/**
|
||||
* @var $cc string[]|null
|
||||
*/
|
||||
public $cc;
|
||||
|
||||
/**
|
||||
* @var $bcc string[]|null
|
||||
*/
|
||||
public $bcc;
|
||||
}
|
75
api/BusinessLogic/Emails/BasicEmailSender.php
Normal file
75
api/BusinessLogic/Emails/BasicEmailSender.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Attachment;
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use PHPMailer;
|
||||
|
||||
class BasicEmailSender implements EmailSender {
|
||||
|
||||
function sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $sendAsHtml) {
|
||||
$mailer = new PHPMailer();
|
||||
|
||||
if ($heskSettings['smtp']) {
|
||||
$mailer->isSMTP();
|
||||
$mailer->SMTPAuth = true;
|
||||
if ($heskSettings['smtp_ssl']) {
|
||||
$mailer->SMTPSecure = "ssl";
|
||||
} elseif ($heskSettings['smtp_tls']) {
|
||||
$mailer->SMTPSecure = "tls";
|
||||
}
|
||||
$mailer->Host = $heskSettings['smtp_host_name'];
|
||||
$mailer->Port = $heskSettings['smtp_host_port'];
|
||||
$mailer->Username = $heskSettings['smtp_user'];
|
||||
$mailer->Password = $heskSettings['smtp_password'];
|
||||
}
|
||||
|
||||
$mailer->FromName = $heskSettings['noreply_name'] !== null &&
|
||||
$heskSettings['noreply_name'] !== '' ? $heskSettings['noreply_name'] : '';
|
||||
$mailer->From = $heskSettings['noreply_mail'];
|
||||
|
||||
if ($emailBuilder->to !== null) {
|
||||
foreach ($emailBuilder->to as $to) {
|
||||
$mailer->addAddress($to);
|
||||
}
|
||||
}
|
||||
|
||||
if ($emailBuilder->cc !== null) {
|
||||
foreach ($emailBuilder->cc as $cc) {
|
||||
$mailer->addCC($cc);
|
||||
}
|
||||
}
|
||||
|
||||
if ($emailBuilder->bcc !== null) {
|
||||
foreach ($emailBuilder->bcc as $bcc) {
|
||||
$mailer->addBCC($bcc);
|
||||
}
|
||||
}
|
||||
|
||||
$mailer->Subject = $emailBuilder->subject;
|
||||
|
||||
if ($sendAsHtml) {
|
||||
$mailer->Body = $emailBuilder->htmlMessage;
|
||||
$mailer->AltBody = $emailBuilder->message;
|
||||
} else {
|
||||
$mailer->Body = $emailBuilder->message;
|
||||
$mailer->isHTML(false);
|
||||
}
|
||||
$mailer->Timeout = $heskSettings['smtp_timeout'];
|
||||
|
||||
if ($emailBuilder->attachments !== null) {
|
||||
foreach ($emailBuilder->attachments as $attachment) {
|
||||
$mailer->addAttachment(__DIR__ . '/../../../' . $heskSettings['attach_dir'] . '/' . $attachment->savedName,
|
||||
$attachment->fileName);
|
||||
}
|
||||
}
|
||||
|
||||
if ($mailer->send()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $mailer->ErrorInfo;
|
||||
}
|
||||
}
|
43
api/BusinessLogic/Emails/EmailBuilder.php
Normal file
43
api/BusinessLogic/Emails/EmailBuilder.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Attachment;
|
||||
|
||||
class EmailBuilder {
|
||||
/**
|
||||
* @var $to string[]
|
||||
*/
|
||||
public $to;
|
||||
|
||||
/**
|
||||
* @var $cc string[]
|
||||
*/
|
||||
public $cc;
|
||||
|
||||
/**
|
||||
* @var $bcc string[]
|
||||
*/
|
||||
public $bcc;
|
||||
|
||||
/**
|
||||
* @var $subject string
|
||||
*/
|
||||
public $subject;
|
||||
|
||||
/**
|
||||
* @var $message string
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* @var $htmlMessage string
|
||||
*/
|
||||
public $htmlMessage;
|
||||
|
||||
/**
|
||||
* @var $attachments Attachment[]
|
||||
*/
|
||||
public $attachments;
|
||||
}
|
21
api/BusinessLogic/Emails/EmailSender.php
Normal file
21
api/BusinessLogic/Emails/EmailSender.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Attachment;
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use PHPMailer;
|
||||
|
||||
interface EmailSender {
|
||||
/**
|
||||
* Use to send emails
|
||||
*
|
||||
* @param $emailBuilder EmailBuilder
|
||||
* @param $heskSettings array
|
||||
* @param $modsForHeskSettings array
|
||||
* @param $sendAsHtml bool
|
||||
* @return bool|string|\stdClass true if message sent successfully, string for PHPMail/Smtp error, stdClass for Mailgun error
|
||||
*/
|
||||
function sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $sendAsHtml);
|
||||
}
|
74
api/BusinessLogic/Emails/EmailSenderHelper.php
Normal file
74
api/BusinessLogic/Emails/EmailSenderHelper.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
|
||||
class EmailSenderHelper {
|
||||
/**
|
||||
* @var $emailTemplateParser EmailTemplateParser
|
||||
*/
|
||||
private $emailTemplateParser;
|
||||
|
||||
/**
|
||||
* @var $basicEmailSender BasicEmailSender
|
||||
*/
|
||||
private $basicEmailSender;
|
||||
|
||||
/**
|
||||
* @var $mailgunEmailSender MailgunEmailSender
|
||||
*/
|
||||
private $mailgunEmailSender;
|
||||
|
||||
function __construct($emailTemplateParser, $basicEmailSender, $mailgunEmailSender) {
|
||||
$this->emailTemplateParser = $emailTemplateParser;
|
||||
$this->basicEmailSender = $basicEmailSender;
|
||||
$this->mailgunEmailSender = $mailgunEmailSender;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $templateId int the EmailTemplateRetriever::TEMPLATE_NAME
|
||||
* @param $language string the language name
|
||||
* @param $addressees Addressees the addressees. **cc and bcc addresses from custom fields will be added here!**
|
||||
* @param $ticket Ticket
|
||||
* @param $heskSettings array
|
||||
* @param $modsForHeskSettings array
|
||||
*/
|
||||
function sendEmailForTicket($templateId, $language, $addressees, $ticket, $heskSettings, $modsForHeskSettings) {
|
||||
$languageCode = $heskSettings['languages'][$language]['folder'];
|
||||
|
||||
$parsedTemplate = $this->emailTemplateParser->getFormattedEmailForLanguage($templateId, $languageCode,
|
||||
$ticket, $heskSettings, $modsForHeskSettings);
|
||||
|
||||
$emailBuilder = new EmailBuilder();
|
||||
$emailBuilder->subject = $parsedTemplate->subject;
|
||||
$emailBuilder->message = $parsedTemplate->message;
|
||||
$emailBuilder->htmlMessage = $parsedTemplate->htmlMessage;
|
||||
$emailBuilder->to = $addressees->to;
|
||||
$emailBuilder->cc = $addressees->cc;
|
||||
$emailBuilder->bcc = $addressees->bcc;
|
||||
|
||||
foreach ($heskSettings['custom_fields'] as $k => $v) {
|
||||
$number = intval(str_replace('custom', '', $k));
|
||||
if ($v['use'] && $v['type'] == 'email' && !empty($ticket->customFields[$number])) {
|
||||
if ($v['value']['email_type'] == 'cc') {
|
||||
$emailBuilder->cc[] = $ticket->customFields[$number];
|
||||
} elseif ($v['value']['email_type'] == 'bcc') {
|
||||
$emailBuilder->bcc[] = $ticket->customFields[$number];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($modsForHeskSettings['attachments']) {
|
||||
$emailBuilder->attachments = $ticket->attachments;
|
||||
}
|
||||
|
||||
if ($modsForHeskSettings['use_mailgun']) {
|
||||
$this->mailgunEmailSender->sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $modsForHeskSettings['html_emails']);
|
||||
} else {
|
||||
$this->basicEmailSender->sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $modsForHeskSettings['html_emails']);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
27
api/BusinessLogic/Emails/EmailTemplate.php
Normal file
27
api/BusinessLogic/Emails/EmailTemplate.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
class EmailTemplate {
|
||||
/**
|
||||
* @var $languageKey string
|
||||
*/
|
||||
public $languageKey;
|
||||
|
||||
/**
|
||||
* @var $fileName string
|
||||
*/
|
||||
public $fileName;
|
||||
|
||||
/**
|
||||
* @var $forStaff bool
|
||||
*/
|
||||
public $forStaff;
|
||||
|
||||
function __construct($forStaff, $fileName, $languageKey = null) {
|
||||
$this->languageKey = $languageKey === null ? $fileName : $languageKey;
|
||||
$this->fileName = $fileName;
|
||||
$this->forStaff = $forStaff;
|
||||
}
|
||||
}
|
331
api/BusinessLogic/Emails/EmailTemplateParser.php
Normal file
331
api/BusinessLogic/Emails/EmailTemplateParser.php
Normal file
@ -0,0 +1,331 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Exceptions\EmailTemplateNotFoundException;
|
||||
use BusinessLogic\Exceptions\InvalidEmailTemplateException;
|
||||
use BusinessLogic\Statuses\DefaultStatusForAction;
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use Core\Constants\Priority;
|
||||
use DataAccess\Categories\CategoryGateway;
|
||||
use DataAccess\Security\UserGateway;
|
||||
use DataAccess\Statuses\StatusGateway;
|
||||
|
||||
class EmailTemplateParser {
|
||||
|
||||
/**
|
||||
* @var $statusGateway StatusGateway
|
||||
*/
|
||||
private $statusGateway;
|
||||
|
||||
/**
|
||||
* @var $categoryGateway CategoryGateway
|
||||
*/
|
||||
private $categoryGateway;
|
||||
|
||||
/**
|
||||
* @var $userGateway UserGateway
|
||||
*/
|
||||
private $userGateway;
|
||||
|
||||
/**
|
||||
* @var $emailTemplateRetriever EmailTemplateRetriever
|
||||
*/
|
||||
private $emailTemplateRetriever;
|
||||
|
||||
function __construct($statusGateway, $categoryGateway, $userGateway, $emailTemplateRetriever) {
|
||||
$this->statusGateway = $statusGateway;
|
||||
$this->categoryGateway = $categoryGateway;
|
||||
$this->userGateway = $userGateway;
|
||||
$this->emailTemplateRetriever = $emailTemplateRetriever;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $templateId int
|
||||
* @param $languageCode string
|
||||
* @param $ticket Ticket
|
||||
* @param $heskSettings array
|
||||
* @param $modsForHeskSettings array
|
||||
* @return ParsedEmailProperties
|
||||
* @throws InvalidEmailTemplateException
|
||||
*/
|
||||
function getFormattedEmailForLanguage($templateId, $languageCode, $ticket, $heskSettings, $modsForHeskSettings) {
|
||||
global $hesklang;
|
||||
|
||||
$emailTemplate = $this->emailTemplateRetriever->getTemplate($templateId);
|
||||
|
||||
if ($emailTemplate === null) {
|
||||
throw new InvalidEmailTemplateException($templateId);
|
||||
}
|
||||
|
||||
$template = self::getFromFileSystem($emailTemplate->fileName, $languageCode, false);
|
||||
$htmlTemplate = self::getFromFileSystem($emailTemplate->fileName, $languageCode, true);
|
||||
$subject = $hesklang[$emailTemplate->languageKey];
|
||||
|
||||
$fullLanguageName = null;
|
||||
foreach ($heskSettings['languages'] as $key => $value) {
|
||||
if ($value['folder'] === $languageCode) {
|
||||
$fullLanguageName = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($fullLanguageName === null) {
|
||||
throw new \Exception("Language code {$languageCode} did not return any valid HESK languages!");
|
||||
}
|
||||
|
||||
$subject = $this->parseSubject($subject, $ticket, $fullLanguageName, $heskSettings);
|
||||
$message = $this->parseMessage($template, $ticket, $fullLanguageName, $emailTemplate->forStaff, $heskSettings, $modsForHeskSettings, false);
|
||||
$htmlMessage = $this->parseMessage($htmlTemplate, $ticket, $fullLanguageName, $emailTemplate->forStaff, $heskSettings, $modsForHeskSettings, true);
|
||||
|
||||
return new ParsedEmailProperties($subject, $message, $htmlMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $template string
|
||||
* @param $language string
|
||||
* @param $html bool
|
||||
* @return string The template
|
||||
* @throws EmailTemplateNotFoundException If the template was not found in the filesystem for the provided language
|
||||
*/
|
||||
private function getFromFileSystem($template, $language, $html)
|
||||
{
|
||||
$htmlFolder = $html ? 'html/' : '';
|
||||
|
||||
/* Get email template */
|
||||
$file = "language/{$language}/emails/{$htmlFolder}{$template}.txt";
|
||||
$absoluteFilePath = __DIR__ . '/../../../' . $file;
|
||||
|
||||
if (file_exists($absoluteFilePath)) {
|
||||
return file_get_contents($absoluteFilePath);
|
||||
} else {
|
||||
throw new EmailTemplateNotFoundException($template, $language);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $subjectTemplate string
|
||||
* @param $ticket Ticket
|
||||
* @param $language string
|
||||
* @param $heskSettings array
|
||||
* @return string
|
||||
* @throws \Exception if common.inc.php isn't loaded
|
||||
*/
|
||||
private function parseSubject($subjectTemplate, $ticket, $language, $heskSettings) {
|
||||
global $hesklang;
|
||||
|
||||
if (!function_exists('hesk_msgToPlain')) {
|
||||
throw new \Exception("common.inc.php not loaded!");
|
||||
}
|
||||
|
||||
if ($ticket === null) {
|
||||
return $subjectTemplate;
|
||||
}
|
||||
|
||||
// Status name and category name
|
||||
$defaultStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings);
|
||||
$statusName = $defaultStatus->localizedNames[$language];
|
||||
$category = $this->categoryGateway->getAllCategories($heskSettings)[$ticket->categoryId];
|
||||
|
||||
switch ($ticket->priorityId) {
|
||||
case Priority::CRITICAL:
|
||||
$priority = $hesklang['critical'];
|
||||
break;
|
||||
case Priority::HIGH:
|
||||
$priority = $hesklang['high'];
|
||||
break;
|
||||
case Priority::MEDIUM:
|
||||
$priority = $hesklang['medium'];
|
||||
break;
|
||||
case Priority::LOW:
|
||||
$priority = $hesklang['low'];
|
||||
break;
|
||||
default:
|
||||
$priority = 'PRIORITY NOT FOUND';
|
||||
break;
|
||||
}
|
||||
|
||||
// Special tags
|
||||
$subject = str_replace('%%SUBJECT%%', $ticket->subject, $subjectTemplate);
|
||||
$subject = str_replace('%%TRACK_ID%%', $ticket->trackingId, $subject);
|
||||
$subject = str_replace('%%CATEGORY%%', $category->id, $subject);
|
||||
$subject = str_replace('%%PRIORITY%%', $priority, $subject);
|
||||
$subject = str_replace('%%STATUS%%', $statusName, $subject);
|
||||
|
||||
return $subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $messageTemplate string
|
||||
* @param $ticket Ticket
|
||||
* @param $language string
|
||||
* @param $heskSettings array
|
||||
* @return string
|
||||
* @throws \Exception if common.inc.php isn't loaded
|
||||
*/
|
||||
private function parseMessage($messageTemplate, $ticket, $language, $admin, $heskSettings, $modsForHeskSettings, $html) {
|
||||
global $hesklang;
|
||||
|
||||
if (!function_exists('hesk_msgToPlain')) {
|
||||
throw new \Exception("common.inc.php not loaded!");
|
||||
}
|
||||
|
||||
if ($ticket === null) {
|
||||
return $messageTemplate;
|
||||
}
|
||||
|
||||
$heskSettings['site_title'] = hesk_msgToPlain($heskSettings['site_title'], 1);
|
||||
|
||||
// Is email required to view ticket (for customers only)?
|
||||
$heskSettings['e_param'] = $heskSettings['email_view_ticket'] ? '&e=' . rawurlencode(implode(';', $ticket->email)) : '';
|
||||
|
||||
/* Generate the ticket URLs */
|
||||
$trackingURL = $heskSettings['hesk_url'];
|
||||
$trackingURL .= $admin ? '/' . $heskSettings['admin_dir'] . '/admin_ticket.php' : '/ticket.php';
|
||||
$trackingURL .= '?track=' . $ticket->trackingId . ($admin ? '' : $heskSettings['e_param']) . '&Refresh=' . rand(10000, 99999);
|
||||
|
||||
// Status name and category name
|
||||
$defaultStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings);
|
||||
$statusName = hesk_msgToPlain($defaultStatus->localizedNames[$language]);
|
||||
$category = hesk_msgToPlain($this->categoryGateway->getAllCategories($heskSettings)[$ticket->categoryId]->name);
|
||||
$owner = hesk_msgToPlain($this->userGateway->getUserById($ticket->ownerId, $heskSettings)->name);
|
||||
|
||||
switch ($ticket->priorityId) {
|
||||
case Priority::CRITICAL:
|
||||
$priority = $hesklang['critical'];
|
||||
break;
|
||||
case Priority::HIGH:
|
||||
$priority = $hesklang['high'];
|
||||
break;
|
||||
case Priority::MEDIUM:
|
||||
$priority = $hesklang['medium'];
|
||||
break;
|
||||
case Priority::LOW:
|
||||
$priority = $hesklang['low'];
|
||||
break;
|
||||
default:
|
||||
$priority = 'PRIORITY NOT FOUND';
|
||||
break;
|
||||
}
|
||||
|
||||
// Special tags
|
||||
$msg = str_replace('%%NAME%%', $ticket->name, $messageTemplate);
|
||||
$msg = str_replace('%%SUBJECT%%', $ticket->subject, $msg);
|
||||
$msg = str_replace('%%TRACK_ID%%', $ticket->trackingId, $msg);
|
||||
$msg = str_replace('%%TRACK_URL%%', $trackingURL, $msg);
|
||||
$msg = str_replace('%%SITE_TITLE%%', $heskSettings['site_title'], $msg);
|
||||
$msg = str_replace('%%SITE_URL%%', $heskSettings['site_url'], $msg);
|
||||
$msg = str_replace('%%CATEGORY%%', $category, $msg);
|
||||
$msg = str_replace('%%PRIORITY%%', $priority, $msg);
|
||||
$msg = str_replace('%%OWNER%%', $owner, $msg);
|
||||
$msg = str_replace('%%STATUS%%', $statusName, $msg);
|
||||
$msg = str_replace('%%EMAIL%%', implode(';',$ticket->email), $msg);
|
||||
$msg = str_replace('%%CREATED%%', $ticket->dateCreated, $msg);
|
||||
$msg = str_replace('%%UPDATED%%', $ticket->lastChanged, $msg);
|
||||
$msg = str_replace('%%ID%%', $ticket->id, $msg);
|
||||
|
||||
/* All custom fields */
|
||||
for ($i=1; $i<=50; $i++) {
|
||||
$k = 'custom'.$i;
|
||||
|
||||
if (isset($heskSettings['custom_fields'][$k]) && isset($ticket->customFields[$i])) {
|
||||
$v = $heskSettings['custom_fields'][$k];
|
||||
|
||||
switch ($v['type']) {
|
||||
case 'checkbox':
|
||||
$ticket->customFields[$i] = str_replace("<br>","\n",$ticket->customFields[$i]);
|
||||
break;
|
||||
case 'date':
|
||||
$ticket->customFields[$i] = hesk_custom_date_display_format($ticket->customFields[$i], $v['value']['date_format']);
|
||||
break;
|
||||
}
|
||||
|
||||
$msg = str_replace('%%'.strtoupper($k).'%%',stripslashes($ticket->customFields[$i]),$msg);
|
||||
} else {
|
||||
$msg = str_replace('%%'.strtoupper($k).'%%','',$msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Is message tag in email template?
|
||||
if (strpos($msg, '%%MESSAGE%%') !== false) {
|
||||
// Replace message
|
||||
if ($html) {
|
||||
$htmlMessage = html_entity_decode($ticket->message);
|
||||
$htmlMessage = nl2br($htmlMessage);
|
||||
$msg = str_replace('%%MESSAGE%%', $htmlMessage, $msg);
|
||||
} else {
|
||||
$plainTextMessage = $ticket->message;
|
||||
|
||||
$messageHtml = $ticket->usesHtml;
|
||||
|
||||
if (count($ticket->replies) > 0) {
|
||||
$lastReply = end($ticket->replies);
|
||||
$messageHtml = $lastReply->usesHtml;
|
||||
}
|
||||
|
||||
if ($messageHtml) {
|
||||
if (!function_exists('convert_html_to_text')) {
|
||||
require(__DIR__ . '/../../../inc/html2text/html2text.php');
|
||||
}
|
||||
$plainTextMessage = convert_html_to_text($plainTextMessage);
|
||||
$plainTextMessage = fix_newlines($plainTextMessage);
|
||||
}
|
||||
$msg = str_replace('%%MESSAGE%%', $plainTextMessage, $msg);
|
||||
}
|
||||
|
||||
// Add direct links to any attachments at the bottom of the email message
|
||||
if ($heskSettings['attachments']['use'] && isset($ticket->attachments) && count($ticket->attachments) > 0) {
|
||||
if (!$modsForHeskSettings['attachments']) {
|
||||
if ($html) {
|
||||
$msg .= "<br><br><br>" . $hesklang['fatt'];
|
||||
} else {
|
||||
$msg .= "\n\n\n" . $hesklang['fatt'];
|
||||
}
|
||||
|
||||
foreach ($ticket->attachments as $attachment) {
|
||||
if ($html) {
|
||||
$msg .= "<br><br>{$attachment->fileName}<br>";
|
||||
} else {
|
||||
$msg .= "\n\n{$attachment->fileName}\n";
|
||||
}
|
||||
|
||||
$msg .= "{$heskSettings['hesk_url']}/download_attachment.php?att_id={$attachment->id}&track={$ticket->trackingId}{$heskSettings['e_param']}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For customer notifications: if we allow email piping/pop 3 fetching and
|
||||
// stripping quoted replies add an "reply above this line" tag
|
||||
if (!$admin && ($heskSettings['email_piping'] || $heskSettings['pop3']) && $heskSettings['strip_quoted']) {
|
||||
$msg = $hesklang['EMAIL_HR'] . "\n\n" . $msg;
|
||||
}
|
||||
} elseif (strpos($msg, '%%MESSAGE_NO_ATTACHMENTS%%') !== false) {
|
||||
if ($html) {
|
||||
$htmlMessage = nl2br($ticket->message);
|
||||
$msg = str_replace('%%MESSAGE_NO_ATTACHMENTS%%', $htmlMessage, $msg);
|
||||
} else {
|
||||
$plainTextMessage = $ticket->message;
|
||||
|
||||
$messageHtml = $ticket->usesHtml;
|
||||
|
||||
if (count($ticket->replies) > 0) {
|
||||
$lastReply = end($ticket->replies);
|
||||
$messageHtml = $lastReply->usesHtml;
|
||||
}
|
||||
|
||||
if ($messageHtml) {
|
||||
if (!function_exists('convert_html_to_text')) {
|
||||
require(__DIR__ . '/../../../inc/html2text/html2text.php');
|
||||
}
|
||||
$plainTextMessage = convert_html_to_text($plainTextMessage);
|
||||
$plainTextMessage = fix_newlines($plainTextMessage);
|
||||
}
|
||||
$msg = str_replace('%%MESSAGE_NO_ATTACHMENTS%%', $plainTextMessage, $msg);
|
||||
}
|
||||
}
|
||||
|
||||
return $msg;
|
||||
}
|
||||
}
|
65
api/BusinessLogic/Emails/EmailTemplateRetriever.php
Normal file
65
api/BusinessLogic/Emails/EmailTemplateRetriever.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
class EmailTemplateRetriever {
|
||||
/**
|
||||
* @var $validTemplates EmailTemplate[]
|
||||
*/
|
||||
private $validTemplates;
|
||||
|
||||
function __construct() {
|
||||
$this->validTemplates = array();
|
||||
$this->initializeArray();
|
||||
}
|
||||
|
||||
const FORGOT_TICKET_ID = 0;
|
||||
const NEW_REPLY_BY_STAFF = 1;
|
||||
const NEW_TICKET = 2;
|
||||
const VERIFY_EMAIL = 3;
|
||||
const TICKET_CLOSED = 4;
|
||||
const CATEGORY_MOVED = 5;
|
||||
const NEW_REPLY_BY_CUSTOMER = 6;
|
||||
const NEW_TICKET_STAFF = 7;
|
||||
const TICKET_ASSIGNED_TO_YOU = 8;
|
||||
const NEW_PM = 9;
|
||||
const NEW_NOTE = 10;
|
||||
const RESET_PASSWORD = 11;
|
||||
const CALENDAR_REMINDER = 12;
|
||||
const OVERDUE_TICKET = 13;
|
||||
|
||||
function initializeArray() {
|
||||
if (count($this->validTemplates) > 0) {
|
||||
//-- Map already built
|
||||
return;
|
||||
}
|
||||
|
||||
$this->validTemplates[self::FORGOT_TICKET_ID] = new EmailTemplate(false, 'forgot_ticket_id');
|
||||
$this->validTemplates[self::NEW_REPLY_BY_STAFF] = new EmailTemplate(false, 'new_reply_by_staff');
|
||||
$this->validTemplates[self::NEW_TICKET] = new EmailTemplate(false, 'new_ticket', 'ticket_received');
|
||||
$this->validTemplates[self::VERIFY_EMAIL] = new EmailTemplate(false, 'verify_email');
|
||||
$this->validTemplates[self::TICKET_CLOSED] = new EmailTemplate(false, 'ticket_closed');
|
||||
$this->validTemplates[self::CATEGORY_MOVED] = new EmailTemplate(true, 'category_moved');
|
||||
$this->validTemplates[self::NEW_REPLY_BY_CUSTOMER] = new EmailTemplate(true, 'new_reply_by_customer');
|
||||
$this->validTemplates[self::NEW_TICKET_STAFF] = new EmailTemplate(true, 'new_ticket_staff');
|
||||
$this->validTemplates[self::TICKET_ASSIGNED_TO_YOU] = new EmailTemplate(true, 'ticket_assigned_to_you');
|
||||
$this->validTemplates[self::NEW_PM] = new EmailTemplate(true, 'new_pm');
|
||||
$this->validTemplates[self::NEW_NOTE] = new EmailTemplate(true, 'new_note');
|
||||
$this->validTemplates[self::RESET_PASSWORD] = new EmailTemplate(true, 'reset_password');
|
||||
$this->validTemplates[self::CALENDAR_REMINDER] = new EmailTemplate(true, 'reset_password');
|
||||
$this->validTemplates[self::OVERDUE_TICKET] = new EmailTemplate(true, 'overdue_ticket');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $templateId
|
||||
* @return EmailTemplate|null
|
||||
*/
|
||||
function getTemplate($templateId) {
|
||||
if (isset($this->validTemplates[$templateId])) {
|
||||
return $this->validTemplates[$templateId];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
71
api/BusinessLogic/Emails/MailgunEmailSender.php
Normal file
71
api/BusinessLogic/Emails/MailgunEmailSender.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Attachment;
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use Mailgun\Mailgun;
|
||||
|
||||
class MailgunEmailSender implements EmailSender {
|
||||
function sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $sendAsHtml) {
|
||||
$mailgunArray = array();
|
||||
|
||||
$mailgunArray['from'] = $heskSettings['noreply_mail']; // Email Address
|
||||
if ($heskSettings['noreply_name'] !== null && $heskSettings['noreply_name'] !== '') {
|
||||
$mailgunArray['from'] = "{$heskSettings['noreply_name']} <{$heskSettings['noreply_mail']}>"; // Name and address
|
||||
}
|
||||
|
||||
$mailgunArray['to'] = implode(',', $emailBuilder->to);
|
||||
|
||||
if ($emailBuilder->cc !== null) {
|
||||
$mailgunArray['cc'] = implode(',', $emailBuilder->cc);
|
||||
}
|
||||
|
||||
if ($emailBuilder->bcc !== null) {
|
||||
$mailgunArray['bcc'] = implode(',', $emailBuilder->bcc);
|
||||
}
|
||||
|
||||
$mailgunArray['subject'] = $emailBuilder->subject;
|
||||
$mailgunArray['text'] = $emailBuilder->message;
|
||||
|
||||
if ($sendAsHtml) {
|
||||
$mailgunArray['html'] = $emailBuilder->htmlMessage;
|
||||
}
|
||||
|
||||
$mailgunAttachments = array();
|
||||
if ($emailBuilder->attachments !== null) {
|
||||
foreach ($emailBuilder->attachments as $attachment) {
|
||||
$mailgunAttachments[] = array(
|
||||
'remoteName' => $attachment->fileName,
|
||||
'filePath' => __DIR__ . '/../../../' . $heskSettings['attach_dir'] . '/' . $attachment->savedName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$result = $this->sendMessage($mailgunArray, $mailgunAttachments, $modsForHeskSettings);
|
||||
|
||||
|
||||
if (isset($result->http_response_code)
|
||||
&& $result->http_response_code === 200) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function sendMessage($mailgunArray, $attachments, $modsForHeskSettings) {
|
||||
$messageClient = new Mailgun($modsForHeskSettings['mailgun_api_key']);
|
||||
|
||||
$mailgunAttachments = array();
|
||||
if (count($attachments) > 0) {
|
||||
$mailgunAttachments = array(
|
||||
'attachment' => $attachments
|
||||
);
|
||||
}
|
||||
|
||||
$result = $messageClient->sendMessage($modsForHeskSettings['mailgun_domain'], $mailgunArray, $mailgunAttachments);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
33
api/BusinessLogic/Emails/ParsedEmailProperties.php
Normal file
33
api/BusinessLogic/Emails/ParsedEmailProperties.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: mkoch
|
||||
* Date: 2/28/2017
|
||||
* Time: 9:36 PM
|
||||
*/
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
class ParsedEmailProperties {
|
||||
function __construct($subject, $message, $htmlMessage) {
|
||||
$this->subject = $subject;
|
||||
$this->message = $message;
|
||||
$this->htmlMessage = $htmlMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var $subject string
|
||||
*/
|
||||
public $subject;
|
||||
|
||||
/**
|
||||
* @var $message string
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* @var $htmlMessage string
|
||||
*/
|
||||
public $htmlMessage;
|
||||
}
|
10
api/BusinessLogic/Exceptions/AccessViolationException.php
Normal file
10
api/BusinessLogic/Exceptions/AccessViolationException.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
class AccessViolationException extends ApiFriendlyException {
|
||||
function __construct($message) {
|
||||
parent::__construct($message, 'Access Exception', 403);
|
||||
}
|
||||
}
|
25
api/BusinessLogic/Exceptions/ApiFriendlyException.php
Normal file
25
api/BusinessLogic/Exceptions/ApiFriendlyException.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
class ApiFriendlyException extends Exception {
|
||||
public $title;
|
||||
public $httpResponseCode;
|
||||
|
||||
/**
|
||||
* ApiFriendlyException constructor.
|
||||
* @param string $message
|
||||
* @param string $title
|
||||
* @param int $httpResponseCode
|
||||
*/
|
||||
function __construct($message, $title, $httpResponseCode) {
|
||||
$this->title = $title;
|
||||
$this->httpResponseCode = $httpResponseCode;
|
||||
|
||||
parent::__construct($message);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: mkoch
|
||||
* Date: 2/22/2017
|
||||
* Time: 10:00 PM
|
||||
*/
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
class EmailTemplateNotFoundException extends ApiFriendlyException {
|
||||
function __construct($emailTemplate, $language) {
|
||||
parent::__construct(sprintf("The email template '%s' was not found for the language '%s'", $emailTemplate, $language),
|
||||
'Email Template Not Found!', 400);
|
||||
}
|
||||
}
|
10
api/BusinessLogic/Exceptions/InternalUseOnlyException.php
Normal file
10
api/BusinessLogic/Exceptions/InternalUseOnlyException.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
class InternalUseOnlyException extends ApiFriendlyException {
|
||||
function __construct() {
|
||||
parent::__construct("This endpoint can only be used internally", "Internal Use Only", 401);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
class InvalidAuthenticationTokenException extends ApiFriendlyException {
|
||||
public function __construct() {
|
||||
parent::__construct('The X-Auth-Token is invalid. The token must be for an active helpdesk user.',
|
||||
'Security Exception',
|
||||
401);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: mkoch
|
||||
* Date: 2/23/2017
|
||||
* Time: 8:13 PM
|
||||
*/
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
class InvalidEmailTemplateException extends ApiFriendlyException {
|
||||
function __construct($template) {
|
||||
parent::__construct(sprintf("The email template '%s' is invalid", $template), 'Invalid Email Template', 400);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
class MissingAuthenticationTokenException extends ApiFriendlyException {
|
||||
function __construct() {
|
||||
parent::__construct("An 'X-Auth-Token' is required for all requests",
|
||||
'Security Exception',
|
||||
400);
|
||||
}
|
||||
}
|
16
api/BusinessLogic/Exceptions/SessionNotActiveException.php
Normal file
16
api/BusinessLogic/Exceptions/SessionNotActiveException.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: cokoch
|
||||
* Date: 5/2/2017
|
||||
* Time: 12:28 PM
|
||||
*/
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
class SessionNotActiveException extends ApiFriendlyException {
|
||||
function __construct() {
|
||||
parent::__construct("You must be logged in to call internal API methods", "Authentication Required", 401);
|
||||
}
|
||||
}
|
21
api/BusinessLogic/Exceptions/ValidationException.php
Normal file
21
api/BusinessLogic/Exceptions/ValidationException.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
use BusinessLogic\ValidationModel;
|
||||
use Exception;
|
||||
|
||||
class ValidationException extends ApiFriendlyException {
|
||||
/**
|
||||
* ValidationException constructor.
|
||||
* @param ValidationModel $validationModel The validation model
|
||||
* @throws Exception If the validationModel's errorKeys is empty
|
||||
*/
|
||||
function __construct($validationModel) {
|
||||
if (count($validationModel->errorKeys) === 0) {
|
||||
throw new Exception('Tried to throw a ValidationException, but the validation model was valid or had 0 error keys!');
|
||||
}
|
||||
|
||||
parent::__construct(implode(",", $validationModel->errorKeys), "Validation Failed. Error keys are available in the message section.", 400);
|
||||
}
|
||||
}
|
29
api/BusinessLogic/Helpers.php
Normal file
29
api/BusinessLogic/Helpers.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic;
|
||||
|
||||
|
||||
class Helpers {
|
||||
static function getHeader($key) {
|
||||
$headers = getallheaders();
|
||||
|
||||
$uppercaseHeaders = array();
|
||||
foreach ($headers as $header => $value) {
|
||||
$uppercaseHeaders[strtoupper($header)] = $value;
|
||||
}
|
||||
|
||||
return isset($uppercaseHeaders[$key])
|
||||
? $uppercaseHeaders[$key]
|
||||
: NULL;
|
||||
}
|
||||
|
||||
static function hashToken($token) {
|
||||
return hash('sha512', $token);
|
||||
}
|
||||
|
||||
static function safeArrayGet($array, $key) {
|
||||
return $array !== null && array_key_exists($key, $array)
|
||||
? $array[$key]
|
||||
: null;
|
||||
}
|
||||
}
|
30
api/BusinessLogic/Navigation/CustomNavElement.php
Normal file
30
api/BusinessLogic/Navigation/CustomNavElement.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
|
||||
class CustomNavElement {
|
||||
/* @var $id int*/
|
||||
public $id;
|
||||
|
||||
/* @var $text string[] */
|
||||
public $text;
|
||||
|
||||
/* @var $subtext string[]|null */
|
||||
public $subtext;
|
||||
|
||||
/* @var $imageUrl string|null */
|
||||
public $imageUrl;
|
||||
|
||||
/* @var $fontIcon string|null */
|
||||
public $fontIcon;
|
||||
|
||||
/* @var $place int */
|
||||
public $place;
|
||||
|
||||
/* @var $url string */
|
||||
public $url;
|
||||
|
||||
/* @var $sort int */
|
||||
public $sort;
|
||||
}
|
70
api/BusinessLogic/Navigation/CustomNavElementHandler.php
Normal file
70
api/BusinessLogic/Navigation/CustomNavElementHandler.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
// TODO Test!
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use DataAccess\Navigation\CustomNavElementGateway;
|
||||
|
||||
class CustomNavElementHandler {
|
||||
/* @var $customNavElementGateway CustomNavElementGateway */
|
||||
private $customNavElementGateway;
|
||||
|
||||
function __construct($customNavElementGateway) {
|
||||
$this->customNavElementGateway = $customNavElementGateway;
|
||||
}
|
||||
|
||||
|
||||
function getAllCustomNavElements($heskSettings) {
|
||||
return $this->customNavElementGateway->getAllCustomNavElements($heskSettings);
|
||||
}
|
||||
|
||||
function getCustomNavElement($id, $heskSettings) {
|
||||
$elements = $this->getAllCustomNavElements($heskSettings);
|
||||
|
||||
foreach ($elements as $element) {
|
||||
if ($element->id === intval($id)) {
|
||||
return output($element);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ApiFriendlyException("Custom nav element {$id} not found!", "Element Not Found", 404);
|
||||
}
|
||||
|
||||
function deleteCustomNavElement($id, $heskSettings) {
|
||||
$this->customNavElementGateway->deleteCustomNavElement($id, $heskSettings);
|
||||
$this->customNavElementGateway->resortAllElements($heskSettings);
|
||||
}
|
||||
|
||||
function saveCustomNavElement($element, $heskSettings) {
|
||||
$this->customNavElementGateway->saveCustomNavElement($element, $heskSettings);
|
||||
}
|
||||
|
||||
function createCustomNavElement($element, $heskSettings) {
|
||||
$element = $this->customNavElementGateway->createCustomNavElement($element, $heskSettings);
|
||||
$this->customNavElementGateway->resortAllElements($heskSettings);
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
function sortCustomNavElement($elementId, $direction, $heskSettings) {
|
||||
/* @var $element CustomNavElement */
|
||||
$elements = $this->customNavElementGateway->getAllCustomNavElements($heskSettings);
|
||||
$elementToChange = null;
|
||||
foreach ($elements as $element) {
|
||||
if ($element->id === intval($elementId)) {
|
||||
$elementToChange = $element;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($direction === Direction::UP) {
|
||||
$elementToChange->sort -= 15;
|
||||
} else {
|
||||
$elementToChange->sort += 15;
|
||||
}
|
||||
|
||||
$this->customNavElementGateway->saveCustomNavElement($elementToChange, $heskSettings);
|
||||
$this->customNavElementGateway->resortAllElements($heskSettings);
|
||||
}
|
||||
}
|
10
api/BusinessLogic/Navigation/CustomNavElementPlace.php
Normal file
10
api/BusinessLogic/Navigation/CustomNavElementPlace.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
|
||||
class CustomNavElementPlace {
|
||||
const HOMEPAGE_BLOCK = 1;
|
||||
const CUSTOMER_NAVIGATION = 2;
|
||||
const ADMIN_NAVIGATION = 3;
|
||||
}
|
9
api/BusinessLogic/Navigation/Direction.php
Normal file
9
api/BusinessLogic/Navigation/Direction.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
|
||||
class Direction {
|
||||
const UP = 'up';
|
||||
const DOWN = 'down';
|
||||
}
|
52
api/BusinessLogic/Security/BanRetriever.php
Normal file
52
api/BusinessLogic/Security/BanRetriever.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
use DataAccess\Security\BanGateway;
|
||||
|
||||
class BanRetriever {
|
||||
/**
|
||||
* @var BanGateway
|
||||
*/
|
||||
private $banGateway;
|
||||
|
||||
function __construct($banGateway) {
|
||||
$this->banGateway = $banGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $email
|
||||
* @param $heskSettings
|
||||
* @return bool
|
||||
*/
|
||||
function isEmailBanned($email, $heskSettings) {
|
||||
|
||||
$bannedEmails = $this->banGateway->getEmailBans($heskSettings);
|
||||
|
||||
foreach ($bannedEmails as $bannedEmail) {
|
||||
if ($bannedEmail->email === $email) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ip int the IP address, converted beforehand using ip2long()
|
||||
* @param $heskSettings
|
||||
* @return bool
|
||||
*/
|
||||
function isIpAddressBanned($ip, $heskSettings) {
|
||||
$bannedIps = $this->banGateway->getIpBans($heskSettings);
|
||||
|
||||
foreach ($bannedIps as $bannedIp) {
|
||||
if ($bannedIp->ipFrom <= $ip && $bannedIp->ipTo >= $ip) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
26
api/BusinessLogic/Security/BannedEmail.php
Normal file
26
api/BusinessLogic/Security/BannedEmail.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class BannedEmail {
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $email;
|
||||
|
||||
/**
|
||||
* @var int|null The user who banned the email, or null if the user was deleted
|
||||
*/
|
||||
public $bannedById;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $dateBanned;
|
||||
}
|
36
api/BusinessLogic/Security/BannedIp.php
Normal file
36
api/BusinessLogic/Security/BannedIp.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class BannedIp {
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var int the lower bound of the IP address range
|
||||
*/
|
||||
public $ipFrom;
|
||||
|
||||
/**
|
||||
* @var int the upper bound of the IP address range
|
||||
*/
|
||||
public $ipTo;
|
||||
|
||||
/**
|
||||
* @var string the display of the IP ban to be shown to the user
|
||||
*/
|
||||
public $ipDisplay;
|
||||
|
||||
/**
|
||||
* @var int|null The user who banned the IP, or null if the user was deleted
|
||||
*/
|
||||
public $bannedById;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $dateBanned;
|
||||
}
|
110
api/BusinessLogic/Security/UserContext.php
Normal file
110
api/BusinessLogic/Security/UserContext.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class UserContext {
|
||||
/* @var $id int */
|
||||
public $id;
|
||||
|
||||
/* @var $username string */
|
||||
public $username;
|
||||
|
||||
/* @var $admin bool */
|
||||
public $admin;
|
||||
|
||||
/* @var $name string */
|
||||
public $name;
|
||||
|
||||
/* @var $email string */
|
||||
public $email;
|
||||
|
||||
/* @var $signature string */
|
||||
public $signature;
|
||||
|
||||
/* @var $language string|null */
|
||||
public $language;
|
||||
|
||||
/* @var $categories int[] */
|
||||
public $categories;
|
||||
|
||||
/* @var $permissions string[] */
|
||||
public $permissions;
|
||||
|
||||
/* @var UserContextPreferences */
|
||||
public $preferences;
|
||||
|
||||
/* @var UserContextNotifications */
|
||||
public $notificationSettings;
|
||||
|
||||
/* @var $autoAssign bool */
|
||||
public $autoAssign;
|
||||
|
||||
/* @var $ratingNegative int */
|
||||
public $ratingNegative;
|
||||
|
||||
/* @var $ratingPositive int */
|
||||
public $ratingPositive;
|
||||
|
||||
/* @var $rating float */
|
||||
public $rating;
|
||||
|
||||
/* @var $totalNumberOfReplies int */
|
||||
public $totalNumberOfReplies;
|
||||
|
||||
/* @var $active bool */
|
||||
public $active;
|
||||
|
||||
/**
|
||||
* Builds a user context based on the current session. **The session must be active!**
|
||||
* @param $dataRow array the $_SESSION superglobal or the hesk_users result set
|
||||
* @return UserContext the built user context
|
||||
*/
|
||||
static function fromDataRow($dataRow) {
|
||||
$userContext = new UserContext();
|
||||
$userContext->id = intval($dataRow['id']);
|
||||
$userContext->username = $dataRow['user'];
|
||||
$userContext->admin = boolval($dataRow['isadmin']);
|
||||
$userContext->name = $dataRow['name'];
|
||||
$userContext->email = $dataRow['email'];
|
||||
$userContext->signature = $dataRow['signature'];
|
||||
$userContext->language = $dataRow['language'];
|
||||
if (is_array($dataRow['categories'])) {
|
||||
$userContext->categories = $dataRow['categories'];
|
||||
} else {
|
||||
$userContext->categories = explode(',', $dataRow['categories']);
|
||||
}
|
||||
$userContext->permissions = explode(',', $dataRow['heskprivileges']);
|
||||
$userContext->autoAssign = boolval($dataRow['autoassign']);
|
||||
$userContext->ratingNegative = intval($dataRow['ratingneg']);
|
||||
$userContext->ratingPositive = intval($dataRow['ratingpos']);
|
||||
$userContext->rating = floatval($dataRow['rating']);
|
||||
$userContext->totalNumberOfReplies = intval($dataRow['replies']);
|
||||
$userContext->active = boolval($dataRow['active']);
|
||||
|
||||
$preferences = new UserContextPreferences();
|
||||
$preferences->afterReply = intval($dataRow['afterreply']);
|
||||
$preferences->autoStartTimeWorked = boolval($dataRow['autostart']);
|
||||
$preferences->autoreload = intval($dataRow['autoreload']);
|
||||
$preferences->defaultNotifyCustomerNewTicket = boolval($dataRow['notify_customer_new']);
|
||||
$preferences->defaultNotifyCustomerReply = boolval($dataRow['notify_customer_reply']);
|
||||
$preferences->showSuggestedKnowledgebaseArticles = boolval($dataRow['show_suggested']);
|
||||
$preferences->defaultCalendarView = intval($dataRow['default_calendar_view']);
|
||||
$preferences->defaultTicketView = $dataRow['default_list'];
|
||||
$userContext->preferences = $preferences;
|
||||
|
||||
$notifications = new UserContextNotifications();
|
||||
$notifications->newUnassigned = boolval($dataRow['notify_new_unassigned']);
|
||||
$notifications->newAssignedToMe = boolval($dataRow['notify_new_my']);
|
||||
$notifications->replyUnassigned = boolval($dataRow['notify_reply_unassigned']);
|
||||
$notifications->replyToMe = boolval($dataRow['notify_reply_my']);
|
||||
$notifications->ticketAssignedToMe = boolval($dataRow['notify_assigned']);
|
||||
$notifications->privateMessage = boolval($dataRow['notify_pm']);
|
||||
$notifications->noteOnTicketAssignedToMe = boolval($dataRow['notify_note']);
|
||||
$notifications->noteOnTicketNotAssignedToMe = boolval($dataRow['notify_note_unassigned']);
|
||||
$notifications->overdueTicketUnassigned = boolval($dataRow['notify_overdue_unassigned']);
|
||||
$userContext->notificationSettings = $notifications;
|
||||
|
||||
return $userContext;
|
||||
}
|
||||
}
|
87
api/BusinessLogic/Security/UserContextBuilder.php
Normal file
87
api/BusinessLogic/Security/UserContextBuilder.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\InvalidAuthenticationTokenException;
|
||||
use BusinessLogic\Exceptions\MissingAuthenticationTokenException;
|
||||
use BusinessLogic\Helpers;
|
||||
use DataAccess\Security\UserGateway;
|
||||
|
||||
class UserContextBuilder {
|
||||
/**
|
||||
* @var UserGateway
|
||||
*/
|
||||
private $userGateway;
|
||||
|
||||
function __construct($userGateway) {
|
||||
$this->userGateway = $userGateway;
|
||||
}
|
||||
|
||||
function buildUserContext($authToken, $heskSettings) {
|
||||
$NULL_OR_EMPTY_STRING = 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e';
|
||||
|
||||
$hashedToken = Helpers::hashToken($authToken);
|
||||
|
||||
if ($hashedToken === $NULL_OR_EMPTY_STRING) {
|
||||
throw new MissingAuthenticationTokenException();
|
||||
}
|
||||
|
||||
$userRow = $this->userGateway->getUserForAuthToken($hashedToken, $heskSettings);
|
||||
|
||||
if ($userRow === null) {
|
||||
throw new InvalidAuthenticationTokenException();
|
||||
}
|
||||
|
||||
return UserContext::fromDataRow($userRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a user context based on the current session. **The session must be active!**
|
||||
* @param $dataRow array the $_SESSION superglobal or the hesk_users result set
|
||||
* @return UserContext the built user context
|
||||
*/
|
||||
function fromDataRow($dataRow) {
|
||||
$userContext = new UserContext();
|
||||
$userContext->id = $dataRow['id'];
|
||||
$userContext->username = $dataRow['user'];
|
||||
$userContext->admin = $dataRow['isadmin'];
|
||||
$userContext->name = $dataRow['name'];
|
||||
$userContext->email = $dataRow['email'];
|
||||
$userContext->signature = $dataRow['signature'];
|
||||
$userContext->language = $dataRow['language'];
|
||||
$userContext->categories = explode(',', $dataRow['categories']);
|
||||
$userContext->permissions = explode(',', $dataRow['heskprivileges']);
|
||||
$userContext->autoAssign = $dataRow['autoassign'];
|
||||
$userContext->ratingNegative = $dataRow['ratingneg'];
|
||||
$userContext->ratingPositive = $dataRow['ratingpos'];
|
||||
$userContext->rating = $dataRow['rating'];
|
||||
$userContext->totalNumberOfReplies = $dataRow['replies'];
|
||||
$userContext->active = $dataRow['active'];
|
||||
|
||||
$preferences = new UserContextPreferences();
|
||||
$preferences->afterReply = $dataRow['afterreply'];
|
||||
$preferences->autoStartTimeWorked = $dataRow['autostart'];
|
||||
$preferences->autoreload = $dataRow['autoreload'];
|
||||
$preferences->defaultNotifyCustomerNewTicket = $dataRow['notify_customer_new'];
|
||||
$preferences->defaultNotifyCustomerReply = $dataRow['notify_customer_reply'];
|
||||
$preferences->showSuggestedKnowledgebaseArticles = $dataRow['show_suggested'];
|
||||
$preferences->defaultCalendarView = $dataRow['default_calendar_view'];
|
||||
$preferences->defaultTicketView = $dataRow['default_list'];
|
||||
$userContext->preferences = $preferences;
|
||||
|
||||
$notifications = new UserContextNotifications();
|
||||
$notifications->newUnassigned = $dataRow['notify_new_unassigned'];
|
||||
$notifications->newAssignedToMe = $dataRow['notify_new_my'];
|
||||
$notifications->replyUnassigned = $dataRow['notify_reply_unassigned'];
|
||||
$notifications->replyToMe = $dataRow['notify_reply_my'];
|
||||
$notifications->ticketAssignedToMe = $dataRow['notify_assigned'];
|
||||
$notifications->privateMessage = $dataRow['notify_pm'];
|
||||
$notifications->noteOnTicketAssignedToMe = $dataRow['notify_note'];
|
||||
$notifications->noteOnTicketNotAssignedToMe = $dataRow['notify_note_unassigned'];
|
||||
$notifications->overdueTicketUnassigned = $dataRow['notify_overdue_unassigned'];
|
||||
$userContext->notificationSettings = $notifications;
|
||||
|
||||
return $userContext;
|
||||
}
|
||||
}
|
16
api/BusinessLogic/Security/UserContextNotifications.php
Normal file
16
api/BusinessLogic/Security/UserContextNotifications.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class UserContextNotifications {
|
||||
public $newUnassigned;
|
||||
public $newAssignedToMe;
|
||||
public $replyUnassigned;
|
||||
public $replyToMe;
|
||||
public $ticketAssignedToMe;
|
||||
public $privateMessage;
|
||||
public $noteOnTicketAssignedToMe;
|
||||
public $noteOnTicketNotAssignedToMe;
|
||||
public $overdueTicketUnassigned;
|
||||
}
|
15
api/BusinessLogic/Security/UserContextPreferences.php
Normal file
15
api/BusinessLogic/Security/UserContextPreferences.php
Normal file
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class UserContextPreferences {
|
||||
public $afterReply;
|
||||
public $autoStartTimeWorked;
|
||||
public $autoreload;
|
||||
public $defaultNotifyCustomerNewTicket;
|
||||
public $defaultNotifyCustomerReply;
|
||||
public $showSuggestedKnowledgebaseArticles;
|
||||
public $defaultCalendarView;
|
||||
public $defaultTicketView;
|
||||
}
|
17
api/BusinessLogic/Security/UserPrivilege.php
Normal file
17
api/BusinessLogic/Security/UserPrivilege.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: mkoch
|
||||
* Date: 3/12/2017
|
||||
* Time: 12:11 PM
|
||||
*/
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class UserPrivilege {
|
||||
const CAN_VIEW_TICKETS = 'can_view_tickets';
|
||||
const CAN_REPLY_TO_TICKETS = 'can_reply_tickets';
|
||||
const CAN_EDIT_TICKETS = 'can_edit_tickets';
|
||||
const CAN_DELETE_TICKETS = 'can_del_tickets';
|
||||
}
|
50
api/BusinessLogic/Security/UserToTicketChecker.php
Normal file
50
api/BusinessLogic/Security/UserToTicketChecker.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use DataAccess\Security\UserGateway;
|
||||
|
||||
class UserToTicketChecker {
|
||||
/* @var $userGateway UserGateway */
|
||||
private $userGateway;
|
||||
|
||||
function __construct($userGateway) {
|
||||
$this->userGateway = $userGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $user UserContext
|
||||
* @param $ticket Ticket
|
||||
* @param $heskSettings array
|
||||
* @param $extraPermissions UserPrivilege[] additional privileges the user needs besides CAN_VIEW_TICKETS (if not an admin)
|
||||
* for this to return true
|
||||
* @return bool
|
||||
*/
|
||||
function isTicketAccessibleToUser($user, $ticket, $heskSettings, $extraPermissions = array()) {
|
||||
if ($user->admin === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!in_array($ticket->categoryId, $user->categories)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$categoryManagerId = $this->userGateway->getManagerForCategory($ticket->categoryId, $heskSettings);
|
||||
|
||||
if ($user->id === $categoryManagerId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$extraPermissions[] = UserPrivilege::CAN_VIEW_TICKETS;
|
||||
|
||||
foreach ($extraPermissions as $permission) {
|
||||
if (!in_array($permission, $user->permissions)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
21
api/BusinessLogic/Settings/ApiChecker.php
Normal file
21
api/BusinessLogic/Settings/ApiChecker.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Settings;
|
||||
|
||||
|
||||
use DataAccess\Settings\ModsForHeskSettingsGateway;
|
||||
|
||||
class ApiChecker {
|
||||
/* @var $modsForHeskSettingsGateway ModsForHeskSettingsGateway */
|
||||
private $modsForHeskSettingsGateway;
|
||||
|
||||
function __construct($modsForHeskSettingsGateway) {
|
||||
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
|
||||
}
|
||||
|
||||
function isApiEnabled($heskSettings) {
|
||||
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
|
||||
|
||||
return intval($modsForHeskSettings['public_api']) === 1;
|
||||
}
|
||||
}
|
86
api/BusinessLogic/Settings/SettingsRetriever.php
Normal file
86
api/BusinessLogic/Settings/SettingsRetriever.php
Normal file
@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Settings;
|
||||
|
||||
// TODO Test!
|
||||
use DataAccess\Settings\ModsForHeskSettingsGateway;
|
||||
|
||||
class SettingsRetriever {
|
||||
/* @var $modsForHeskSettingsGateway ModsForHeskSettingsGateway */
|
||||
private $modsForHeskSettingsGateway;
|
||||
|
||||
function __construct($modsForHeskSettingsGateway) {
|
||||
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
|
||||
}
|
||||
|
||||
private static $settingsToNotReturn = array(
|
||||
'webmaster_email',
|
||||
'noreply_email',
|
||||
'noreply_name',
|
||||
'db_.*',
|
||||
'admin_dir',
|
||||
'attach_dir',
|
||||
'cache_dir',
|
||||
'autoclose',
|
||||
'autologin',
|
||||
'autoassign',
|
||||
'secimg_.*',
|
||||
'recaptcha_.*',
|
||||
'question_.*',
|
||||
'attempt_.*',
|
||||
'reset_pass',
|
||||
'x_frame_opt',
|
||||
'force_ssl',
|
||||
'imap.*',
|
||||
'smtp.*',
|
||||
'email_piping',
|
||||
'pop3.*',
|
||||
'loop.*',
|
||||
'email_providers',
|
||||
'notify_.*',
|
||||
'alink',
|
||||
'submit_notice',
|
||||
'online',
|
||||
'online_min',
|
||||
'modsForHeskVersion',
|
||||
'use_mailgun',
|
||||
'mailgun.*',
|
||||
'kb_attach_dir',
|
||||
'public_api',
|
||||
'custom_fields',
|
||||
'hesk_version',
|
||||
'hesk_license',
|
||||
);
|
||||
|
||||
/**
|
||||
* @param $heskSettings array
|
||||
* @return array
|
||||
*/
|
||||
function getAllSettings($heskSettings) {
|
||||
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
|
||||
$settingsToReturn = array();
|
||||
|
||||
foreach ($heskSettings as $key => $value) {
|
||||
if ($this->isPermittedKey($key)) {
|
||||
$settingsToReturn[$key] = $value;
|
||||
}
|
||||
}
|
||||
foreach ($modsForHeskSettings as $key => $value) {
|
||||
if ($this->isPermittedKey($key)) {
|
||||
$settingsToReturn[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $settingsToReturn;
|
||||
}
|
||||
|
||||
private function isPermittedKey($key) {
|
||||
foreach (self::$settingsToNotReturn as $setting) {
|
||||
if (preg_match("/{$setting}/", $key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
11
api/BusinessLogic/Statuses/Closable.php
Normal file
11
api/BusinessLogic/Statuses/Closable.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Statuses;
|
||||
|
||||
|
||||
class Closable {
|
||||
const YES = "yes";
|
||||
const STAFF_ONLY = "sonly";
|
||||
const CUSTOMERS_ONLY = "conly";
|
||||
const NO = "no";
|
||||
}
|
30
api/BusinessLogic/Statuses/DefaultStatusForAction.php
Normal file
30
api/BusinessLogic/Statuses/DefaultStatusForAction.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Statuses;
|
||||
|
||||
|
||||
class DefaultStatusForAction {
|
||||
const NEW_TICKET = "IsNewTicketStatus";
|
||||
const CLOSED_STATUS = "IsClosed";
|
||||
const CLOSED_BY_CLIENT = "IsClosedByClient";
|
||||
const CUSTOMER_REPLY = "IsCustomerReplyStatus";
|
||||
const CLOSED_BY_STAFF = "IsStaffClosedOption";
|
||||
const REOPENED_BY_STAFF = "IsStaffReopenedStatus";
|
||||
const DEFAULT_STAFF_REPLY = "IsDefaultStaffReplyStatus";
|
||||
const LOCKED_TICKET = "LockedTicketStatus";
|
||||
const AUTOCLOSE_STATUS = "IsAutocloseOption";
|
||||
|
||||
static function getAll() {
|
||||
return array(
|
||||
self::NEW_TICKET,
|
||||
self::CLOSED_STATUS,
|
||||
self::CLOSED_BY_CLIENT,
|
||||
self::CUSTOMER_REPLY,
|
||||
self::CLOSED_BY_STAFF,
|
||||
self::REOPENED_BY_STAFF,
|
||||
self::DEFAULT_STAFF_REPLY,
|
||||
self::LOCKED_TICKET,
|
||||
self::AUTOCLOSE_STATUS
|
||||
);
|
||||
}
|
||||
}
|
72
api/BusinessLogic/Statuses/Status.php
Normal file
72
api/BusinessLogic/Statuses/Status.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Statuses;
|
||||
|
||||
|
||||
class Status {
|
||||
static function fromDatabase($row, $languageRs) {
|
||||
$status = new Status();
|
||||
$status->id = intval($row['ID']);
|
||||
$status->textColor = $row['TextColor'];
|
||||
$status->defaultActions = array();
|
||||
|
||||
foreach (DefaultStatusForAction::getAll() as $defaultStatus) {
|
||||
$status = self::addDefaultStatusIfSet($status, $row, $defaultStatus);
|
||||
}
|
||||
|
||||
$status->closable = $row['Closable'];
|
||||
|
||||
$localizedLanguages = array();
|
||||
while ($languageRow = hesk_dbFetchAssoc($languageRs)) {
|
||||
$localizedLanguages[$languageRow['language']] = $languageRow['text'];
|
||||
}
|
||||
$status->localizedNames = $localizedLanguages;
|
||||
$status->sort = intval($row['sort']);
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $status Status
|
||||
* @param $row array
|
||||
* @param $key string
|
||||
* @return Status
|
||||
*/
|
||||
private static function addDefaultStatusIfSet($status, $row, $key) {
|
||||
if ($row[$key]) {
|
||||
$status->defaultActions[] = $key;
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var $id int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var $textColor string
|
||||
*/
|
||||
public $textColor;
|
||||
|
||||
/**
|
||||
* @var $defaultActions DefaultStatusForAction[]
|
||||
*/
|
||||
public $defaultActions;
|
||||
|
||||
/**
|
||||
* @var $closable Closable
|
||||
*/
|
||||
public $closable;
|
||||
|
||||
/**
|
||||
* @var $sort int
|
||||
*/
|
||||
public $sort;
|
||||
|
||||
/**
|
||||
* @var $name string[]
|
||||
*/
|
||||
public $localizedNames;
|
||||
}
|
20
api/BusinessLogic/Statuses/StatusRetriever.php
Normal file
20
api/BusinessLogic/Statuses/StatusRetriever.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Statuses;
|
||||
|
||||
|
||||
use DataAccess\Statuses\StatusGateway;
|
||||
|
||||
// TODO Test!
|
||||
class StatusRetriever {
|
||||
/* @var $statusGateway StatusGateway */
|
||||
private $statusGateway;
|
||||
|
||||
function __construct($statusGateway) {
|
||||
$this->statusGateway = $statusGateway;
|
||||
}
|
||||
|
||||
function getAllStatuses($heskSettings) {
|
||||
return $this->statusGateway->getStatuses($heskSettings);
|
||||
}
|
||||
}
|
21
api/BusinessLogic/Tickets/Attachment.php
Normal file
21
api/BusinessLogic/Tickets/Attachment.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
class Attachment {
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $fileName;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $savedName;
|
||||
}
|
47
api/BusinessLogic/Tickets/Autoassigner.php
Normal file
47
api/BusinessLogic/Tickets/Autoassigner.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Security\UserContext;
|
||||
use BusinessLogic\Security\UserPrivilege;
|
||||
use DataAccess\Categories\CategoryGateway;
|
||||
use DataAccess\Security\UserGateway;
|
||||
|
||||
class Autoassigner {
|
||||
/* @var $categoryGateway CategoryGateway */
|
||||
private $categoryGateway;
|
||||
|
||||
/* @var $userGateway UserGateway */
|
||||
private $userGateway;
|
||||
|
||||
function __construct($categoryGateway, $userGateway) {
|
||||
$this->categoryGateway = $categoryGateway;
|
||||
$this->userGateway = $userGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $categoryId int
|
||||
* @param $heskSettings array
|
||||
* @return UserContext the user who is assigned, or null if no user should be assigned
|
||||
*/
|
||||
function getNextUserForTicket($categoryId, $heskSettings) {
|
||||
if (!$heskSettings['autoassign']) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$potentialUsers = $this->userGateway->getUsersByNumberOfOpenTicketsForAutoassign($heskSettings);
|
||||
|
||||
foreach ($potentialUsers as $potentialUser) {
|
||||
if ($potentialUser->admin ||
|
||||
(in_array($categoryId, $potentialUser->categories) &&
|
||||
in_array(UserPrivilege::CAN_VIEW_TICKETS, $potentialUser->permissions) &&
|
||||
in_array(UserPrivilege::CAN_REPLY_TO_TICKETS, $potentialUser->permissions))) {
|
||||
return $potentialUser;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
80
api/BusinessLogic/Tickets/CreateTicketByCustomerModel.php
Normal file
80
api/BusinessLogic/Tickets/CreateTicketByCustomerModel.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
class CreateTicketByCustomerModel {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $email;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
public $priority;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
public $category;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $subject;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $html;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $customFields;
|
||||
|
||||
/**
|
||||
* @var string[]|null The latitude/longitude pair, or relevant error code (E-#)
|
||||
*/
|
||||
public $location;
|
||||
|
||||
/**
|
||||
* @var int[]|null
|
||||
*/
|
||||
public $suggestedKnowledgebaseArticleIds;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $userAgent;
|
||||
|
||||
/**
|
||||
* @var int[]|null
|
||||
*/
|
||||
public $screenResolution;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
public $ipAddress;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $language;
|
||||
|
||||
/**
|
||||
* @var $sendEmailToCustomer bool
|
||||
*/
|
||||
public $sendEmailToCustomer;
|
||||
}
|
17
api/BusinessLogic/Tickets/CreatedTicketModel.php
Normal file
17
api/BusinessLogic/Tickets/CreatedTicketModel.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
class CreatedTicketModel {
|
||||
/* @var $ticket Ticket */
|
||||
public $ticket;
|
||||
|
||||
/* @var $emailVerified bool */
|
||||
public $emailVerified;
|
||||
|
||||
function __construct($ticket, $emailVerified) {
|
||||
$this->ticket = $ticket;
|
||||
$this->emailVerified = $emailVerified;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets\CustomFields;
|
||||
|
||||
|
||||
class CustomFieldValidator {
|
||||
static function isCustomFieldInCategory($customFieldId, $categoryId, $staff, $heskSettings) {
|
||||
$customField = $heskSettings['custom_fields']["custom{$customFieldId}"];
|
||||
|
||||
if (!$customField['use'] ||
|
||||
(!$staff && $customField['use'] === 2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return count($customField['category']) === 0 ||
|
||||
in_array($categoryId, $customField['category']);
|
||||
}
|
||||
}
|
30
api/BusinessLogic/Tickets/EditTicketModel.php
Normal file
30
api/BusinessLogic/Tickets/EditTicketModel.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
class EditTicketModel {
|
||||
/* @var $id int */
|
||||
public $id;
|
||||
|
||||
/* @var $language string */
|
||||
public $language;
|
||||
|
||||
/* @var $subject string */
|
||||
public $subject;
|
||||
|
||||
/* @var $name string */
|
||||
public $name;
|
||||
|
||||
/* @var $emails string */
|
||||
public $email;
|
||||
|
||||
/* @var $message string */
|
||||
public $message;
|
||||
|
||||
/* @var $html bool */
|
||||
public $html;
|
||||
|
||||
/* @var $customFields string[] */
|
||||
public $customFields;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets\Exceptions;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
class UnableToGenerateTrackingIdException extends Exception {
|
||||
public function __construct() {
|
||||
parent::__construct("Error generating a unique ticket ID.");
|
||||
}
|
||||
}
|
132
api/BusinessLogic/Tickets/NewTicketValidator.php
Normal file
132
api/BusinessLogic/Tickets/NewTicketValidator.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Categories\CategoryRetriever;
|
||||
use BusinessLogic\Security\BanRetriever;
|
||||
use BusinessLogic\Tickets\CustomFields\CustomFieldValidator;
|
||||
use BusinessLogic\ValidationModel;
|
||||
use BusinessLogic\Validators;
|
||||
use Core\Constants\CustomField;
|
||||
|
||||
class NewTicketValidator {
|
||||
/**
|
||||
* @var $categoryRetriever CategoryRetriever
|
||||
*/
|
||||
private $categoryRetriever;
|
||||
/**
|
||||
* @var $banRetriever BanRetriever
|
||||
*/
|
||||
private $banRetriever;
|
||||
/**
|
||||
* @var $ticketValidators TicketValidators
|
||||
*/
|
||||
private $ticketValidators;
|
||||
|
||||
function __construct($categoryRetriever, $banRetriever, $ticketValidators) {
|
||||
$this->categoryRetriever = $categoryRetriever;
|
||||
$this->banRetriever = $banRetriever;
|
||||
$this->ticketValidators = $ticketValidators;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ticketRequest CreateTicketByCustomerModel
|
||||
* @param $heskSettings array HESK settings
|
||||
* @return ValidationModel If errorKeys is empty, validation successful. Otherwise invalid ticket
|
||||
*/
|
||||
function validateNewTicketForCustomer($ticketRequest, $heskSettings, $userContext) {
|
||||
$TICKET_PRIORITY_CRITICAL = 0;
|
||||
|
||||
$validationModel = new ValidationModel();
|
||||
|
||||
if ($ticketRequest->name === NULL || $ticketRequest->name == '') {
|
||||
$validationModel->errorKeys[] = 'NO_NAME';
|
||||
}
|
||||
|
||||
if (!Validators::validateEmail($ticketRequest->email, $heskSettings['multi_eml'], false)) {
|
||||
$validationModel->errorKeys[] = 'INVALID_OR_MISSING_EMAIL';
|
||||
}
|
||||
|
||||
$categoryId = intval($ticketRequest->category);
|
||||
if ($categoryId < 1) {
|
||||
$validationModel->errorKeys[] = 'NO_CATEGORY';
|
||||
} else {
|
||||
$categoryExists = array_key_exists($categoryId, $this->categoryRetriever->getAllCategories($heskSettings, $userContext));
|
||||
if (!$categoryExists) {
|
||||
$validationModel->errorKeys[] = 'CATEGORY_DOES_NOT_EXIST';
|
||||
}
|
||||
}
|
||||
|
||||
//-- TODO assert priority exists
|
||||
|
||||
if ($heskSettings['cust_urgency'] && intval($ticketRequest->priority) === $TICKET_PRIORITY_CRITICAL) {
|
||||
$validationModel->errorKeys[] = 'CRITICAL_PRIORITY_FORBIDDEN';
|
||||
}
|
||||
|
||||
if ($heskSettings['require_subject'] === 1 &&
|
||||
($ticketRequest->subject === NULL || $ticketRequest->subject === '')) {
|
||||
$validationModel->errorKeys[] = 'SUBJECT_REQUIRED';
|
||||
}
|
||||
|
||||
if ($heskSettings['require_message'] === 1 &&
|
||||
($ticketRequest->message === NULL || $ticketRequest->message === '')) {
|
||||
$validationModel->errorKeys[] = 'MESSAGE_REQUIRED';
|
||||
}
|
||||
|
||||
foreach ($heskSettings['custom_fields'] as $key => $value) {
|
||||
$customFieldNumber = intval(str_replace('custom', '', $key));
|
||||
|
||||
//TODO test this
|
||||
if (!array_key_exists($customFieldNumber, $ticketRequest->customFields)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value['use'] == 1 && CustomFieldValidator::isCustomFieldInCategory($customFieldNumber, intval($ticketRequest->category), false, $heskSettings)) {
|
||||
$custom_field_value = $ticketRequest->customFields[$customFieldNumber];
|
||||
if (empty($custom_field_value)) {
|
||||
$validationModel->errorKeys[] = "CUSTOM_FIELD_{$customFieldNumber}_INVALID::NO_VALUE";
|
||||
continue;
|
||||
}
|
||||
switch($value['type']) {
|
||||
case CustomField::DATE:
|
||||
if (!preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $custom_field_value)) {
|
||||
$validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $customFieldNumber . '_INVALID::INVALID_DATE';
|
||||
} else {
|
||||
// Actually validate based on range
|
||||
$date = strtotime($custom_field_value . ' t00:00:00');
|
||||
$dmin = strlen($value['value']['dmin']) ? strtotime($value['value']['dmin'] . ' t00:00:00') : false;
|
||||
$dmax = strlen($value['value']['dmax']) ? strtotime($value['value']['dmax'] . ' t00:00:00') : false;
|
||||
|
||||
if ($dmin && $dmin > $date) {
|
||||
$validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $customFieldNumber . '_INVALID::DATE_BEFORE_MIN::MIN:' . date('Y-m-d', $dmin) . '::ENTERED:' . date('Y-m-d', $date);
|
||||
} elseif ($dmax && $dmax < $date) {
|
||||
$validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $customFieldNumber . '_INVALID::DATE_AFTER_MAX::MAX:' . date('Y-m-d', $dmax) . '::ENTERED:' . date('Y-m-d', $date);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CustomField::EMAIL:
|
||||
if (!Validators::validateEmail($custom_field_value, $value['value']['multiple'], false)) {
|
||||
$validationModel->errorKeys[] = "CUSTOM_FIELD_{$customFieldNumber}_INVALID::INVALID_EMAIL";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->banRetriever->isEmailBanned($ticketRequest->email, $heskSettings)) {
|
||||
$validationModel->errorKeys[] = 'EMAIL_BANNED';
|
||||
}
|
||||
|
||||
if ($this->ticketValidators->isCustomerAtMaxTickets($ticketRequest->email, $heskSettings)) {
|
||||
$validationModel->errorKeys[] = 'EMAIL_AT_MAX_OPEN_TICKETS';
|
||||
}
|
||||
|
||||
if ($ticketRequest->language === null ||
|
||||
$ticketRequest->language === '') {
|
||||
$validationModel->errorKeys[] = 'MISSING_LANGUAGE';
|
||||
}
|
||||
|
||||
return $validationModel;
|
||||
}
|
||||
}
|
62
api/BusinessLogic/Tickets/Reply.php
Normal file
62
api/BusinessLogic/Tickets/Reply.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: mkoch
|
||||
* Date: 2/28/2017
|
||||
* Time: 9:17 PM
|
||||
*/
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
class Reply {
|
||||
/**
|
||||
* @var $id int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var $ticketId int
|
||||
*/
|
||||
public $ticketId;
|
||||
|
||||
/**
|
||||
* @var $replierName string
|
||||
*/
|
||||
public $replierName;
|
||||
|
||||
/**
|
||||
* @var $message string
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* @var $dateCreated string
|
||||
*/
|
||||
public $dateCreated;
|
||||
|
||||
/**
|
||||
* @var $attachments Attachment[]
|
||||
*/
|
||||
public $attachments;
|
||||
|
||||
/**
|
||||
* @var $staffId int|null
|
||||
*/
|
||||
public $staffId;
|
||||
|
||||
/**
|
||||
* @var $rating int|null
|
||||
*/
|
||||
public $rating;
|
||||
|
||||
/**
|
||||
* @var $isRead bool
|
||||
*/
|
||||
public $isRead;
|
||||
|
||||
/**
|
||||
* @var $usesHtml bool
|
||||
*/
|
||||
public $usesHtml;
|
||||
}
|
14
api/BusinessLogic/Tickets/StageTicket.php
Normal file
14
api/BusinessLogic/Tickets/StageTicket.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: mkoch
|
||||
* Date: 2/20/2017
|
||||
* Time: 10:03 PM
|
||||
*/
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
class StageTicket extends Ticket {
|
||||
//-- Nothing here, just an indicator that it is a StageTicket and not a regular Ticket
|
||||
}
|
359
api/BusinessLogic/Tickets/Ticket.php
Normal file
359
api/BusinessLogic/Tickets/Ticket.php
Normal file
@ -0,0 +1,359 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
class Ticket {
|
||||
static function fromDatabaseRow($row, $linkedTicketsRs, $repliesRs, $heskSettings) {
|
||||
$ticket = new Ticket();
|
||||
$ticket->id = intval($row['id']);
|
||||
$ticket->trackingId = $row['trackid'];
|
||||
$ticket->name = $row['name'];
|
||||
if ($row['email'] !== null) {
|
||||
$emails = str_replace(';', ',', $row['email']);
|
||||
$emails = explode(',', strtolower($emails));
|
||||
$ticket->email = array_filter($emails);
|
||||
}
|
||||
$ticket->categoryId = intval($row['category']);
|
||||
$ticket->priorityId = intval($row['priority']);
|
||||
$ticket->subject = $row['subject'];
|
||||
$ticket->message = $row['message'];
|
||||
$ticket->dateCreated = $row['dt'];
|
||||
$ticket->lastChanged = $row['lastchange'];
|
||||
$ticket->firstReplyDate = $row['firstreply'];
|
||||
$ticket->closedDate = $row['closedat'];
|
||||
|
||||
if (trim($row['articles']) !== '') {
|
||||
$suggestedArticles = explode(',', $row['articles']);
|
||||
|
||||
$articlesAsInts = array();
|
||||
foreach ($suggestedArticles as $article) {
|
||||
$articlesAsInts[] = intval($article);
|
||||
}
|
||||
$ticket->suggestedArticles = $articlesAsInts;
|
||||
}
|
||||
|
||||
$ticket->ipAddress = $row['ip'];
|
||||
$ticket->language = $row['language'];
|
||||
$ticket->statusId = intval($row['status']);
|
||||
$ticket->openedBy = intval($row['openedby']);
|
||||
$ticket->firstReplyByUserId = $row['firstreplyby'] === null ? null : intval($row['firstreplyby']);
|
||||
$ticket->closedByUserId = $row['closedby'] === null ? null : intval($row['closedby']);
|
||||
$ticket->numberOfReplies = intval($row['replies']);
|
||||
$ticket->numberOfStaffReplies = intval($row['staffreplies']);
|
||||
$ticket->ownerId = intval($row['owner']);
|
||||
$ticket->timeWorked = $row['time_worked'];
|
||||
$ticket->lastReplyBy = intval($row['lastreplier']);
|
||||
$ticket->lastReplier = $row['replierid'] === null ? null : intval($row['replierid']);
|
||||
$ticket->archived = intval($row['archive']) === 1;
|
||||
$ticket->locked = intval($row['locked']) === 1;
|
||||
|
||||
if (trim($row['attachments']) !== '') {
|
||||
$attachments = explode(',', $row['attachments']);
|
||||
$attachmentArray = array();
|
||||
foreach ($attachments as $attachment) {
|
||||
if (trim($attachment) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attachmentRow = explode('#', $attachment);
|
||||
$attachmentModel = new Attachment();
|
||||
|
||||
$attachmentModel->id = $attachmentRow[0];
|
||||
$attachmentModel->fileName = $attachmentRow[1];
|
||||
$attachmentModel->savedName = $attachmentRow[2];
|
||||
|
||||
$attachmentArray[] = $attachmentModel;
|
||||
}
|
||||
$ticket->attachments = $attachmentArray;
|
||||
}
|
||||
|
||||
if (trim($row['merged']) !== '') {
|
||||
$ticket->mergedTicketIds = explode(',', $row['merged']);
|
||||
}
|
||||
|
||||
$ticket->auditTrailHtml = $row['history'];
|
||||
|
||||
$ticket->customFields = array();
|
||||
foreach ($heskSettings['custom_fields'] as $key => $value) {
|
||||
if ($value['use'] && hesk_is_custom_field_in_category($key, intval($ticket->categoryId))) {
|
||||
$ticket->customFields[str_replace('custom', '', $key)] = $row[$key];
|
||||
}
|
||||
}
|
||||
|
||||
while ($linkedTicketsRow = hesk_dbFetchAssoc($linkedTicketsRs)) {
|
||||
$ticket->linkedTicketIds[] = $linkedTicketsRow['id'];
|
||||
}
|
||||
|
||||
if ($row['latitude'] !== '' && $row['longitude'] !== '') {
|
||||
$ticket->location = array();
|
||||
$ticket->location[0] = $row['latitude'];
|
||||
$ticket->location[1] = $row['longitude'];
|
||||
}
|
||||
|
||||
$ticket->usesHtml = intval($row['html']) === 1;
|
||||
|
||||
if ($row['user_agent'] !== null && trim($row['user_agent']) !== '') {
|
||||
$ticket->userAgent = $row['user_agent'];
|
||||
}
|
||||
|
||||
if ($row['screen_resolution_height'] !== null && $row['screen_resolution_width'] !== null){
|
||||
$ticket->screenResolution = array();
|
||||
$ticket->screenResolution[0] = $row['screen_resolution_width'];
|
||||
$ticket->screenResolution[1] = $row['screen_resolution_height'];
|
||||
}
|
||||
|
||||
$ticket->dueDate = $row['due_date'];
|
||||
$ticket->dueDateOverdueEmailSent = $row['overdue_email_sent'] !== null && intval($row['overdue_email_sent']) === 1;
|
||||
|
||||
$replies = array();
|
||||
while ($replyRow = hesk_dbFetchAssoc($repliesRs)) {
|
||||
$reply = new Reply();
|
||||
$reply->id = $replyRow['id'];
|
||||
$reply->ticketId = $replyRow['replyto'];
|
||||
$reply->replierName = $replyRow['name'];
|
||||
$reply->message = $replyRow['message'];
|
||||
$reply->dateCreated = $replyRow['dt'];
|
||||
|
||||
if (trim($replyRow['attachments']) !== '') {
|
||||
$attachments = explode(',', $replyRow['attachments']);
|
||||
$attachmentArray = array();
|
||||
foreach ($attachments as $attachment) {
|
||||
if (trim($attachment) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attachmentRow = explode('#', $attachment);
|
||||
$attachmentModel = new Attachment();
|
||||
|
||||
$attachmentModel->id = $attachmentRow[0];
|
||||
$attachmentModel->fileName = $attachmentRow[1];
|
||||
$attachmentModel->savedName = $attachmentRow[2];
|
||||
|
||||
$attachmentArray[] = $attachmentModel;
|
||||
}
|
||||
$reply->attachments = $attachmentArray;
|
||||
}
|
||||
|
||||
$reply->staffId = $replyRow['staffid'] > 0 ? $replyRow['staffid'] : null;
|
||||
$reply->rating = $replyRow['rating'];
|
||||
$reply->isRead = $replyRow['read'] === '1';
|
||||
$reply->usesHtml = $replyRow['html'] === '1';
|
||||
|
||||
$replies[$reply->id] = $reply;
|
||||
}
|
||||
$ticket->replies = $replies;
|
||||
|
||||
return $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $trackingId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var array|null
|
||||
*/
|
||||
public $email;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $categoryId;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $priorityId;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $subject;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $dateCreated;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $lastChanged;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $firstReplyDate;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $closedDate;
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
public $suggestedArticles = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $ipAddress;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $language;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $statusId;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $openedBy;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
public $firstReplyByUserId;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
public $closedByUserId;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $numberOfReplies;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $numberOfStaffReplies;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
public $ownerId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $timeWorked;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $lastReplyBy;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
public $lastReplier;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $archived;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $locked;
|
||||
|
||||
/**
|
||||
* @var Attachment[]
|
||||
*/
|
||||
public $attachments = array();
|
||||
|
||||
function getAttachmentsForDatabase() {
|
||||
$attachmentArray = array();
|
||||
|
||||
if ($this->attachments !== null) {
|
||||
foreach ($this->attachments as $attachment) {
|
||||
$attachmentArray[] = $attachment->id . '#' . $attachment->fileName . '#' . $attachment->savedName;
|
||||
}
|
||||
}
|
||||
|
||||
return implode(',', $attachmentArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
public $mergedTicketIds = array();
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $auditTrailHtml;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $customFields;
|
||||
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
public $linkedTicketIds = array();
|
||||
|
||||
/**
|
||||
* @var float[]|null
|
||||
*/
|
||||
public $location;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $usesHtml;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $userAgent;
|
||||
|
||||
/**
|
||||
* 0 => width
|
||||
* 1 => height
|
||||
*
|
||||
* @var int[]|null
|
||||
*/
|
||||
public $screenResolution;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $dueDate;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
public $dueDateOverdueEmailSent;
|
||||
|
||||
/**
|
||||
* @var Reply[]
|
||||
*/
|
||||
public $replies = array();
|
||||
}
|
194
api/BusinessLogic/Tickets/TicketCreator.php
Normal file
194
api/BusinessLogic/Tickets/TicketCreator.php
Normal file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
use BusinessLogic\Emails\Addressees;
|
||||
use BusinessLogic\Emails\EmailSenderHelper;
|
||||
use BusinessLogic\Emails\EmailTemplateRetriever;
|
||||
use BusinessLogic\Exceptions\ValidationException;
|
||||
use BusinessLogic\Statuses\DefaultStatusForAction;
|
||||
use DataAccess\Security\UserGateway;
|
||||
use DataAccess\Settings\ModsForHeskSettingsGateway;
|
||||
use DataAccess\Statuses\StatusGateway;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class TicketCreator {
|
||||
/**
|
||||
* @var $newTicketValidator NewTicketValidator
|
||||
*/
|
||||
private $newTicketValidator;
|
||||
|
||||
/**
|
||||
* @var $trackingIdGenerator TrackingIdGenerator
|
||||
*/
|
||||
private $trackingIdGenerator;
|
||||
|
||||
/**
|
||||
* @var $autoassigner Autoassigner
|
||||
*/
|
||||
private $autoassigner;
|
||||
|
||||
/**
|
||||
* @var $statusGateway StatusGateway
|
||||
*/
|
||||
private $statusGateway;
|
||||
|
||||
/**
|
||||
* @var $ticketGateway TicketGateway
|
||||
*/
|
||||
private $ticketGateway;
|
||||
|
||||
/**
|
||||
* @var $verifiedEmailChecker VerifiedEmailChecker
|
||||
*/
|
||||
private $verifiedEmailChecker;
|
||||
|
||||
/**
|
||||
* @var $emailSenderHelper EmailSenderHelper
|
||||
*/
|
||||
private $emailSenderHelper;
|
||||
|
||||
/**
|
||||
* @var $userGateway UserGateway
|
||||
*/
|
||||
private $userGateway;
|
||||
|
||||
/* @var $modsForHeskSettingsGateway ModsForHeskSettingsGateway */
|
||||
private $modsForHeskSettingsGateway;
|
||||
|
||||
function __construct($newTicketValidator, $trackingIdGenerator, $autoassigner, $statusGateway, $ticketGateway,
|
||||
$verifiedEmailChecker, $emailSenderHelper, $userGateway, $modsForHeskSettingsGateway) {
|
||||
$this->newTicketValidator = $newTicketValidator;
|
||||
$this->trackingIdGenerator = $trackingIdGenerator;
|
||||
$this->autoassigner = $autoassigner;
|
||||
$this->statusGateway = $statusGateway;
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
$this->verifiedEmailChecker = $verifiedEmailChecker;
|
||||
$this->emailSenderHelper = $emailSenderHelper;
|
||||
$this->userGateway = $userGateway;
|
||||
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ticket attachments are <b>NOT</b> handled here!
|
||||
*
|
||||
* @param $ticketRequest CreateTicketByCustomerModel
|
||||
* @param $heskSettings array HESK settings
|
||||
* @param $userContext
|
||||
* @return CreatedTicketModel The newly created ticket along with if the email is verified or not
|
||||
* @throws ValidationException When a required field in $ticket_request is missing
|
||||
* @throws \Exception When the default status for new tickets is not found
|
||||
*/
|
||||
function createTicketByCustomer($ticketRequest, $heskSettings, $userContext) {
|
||||
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
|
||||
|
||||
$validationModel = $this->newTicketValidator->validateNewTicketForCustomer($ticketRequest, $heskSettings, $userContext);
|
||||
|
||||
if (count($validationModel->errorKeys) > 0) {
|
||||
// Validation failed
|
||||
throw new ValidationException($validationModel);
|
||||
}
|
||||
|
||||
$emailVerified = true;
|
||||
if ($modsForHeskSettings['customer_email_verification_required']) {
|
||||
$emailVerified = $this->verifiedEmailChecker->isEmailVerified($ticketRequest->email, $heskSettings);
|
||||
}
|
||||
|
||||
// Create the ticket
|
||||
$ticket = $emailVerified
|
||||
? new Ticket()
|
||||
: new StageTicket();
|
||||
$ticket->trackingId = $this->trackingIdGenerator->generateTrackingId($heskSettings);
|
||||
|
||||
if ($heskSettings['autoassign']) {
|
||||
$ticket->ownerId = $this->autoassigner->getNextUserForTicket($ticketRequest->category, $heskSettings)->id;
|
||||
}
|
||||
|
||||
// Transform one-to-one properties
|
||||
$ticket->name = $ticketRequest->name;
|
||||
$ticket->email = $ticketRequest->email;
|
||||
$ticket->priorityId = $ticketRequest->priority;
|
||||
$ticket->categoryId = $ticketRequest->category;
|
||||
$ticket->subject = $ticketRequest->subject;
|
||||
$ticket->message = $ticketRequest->message;
|
||||
$ticket->usesHtml = $ticketRequest->html;
|
||||
$ticket->customFields = $ticketRequest->customFields;
|
||||
$ticket->location = $ticketRequest->location;
|
||||
$ticket->suggestedArticles = $ticketRequest->suggestedKnowledgebaseArticleIds;
|
||||
$ticket->userAgent = $ticketRequest->userAgent;
|
||||
$ticket->screenResolution = $ticketRequest->screenResolution;
|
||||
$ticket->ipAddress = $ticketRequest->ipAddress;
|
||||
$ticket->language = $ticketRequest->language;
|
||||
|
||||
$status = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings);
|
||||
|
||||
if ($status === null) {
|
||||
throw new \Exception("Could not find the default status for a new ticket!");
|
||||
}
|
||||
$ticket->statusId = $status->id;
|
||||
|
||||
$ticketGatewayGeneratedFields = $this->ticketGateway->createTicket($ticket, $emailVerified, $heskSettings);
|
||||
|
||||
$ticket->dateCreated = $ticketGatewayGeneratedFields->dateCreated;
|
||||
$ticket->lastChanged = $ticketGatewayGeneratedFields->dateModified;
|
||||
$ticket->archived = false;
|
||||
$ticket->locked = false;
|
||||
$ticket->id = $ticketGatewayGeneratedFields->id;
|
||||
$ticket->openedBy = 0;
|
||||
$ticket->numberOfReplies = 0;
|
||||
$ticket->numberOfStaffReplies = 0;
|
||||
$ticket->timeWorked = '00:00:00';
|
||||
$ticket->lastReplier = 0;
|
||||
|
||||
$addressees = new Addressees();
|
||||
$addressees->to = $this->getAddressees($ticket->email);
|
||||
|
||||
if ($ticketRequest->sendEmailToCustomer && $emailVerified) {
|
||||
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_TICKET, $ticketRequest->language, $addressees, $ticket, $heskSettings, $modsForHeskSettings);
|
||||
} else if ($modsForHeskSettings['customer_email_verification_required'] && !$emailVerified) {
|
||||
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::VERIFY_EMAIL, $ticketRequest->language, $addressees, $ticket, $heskSettings, $modsForHeskSettings);
|
||||
}
|
||||
|
||||
if ($ticket->ownerId !== null) {
|
||||
$owner = $this->userGateway->getUserById($ticket->ownerId, $heskSettings);
|
||||
|
||||
if ($owner->notificationSettings->newAssignedToMe) {
|
||||
$addressees = new Addressees();
|
||||
$addressees->to = array($owner->email);
|
||||
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::TICKET_ASSIGNED_TO_YOU, $ticketRequest->language, $addressees, $ticket, $heskSettings, $modsForHeskSettings);
|
||||
}
|
||||
} else {
|
||||
// TODO Test
|
||||
$usersToBeNotified = $this->userGateway->getUsersForNewTicketNotification($heskSettings);
|
||||
|
||||
foreach ($usersToBeNotified as $user) {
|
||||
if ($user->admin || in_array($ticket->categoryId, $user->categories)) {
|
||||
$this->sendEmailToStaff($user, $ticket, $heskSettings, $modsForHeskSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new CreatedTicketModel($ticket, $emailVerified);
|
||||
}
|
||||
|
||||
private function getAddressees($emailAddress) {
|
||||
if ($emailAddress === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$emails = str_replace(';', ',', $emailAddress);
|
||||
|
||||
return explode(',', $emails);
|
||||
}
|
||||
|
||||
private function sendEmailToStaff($user, $ticket, $heskSettings, $modsForHeskSettings) {
|
||||
$addressees = new Addressees();
|
||||
$addressees->to = array($user->email);
|
||||
$language = $user->language !== null && trim($user->language) !== ''
|
||||
? $user->language
|
||||
: $heskSettings['language'];
|
||||
|
||||
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_TICKET_STAFF, $language,
|
||||
$addressees, $ticket, $heskSettings, $modsForHeskSettings);
|
||||
}
|
||||
}
|
59
api/BusinessLogic/Tickets/TicketDeleter.php
Normal file
59
api/BusinessLogic/Tickets/TicketDeleter.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Attachments\AttachmentHandler;
|
||||
use BusinessLogic\Exceptions\AccessViolationException;
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Security\UserPrivilege;
|
||||
use BusinessLogic\Security\UserToTicketChecker;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class TicketDeleter {
|
||||
/* @var $ticketGateway TicketGateway */
|
||||
private $ticketGateway;
|
||||
|
||||
/* @var $userToTicketChecker UserToTicketChecker */
|
||||
private $userToTicketChecker;
|
||||
|
||||
/* @var $attachmentHandler AttachmentHandler */
|
||||
private $attachmentHandler;
|
||||
|
||||
function __construct($ticketGateway, $userToTicketChecker, $attachmentHandler) {
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
$this->userToTicketChecker = $userToTicketChecker;
|
||||
$this->attachmentHandler = $attachmentHandler;
|
||||
}
|
||||
|
||||
function deleteTicket($ticketId, $userContext, $heskSettings) {
|
||||
$ticket = $this->ticketGateway->getTicketById($ticketId, $heskSettings);
|
||||
|
||||
if ($ticket === null) {
|
||||
throw new ApiFriendlyException("Ticket {$ticketId} not found!", "Ticket Not Found", 404);
|
||||
}
|
||||
|
||||
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings,
|
||||
array(UserPrivilege::CAN_DELETE_TICKETS))) {
|
||||
throw new AccessViolationException("User does not have access to ticket {$ticketId}");
|
||||
}
|
||||
|
||||
foreach ($ticket->attachments as $attachment) {
|
||||
$this->attachmentHandler->deleteAttachmentFromTicket($ticketId, $attachment->id, $userContext, $heskSettings);
|
||||
}
|
||||
|
||||
foreach ($ticket->replies as $reply) {
|
||||
foreach ($reply->attachments as $attachment) {
|
||||
$this->attachmentHandler->deleteAttachmentFromTicket($ticketId, $attachment->id, $userContext, $heskSettings);
|
||||
}
|
||||
}
|
||||
|
||||
$this->ticketGateway->deleteReplyDraftsForTicket($ticketId, $heskSettings);
|
||||
|
||||
$this->ticketGateway->deleteRepliesForTicket($ticketId, $heskSettings);
|
||||
|
||||
$this->ticketGateway->deleteNotesForTicket($ticketId, $heskSettings);
|
||||
|
||||
$this->ticketGateway->deleteTicket($ticketId, $heskSettings);
|
||||
}
|
||||
}
|
137
api/BusinessLogic/Tickets/TicketEditor.php
Normal file
137
api/BusinessLogic/Tickets/TicketEditor.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\AccessViolationException;
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Exceptions\ValidationException;
|
||||
use BusinessLogic\Security\UserContext;
|
||||
use BusinessLogic\Security\UserPrivilege;
|
||||
use BusinessLogic\Security\UserToTicketChecker;
|
||||
use BusinessLogic\Tickets\CustomFields\CustomFieldValidator;
|
||||
use BusinessLogic\ValidationModel;
|
||||
use BusinessLogic\Validators;
|
||||
use Core\Constants\CustomField;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class TicketEditor {
|
||||
/* @var $ticketGateway TicketGateway */
|
||||
private $ticketGateway;
|
||||
|
||||
/* @var $userToTicketChecker UserToTicketChecker */
|
||||
private $userToTicketChecker;
|
||||
|
||||
function __construct($ticketGateway, $userToTicketChecker) {
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
$this->userToTicketChecker = $userToTicketChecker;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $editTicketModel EditTicketModel
|
||||
* @param $userContext UserContext
|
||||
* @param $heskSettings array
|
||||
* @throws ApiFriendlyException When the ticket isn't found for the ID
|
||||
* @throws \Exception When the user doesn't have access to the ticket
|
||||
*/
|
||||
// TODO Unit Tests
|
||||
function editTicket($editTicketModel, $userContext, $heskSettings) {
|
||||
$ticket = $this->ticketGateway->getTicketById($editTicketModel->id, $heskSettings);
|
||||
|
||||
if ($ticket === null) {
|
||||
throw new ApiFriendlyException("Ticket with ID {$editTicketModel->id} not found!", "Ticket not found", 404);
|
||||
}
|
||||
|
||||
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings, array(UserPrivilege::CAN_EDIT_TICKETS))) {
|
||||
throw new AccessViolationException("User does not have access to ticket {$editTicketModel->id}");
|
||||
}
|
||||
|
||||
$this->validate($editTicketModel, $ticket->categoryId, $heskSettings);
|
||||
|
||||
$ticket->name = $editTicketModel->name;
|
||||
$ticket->email = $editTicketModel->email;
|
||||
$ticket->subject = $editTicketModel->subject;
|
||||
$ticket->message = $editTicketModel->message;
|
||||
$ticket->customFields = $editTicketModel->customFields;
|
||||
|
||||
$this->ticketGateway->updateBasicTicketInfo($ticket, $heskSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $editTicketModel EditTicketModel
|
||||
* @param $categoryId int
|
||||
* @param $heskSettings array
|
||||
* @throws ValidationException When validation fails
|
||||
*/
|
||||
private function validate($editTicketModel, $categoryId, $heskSettings) {
|
||||
$validationModel = new ValidationModel();
|
||||
|
||||
if ($editTicketModel->name === null || trim($editTicketModel->name) === '') {
|
||||
$validationModel->errorKeys[] = 'NO_NAME';
|
||||
}
|
||||
|
||||
if (!Validators::validateEmail($editTicketModel->email, $heskSettings['multi_eml'], false)) {
|
||||
$validationModel->errorKeys[] = 'INVALID_OR_MISSING_EMAIL';
|
||||
}
|
||||
|
||||
if ($heskSettings['require_subject'] === 1 &&
|
||||
($editTicketModel->subject === NULL || $editTicketModel->subject === '')) {
|
||||
$validationModel->errorKeys[] = 'SUBJECT_REQUIRED';
|
||||
}
|
||||
|
||||
if ($heskSettings['require_message'] === 1 &&
|
||||
($editTicketModel->message === NULL || $editTicketModel->message === '')) {
|
||||
$validationModel->errorKeys[] = 'MESSAGE_REQUIRED';
|
||||
}
|
||||
|
||||
foreach ($heskSettings['custom_fields'] as $key => $value) {
|
||||
$customFieldNumber = intval(str_replace('custom', '', $key));
|
||||
|
||||
//TODO test this
|
||||
if ($editTicketModel->customFields === null || !array_key_exists($customFieldNumber, $editTicketModel->customFields)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value['use'] == 1 && CustomFieldValidator::isCustomFieldInCategory($customFieldNumber, intval($categoryId), false, $heskSettings)) {
|
||||
$custom_field_value = $editTicketModel->customFields[$customFieldNumber];
|
||||
if (empty($custom_field_value)) {
|
||||
$validationModel->errorKeys[] = "CUSTOM_FIELD_{$customFieldNumber}_INVALID::NO_VALUE";
|
||||
continue;
|
||||
}
|
||||
switch($value['type']) {
|
||||
case CustomField::DATE:
|
||||
if (!preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $custom_field_value)) {
|
||||
$validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $customFieldNumber . '_INVALID::INVALID_DATE';
|
||||
} else {
|
||||
// Actually validate based on range
|
||||
$date = strtotime($custom_field_value . ' t00:00:00');
|
||||
$dmin = strlen($value['value']['dmin']) ? strtotime($value['value']['dmin'] . ' t00:00:00') : false;
|
||||
$dmax = strlen($value['value']['dmax']) ? strtotime($value['value']['dmax'] . ' t00:00:00') : false;
|
||||
|
||||
if ($dmin && $dmin > $date) {
|
||||
$validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $customFieldNumber . '_INVALID::DATE_BEFORE_MIN::MIN:' . date('Y-m-d', $dmin) . '::ENTERED:' . date('Y-m-d', $date);
|
||||
} elseif ($dmax && $dmax < $date) {
|
||||
$validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $customFieldNumber . '_INVALID::DATE_AFTER_MAX::MAX:' . date('Y-m-d', $dmax) . '::ENTERED:' . date('Y-m-d', $date);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CustomField::EMAIL:
|
||||
if (!Validators::validateEmail($custom_field_value, $value['value']['multiple'], false)) {
|
||||
$validationModel->errorKeys[] = "CUSTOM_FIELD_{$customFieldNumber}_INVALID::INVALID_EMAIL";
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($editTicketModel->language === null ||
|
||||
$editTicketModel->language === '') {
|
||||
$validationModel->errorKeys[] = 'MISSING_LANGUAGE';
|
||||
}
|
||||
|
||||
if (count($validationModel->errorKeys) > 0) {
|
||||
throw new ValidationException($validationModel);
|
||||
}
|
||||
}
|
||||
}
|
10
api/BusinessLogic/Tickets/TicketGatewayGeneratedFields.php
Normal file
10
api/BusinessLogic/Tickets/TicketGatewayGeneratedFields.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
class TicketGatewayGeneratedFields {
|
||||
public $id;
|
||||
public $dateCreated;
|
||||
public $dateModified;
|
||||
}
|
77
api/BusinessLogic/Tickets/TicketRetriever.php
Normal file
77
api/BusinessLogic/Tickets/TicketRetriever.php
Normal file
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\AccessViolationException;
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Exceptions\ValidationException;
|
||||
use BusinessLogic\Security\UserToTicketChecker;
|
||||
use BusinessLogic\ValidationModel;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class TicketRetriever {
|
||||
/**
|
||||
* @var $ticketGateway TicketGateway
|
||||
*/
|
||||
private $ticketGateway;
|
||||
|
||||
/* @var $userToTicketChecker UserToTicketChecker */
|
||||
private $userToTicketChecker;
|
||||
|
||||
function __construct($ticketGateway, $userToTicketChecker) {
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
$this->userToTicketChecker = $userToTicketChecker;
|
||||
}
|
||||
|
||||
//TODO Properly test
|
||||
function getTicketById($id, $heskSettings, $userContext) {
|
||||
$ticket = $this->ticketGateway->getTicketById($id, $heskSettings);
|
||||
|
||||
if ($ticket === null) {
|
||||
throw new ApiFriendlyException("Ticket {$id} not found!", "Ticket Not Found", 404);
|
||||
}
|
||||
|
||||
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings)) {
|
||||
throw new AccessViolationException("User does not have access to ticket {$id}!");
|
||||
}
|
||||
|
||||
return $ticket;
|
||||
}
|
||||
|
||||
function getTicketByTrackingIdAndEmail($trackingId, $emailAddress, $heskSettings) {
|
||||
$this->validate($trackingId, $emailAddress, $heskSettings);
|
||||
|
||||
$ticket = $this->ticketGateway->getTicketByTrackingId($trackingId, $heskSettings);
|
||||
if ($ticket === null) {
|
||||
$ticket = $this->ticketGateway->getTicketByMergedTrackingId($trackingId, $heskSettings);
|
||||
|
||||
if ($ticket === null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($heskSettings['email_view_ticket'] && !in_array($emailAddress, $ticket->email)) {
|
||||
throw new ApiFriendlyException("Email '{$emailAddress}' entered in for ticket '{$trackingId}' does not match!",
|
||||
"Email Does Not Match", 400);
|
||||
}
|
||||
|
||||
return $ticket;
|
||||
}
|
||||
|
||||
private function validate($trackingId, $emailAddress, $heskSettings) {
|
||||
$validationModel = new ValidationModel();
|
||||
|
||||
if ($trackingId === null || trim($trackingId) === '') {
|
||||
$validationModel->errorKeys[] = 'MISSING_TRACKING_ID';
|
||||
}
|
||||
|
||||
if ($heskSettings['email_view_ticket'] && ($emailAddress === null || trim($emailAddress) === '')) {
|
||||
$validationModel->errorKeys[] = 'EMAIL_REQUIRED_AND_MISSING';
|
||||
}
|
||||
|
||||
if (count($validationModel->errorKeys) > 0) {
|
||||
throw new ValidationException($validationModel);
|
||||
}
|
||||
}
|
||||
}
|
30
api/BusinessLogic/Tickets/TicketValidators.php
Normal file
30
api/BusinessLogic/Tickets/TicketValidators.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class TicketValidators {
|
||||
/**
|
||||
* @var $ticketGateway TicketGateway
|
||||
*/
|
||||
private $ticketGateway;
|
||||
|
||||
function __construct($ticketGateway) {
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $customerEmail string The email address
|
||||
* @param $heskSettings array HESK Settings
|
||||
* @return bool true if the user is maxed out on open tickets, false otherwise
|
||||
*/
|
||||
function isCustomerAtMaxTickets($customerEmail, $heskSettings) {
|
||||
if ($heskSettings['max_open'] === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return count($this->ticketGateway->getTicketsByEmail($customerEmail, $heskSettings)) >= $heskSettings['max_open'];
|
||||
}
|
||||
}
|
137
api/BusinessLogic/Tickets/TrackingIdGenerator.php
Normal file
137
api/BusinessLogic/Tickets/TrackingIdGenerator.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Exceptions\UnableToGenerateTrackingIdException;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class TrackingIdGenerator {
|
||||
/**
|
||||
* @var $ticketGateway TicketGateway
|
||||
*/
|
||||
private $ticketGateway;
|
||||
|
||||
function __construct($ticketGateway) {
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $heskSettings array
|
||||
* @return string
|
||||
* @throws UnableToGenerateTrackingIdException
|
||||
*/
|
||||
function generateTrackingId($heskSettings) {
|
||||
$acceptableCharacters = 'AEUYBDGHJLMNPQRSTVWXZ123456789';
|
||||
|
||||
/* Generate raw ID */
|
||||
$trackingId = '';
|
||||
|
||||
/* Let's avoid duplicate ticket ID's, try up to 3 times */
|
||||
for ($i = 1; $i <= 3; $i++) {
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$trackingId .= $acceptableCharacters[mt_rand(0, 29)];
|
||||
}
|
||||
|
||||
$trackingId = $this->formatTrackingId($trackingId);
|
||||
|
||||
/* Check for duplicate IDs */
|
||||
$goodId = !$this->ticketGateway->doesTicketExist($trackingId, $heskSettings);
|
||||
|
||||
if ($goodId) {
|
||||
return $trackingId;
|
||||
}
|
||||
|
||||
/* A duplicate ID has been found! Let's try again (up to 2 more) */
|
||||
$trackingId = '';
|
||||
}
|
||||
|
||||
/* No valid tracking ID, try one more time with microtime() */
|
||||
$trackingId = $acceptableCharacters[mt_rand(0, 29)];
|
||||
$trackingId .= $acceptableCharacters[mt_rand(0, 29)];
|
||||
$trackingId .= $acceptableCharacters[mt_rand(0, 29)];
|
||||
$trackingId .= $acceptableCharacters[mt_rand(0, 29)];
|
||||
$trackingId .= $acceptableCharacters[mt_rand(0, 29)];
|
||||
$trackingId .= substr(microtime(), -5);
|
||||
|
||||
/* Format the ID to the correct shape and check wording */
|
||||
$trackingId = $this->formatTrackingId($trackingId);
|
||||
|
||||
$goodId = !$this->ticketGateway->doesTicketExist($trackingId, $heskSettings);
|
||||
|
||||
if ($goodId) {
|
||||
return $trackingId;
|
||||
}
|
||||
|
||||
throw new UnableToGenerateTrackingIdException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id string
|
||||
* @return string
|
||||
*/
|
||||
private function formatTrackingId($id) {
|
||||
$acceptableCharacters = 'AEUYBDGHJLMNPQRSTVWXZ123456789';
|
||||
|
||||
$replace = $acceptableCharacters[mt_rand(0, 29)];
|
||||
$replace .= mt_rand(1, 9);
|
||||
$replace .= $acceptableCharacters[mt_rand(0, 29)];
|
||||
|
||||
/*
|
||||
Remove 3 letter bad words from ID
|
||||
Possiblitiy: 1:27,000
|
||||
*/
|
||||
$remove = array(
|
||||
'ASS',
|
||||
'CUM',
|
||||
'FAG',
|
||||
'FUK',
|
||||
'GAY',
|
||||
'SEX',
|
||||
'TIT',
|
||||
'XXX',
|
||||
);
|
||||
|
||||
$id = str_replace($remove, $replace, $id);
|
||||
|
||||
/*
|
||||
Remove 4 letter bad words from ID
|
||||
Possiblitiy: 1:810,000
|
||||
*/
|
||||
$remove = array(
|
||||
'ANAL',
|
||||
'ANUS',
|
||||
'BUTT',
|
||||
'CAWK',
|
||||
'CLIT',
|
||||
'COCK',
|
||||
'CRAP',
|
||||
'CUNT',
|
||||
'DICK',
|
||||
'DYKE',
|
||||
'FART',
|
||||
'FUCK',
|
||||
'JAPS',
|
||||
'JERK',
|
||||
'JIZZ',
|
||||
'KNOB',
|
||||
'PISS',
|
||||
'POOP',
|
||||
'SHIT',
|
||||
'SLUT',
|
||||
'SUCK',
|
||||
'TURD',
|
||||
|
||||
// Also, remove words that are known to trigger mod_security
|
||||
'WGET',
|
||||
);
|
||||
|
||||
$replace .= mt_rand(1, 9);
|
||||
$id = str_replace($remove, $replace, $id);
|
||||
|
||||
/* Format the ID string into XXX-XXX-XXXX format for easier readability */
|
||||
$id = $id[0] . $id[1] . $id[2] . '-' . $id[3] . $id[4] . $id[5] . '-' . $id[6] . $id[7] . $id[8] . $id[9];
|
||||
|
||||
return $id;
|
||||
}
|
||||
}
|
27
api/BusinessLogic/Tickets/VerifiedEmailChecker.php
Normal file
27
api/BusinessLogic/Tickets/VerifiedEmailChecker.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: cokoch
|
||||
* Date: 2/20/2017
|
||||
* Time: 12:40 PM
|
||||
*/
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
use DataAccess\Tickets\VerifiedEmailGateway;
|
||||
|
||||
class VerifiedEmailChecker {
|
||||
/**
|
||||
* @var $verifiedEmailGateway VerifiedEmailGateway
|
||||
*/
|
||||
private $verifiedEmailGateway;
|
||||
|
||||
function __construct($verifiedEmailGateway) {
|
||||
$this->verifiedEmailGateway = $verifiedEmailGateway;
|
||||
}
|
||||
|
||||
function isEmailVerified($emailAddress, $heskSettings) {
|
||||
return $this->verifiedEmailGateway->isEmailVerified($emailAddress, $heskSettings);
|
||||
}
|
||||
}
|
14
api/BusinessLogic/ValidationModel.php
Normal file
14
api/BusinessLogic/ValidationModel.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic;
|
||||
|
||||
class ValidationModel {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $errorKeys;
|
||||
|
||||
function __construct() {
|
||||
$this->errorKeys = [];
|
||||
}
|
||||
}
|
123
api/BusinessLogic/Validators.php
Normal file
123
api/BusinessLogic/Validators.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic;
|
||||
|
||||
|
||||
class Validators {
|
||||
/**
|
||||
* @param string $address - the email address
|
||||
* @param array $multiple_emails - true if HESK (or custom field) supports multiple emails
|
||||
* @param bool $return_emails (def. true): return the email address(es). Otherwise a boolean is returned
|
||||
*
|
||||
* @return mixed|null|string - array if multiple valid emails, null if no email and not required, string if valid email
|
||||
*/
|
||||
static function validateEmail($address, $multiple_emails, $return_emails = true) {
|
||||
/* Allow multiple emails to be used? */
|
||||
if ($multiple_emails) {
|
||||
/* Make sure the format is correct */
|
||||
$address = preg_replace('/\s/', '', $address);
|
||||
$address = str_replace(';', ',', $address);
|
||||
|
||||
/* Check if addresses are valid */
|
||||
$all = explode(',', $address);
|
||||
foreach ($all as $k => $v) {
|
||||
if (!self::isValidEmail($v)) {
|
||||
unset($all[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
/* If at least one is found return the value */
|
||||
if (count($all)) {
|
||||
if ($return_emails) {
|
||||
return implode(',', $all);
|
||||
}
|
||||
|
||||
return true;
|
||||
} elseif (!$return_emails) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* Make sure people don't try to enter multiple addresses */
|
||||
$address = str_replace(strstr($address, ','), '', $address);
|
||||
$address = str_replace(strstr($address, ';'), '', $address);
|
||||
$address = trim($address);
|
||||
|
||||
/* Valid address? */
|
||||
if (self::isValidEmail($address)) {
|
||||
if ($return_emails) {
|
||||
return $address;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//-- We shouldn't get here
|
||||
return false;
|
||||
} // END hesk_validateEmail()
|
||||
|
||||
/**
|
||||
* @param $email
|
||||
* @return bool
|
||||
*/
|
||||
static function isValidEmail($email) {
|
||||
/* Check for header injection attempts */
|
||||
if (preg_match("/\r|\n|%0a|%0d/i", $email)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Does it contain an @? */
|
||||
$atIndex = strrpos($email, "@");
|
||||
if ($atIndex === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get local and domain parts */
|
||||
$domain = substr($email, $atIndex + 1);
|
||||
$local = substr($email, 0, $atIndex);
|
||||
$localLen = strlen($local);
|
||||
$domainLen = strlen($domain);
|
||||
|
||||
/* Check local part length */
|
||||
if ($localLen < 1 || $localLen > 64) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check domain part length */
|
||||
if ($domainLen < 1 || $domainLen > 254) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Local part mustn't start or end with a dot */
|
||||
if ($local[0] == '.' || $local[$localLen - 1] == '.') {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Local part mustn't have two consecutive dots*/
|
||||
if (strpos($local, '..') !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check domain part characters */
|
||||
if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Domain part mustn't have two consecutive dots */
|
||||
if (strpos($domain, '..') !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Character not valid in local part unless local part is quoted */
|
||||
if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\", "", $local))) /* " */ {
|
||||
if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\", "", $local))) /* " */ {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* All tests passed, email seems to be OK */
|
||||
return true;
|
||||
} // END hesk_isValidEmail()
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Attachments;
|
||||
|
||||
|
||||
use BusinessLogic\Attachments\AttachmentHandler;
|
||||
use BusinessLogic\Attachments\AttachmentRetriever;
|
||||
use BusinessLogic\Attachments\CreateAttachmentForTicketModel;
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Helpers;
|
||||
use BusinessLogic\Security\UserToTicketChecker;
|
||||
use Controllers\JsonRetriever;
|
||||
|
||||
class StaffTicketAttachmentsController {
|
||||
function get($ticketId, $attachmentId) {
|
||||
global $hesk_settings, $applicationContext, $userContext;
|
||||
|
||||
$this->verifyAttachmentsAreEnabled($hesk_settings);
|
||||
|
||||
/* @var $attachmentRetriever AttachmentRetriever */
|
||||
$attachmentRetriever = $applicationContext->get[AttachmentRetriever::class];
|
||||
|
||||
$contents = $attachmentRetriever->getAttachmentContentsForTicket($ticketId, $attachmentId, $userContext, $hesk_settings);
|
||||
|
||||
output(array('contents' => $contents));
|
||||
}
|
||||
|
||||
private function verifyAttachmentsAreEnabled($heskSettings) {
|
||||
if (!$heskSettings['attachments']['use']) {
|
||||
throw new ApiFriendlyException('Attachments are disabled on this server', 'Attachments Disabled', 404);
|
||||
}
|
||||
}
|
||||
|
||||
function post($ticketId) {
|
||||
global $hesk_settings, $applicationContext, $userContext;
|
||||
|
||||
$this->verifyAttachmentsAreEnabled($hesk_settings);
|
||||
|
||||
/* @var $attachmentHandler AttachmentHandler */
|
||||
$attachmentHandler = $applicationContext->get[AttachmentHandler::class];
|
||||
|
||||
$createAttachmentForTicketModel = $this->createModel(JsonRetriever::getJsonData(), $ticketId);
|
||||
|
||||
$createdAttachment = $attachmentHandler->createAttachmentForTicket(
|
||||
$createAttachmentForTicketModel, $userContext, $hesk_settings);
|
||||
|
||||
return output($createdAttachment, 201);
|
||||
}
|
||||
|
||||
private function createModel($json, $ticketId) {
|
||||
$model = new CreateAttachmentForTicketModel();
|
||||
$model->attachmentContents = Helpers::safeArrayGet($json, 'data');
|
||||
$model->displayName = Helpers::safeArrayGet($json, 'displayName');
|
||||
$model->isEditing = Helpers::safeArrayGet($json, 'isEditing');
|
||||
$model->ticketId = $ticketId;
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
function delete($ticketId, $attachmentId) {
|
||||
global $applicationContext, $hesk_settings, $userContext;
|
||||
|
||||
/* @var $attachmentHandler AttachmentHandler */
|
||||
$attachmentHandler = $applicationContext->get[AttachmentHandler::class];
|
||||
|
||||
$attachmentHandler->deleteAttachmentFromTicket($ticketId, $attachmentId, $userContext, $hesk_settings);
|
||||
|
||||
return http_response_code(204);
|
||||
}
|
||||
}
|
31
api/Controllers/Categories/CategoryController.php
Normal file
31
api/Controllers/Categories/CategoryController.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Categories;
|
||||
|
||||
use BusinessLogic\Categories\CategoryRetriever;
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
|
||||
class CategoryController {
|
||||
function get($id) {
|
||||
$categories = self::getAllCategories();
|
||||
|
||||
if (!isset($categories[$id])) {
|
||||
throw new ApiFriendlyException("Category {$id} not found!", "Category Not Found", 404);
|
||||
}
|
||||
|
||||
output($categories[$id]);
|
||||
}
|
||||
|
||||
static function printAllCategories() {
|
||||
output(self::getAllCategories());
|
||||
}
|
||||
|
||||
private static function getAllCategories() {
|
||||
global $hesk_settings, $applicationContext, $userContext;
|
||||
|
||||
/* @var $categoryRetriever CategoryRetriever */
|
||||
$categoryRetriever = $applicationContext->get[CategoryRetriever::class];
|
||||
|
||||
return $categoryRetriever->getAllCategories($hesk_settings, $userContext);
|
||||
}
|
||||
}
|
23
api/Controllers/InternalApiController.php
Normal file
23
api/Controllers/InternalApiController.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\InternalUseOnlyException;
|
||||
use BusinessLogic\Helpers;
|
||||
|
||||
abstract class InternalApiController {
|
||||
static function staticCheckForInternalUseOnly() {
|
||||
$tokenHeader = Helpers::getHeader('X-AUTH-TOKEN');
|
||||
if ($tokenHeader !== null && trim($tokenHeader) !== '') {
|
||||
throw new InternalUseOnlyException();
|
||||
}
|
||||
}
|
||||
|
||||
function checkForInternalUseOnly() {
|
||||
$tokenHeader = Helpers::getHeader('X-AUTH-TOKEN');
|
||||
if ($tokenHeader !== null && trim($tokenHeader) !== '') {
|
||||
throw new InternalUseOnlyException();
|
||||
}
|
||||
}
|
||||
}
|
16
api/Controllers/JsonRetriever.php
Normal file
16
api/Controllers/JsonRetriever.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers;
|
||||
|
||||
|
||||
class JsonRetriever {
|
||||
/**
|
||||
* Support POST, PUT, and PATCH request (and possibly more)
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
static function getJsonData() {
|
||||
$json = file_get_contents('php://input');
|
||||
return json_decode($json, true);
|
||||
}
|
||||
}
|
101
api/Controllers/Navigation/CustomNavElementController.php
Normal file
101
api/Controllers/Navigation/CustomNavElementController.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Navigation;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Helpers;
|
||||
use BusinessLogic\Navigation\CustomNavElement;
|
||||
use BusinessLogic\Navigation\CustomNavElementHandler;
|
||||
use Controllers\InternalApiController;
|
||||
use Controllers\JsonRetriever;
|
||||
|
||||
class CustomNavElementController extends InternalApiController {
|
||||
static function getAll() {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
self::staticCheckForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
output($handler->getAllCustomNavElements($hesk_settings));
|
||||
}
|
||||
|
||||
static function sort($id, $direction) {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
self::staticCheckForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
$handler->sortCustomNavElement(intval($id), $direction, $hesk_settings);
|
||||
}
|
||||
|
||||
function get($id) {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$this->checkForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
output($handler->getCustomNavElement($id, $hesk_settings));
|
||||
}
|
||||
|
||||
function post() {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$this->checkForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
$data = JsonRetriever::getJsonData();
|
||||
$element = $handler->createCustomNavElement($this->buildElementModel($data), $hesk_settings);
|
||||
|
||||
return output($element, 201);
|
||||
}
|
||||
|
||||
function put($id) {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$this->checkForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
$data = JsonRetriever::getJsonData();
|
||||
$handler->saveCustomNavElement($this->buildElementModel($data, $id), $hesk_settings);
|
||||
|
||||
return http_response_code(204);
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$this->checkForInternalUseOnly();
|
||||
|
||||
/* @var $handler CustomNavElementHandler */
|
||||
$handler = $applicationContext->get[CustomNavElementHandler::class];
|
||||
|
||||
$handler->deleteCustomNavElement($id, $hesk_settings);
|
||||
|
||||
return http_response_code(204);
|
||||
}
|
||||
|
||||
private function buildElementModel($data, $id = null) {
|
||||
$element = new CustomNavElement();
|
||||
$element->id = $id;
|
||||
$element->place = intval(Helpers::safeArrayGet($data, 'place'));
|
||||
$element->fontIcon = Helpers::safeArrayGet($data, 'fontIcon');
|
||||
$element->imageUrl = Helpers::safeArrayGet($data, 'imageUrl');
|
||||
$element->text = Helpers::safeArrayGet($data, 'text');
|
||||
$element->subtext = Helpers::safeArrayGet($data, 'subtext');
|
||||
$element->url = Helpers::safeArrayGet($data, 'url');
|
||||
$element->sort = intval(Helpers::safeArrayGet($data, 'sort'));
|
||||
|
||||
return $element;
|
||||
}
|
||||
}
|
17
api/Controllers/Settings/SettingsController.php
Normal file
17
api/Controllers/Settings/SettingsController.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Settings;
|
||||
|
||||
|
||||
use BusinessLogic\Settings\SettingsRetriever;
|
||||
|
||||
class SettingsController {
|
||||
function get() {
|
||||
global $applicationContext, $hesk_settings, $modsForHesk_settings;
|
||||
|
||||
/* @var $settingsRetriever SettingsRetriever */
|
||||
$settingsRetriever = $applicationContext->get[SettingsRetriever::class];
|
||||
|
||||
output($settingsRetriever->getAllSettings($hesk_settings, $modsForHesk_settings));
|
||||
}
|
||||
}
|
17
api/Controllers/Statuses/StatusController.php
Normal file
17
api/Controllers/Statuses/StatusController.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Statuses;
|
||||
|
||||
|
||||
use BusinessLogic\Statuses\StatusRetriever;
|
||||
|
||||
class StatusController {
|
||||
function get() {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
/* @var $statusRetriever StatusRetriever */
|
||||
$statusRetriever = $applicationContext->get[StatusRetriever::class];
|
||||
|
||||
output($statusRetriever->getAllStatuses($hesk_settings));
|
||||
}
|
||||
}
|
71
api/Controllers/Tickets/CustomerTicketController.php
Normal file
71
api/Controllers/Tickets/CustomerTicketController.php
Normal file
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Tickets;
|
||||
|
||||
use BusinessLogic\Helpers;
|
||||
use BusinessLogic\Tickets\CreateTicketByCustomerModel;
|
||||
use BusinessLogic\Tickets\TicketCreator;
|
||||
use BusinessLogic\Tickets\TicketRetriever;
|
||||
use BusinessLogic\ValidationModel;
|
||||
use Controllers\JsonRetriever;
|
||||
|
||||
|
||||
class CustomerTicketController {
|
||||
function get() {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$trackingId = isset($_GET['trackingId']) ? $_GET['trackingId'] : null;
|
||||
$emailAddress = isset($_GET['email']) ? $_GET['email'] : null;
|
||||
|
||||
/* @var $ticketRetriever TicketRetriever */
|
||||
$ticketRetriever = $applicationContext->get[TicketRetriever::class];
|
||||
|
||||
output($ticketRetriever->getTicketByTrackingIdAndEmail($trackingId, $emailAddress, $hesk_settings));
|
||||
}
|
||||
|
||||
function post() {
|
||||
global $applicationContext, $hesk_settings, $userContext;
|
||||
|
||||
/* @var $ticketCreator TicketCreator */
|
||||
$ticketCreator = $applicationContext->get[TicketCreator::class];
|
||||
|
||||
$jsonRequest = JsonRetriever::getJsonData();
|
||||
|
||||
$ticket = $ticketCreator->createTicketByCustomer($this->buildTicketRequestFromJson($jsonRequest), $hesk_settings, $userContext);
|
||||
|
||||
return output($ticket->ticket, $ticket->emailVerified ? 201 : 202);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $json array
|
||||
* @return CreateTicketByCustomerModel
|
||||
*/
|
||||
private function buildTicketRequestFromJson($json) {
|
||||
$ticketRequest = new CreateTicketByCustomerModel();
|
||||
$ticketRequest->name = Helpers::safeArrayGet($json, 'name');
|
||||
$ticketRequest->email = Helpers::safeArrayGet($json, 'email');
|
||||
$ticketRequest->category = Helpers::safeArrayGet($json, 'category');
|
||||
$ticketRequest->priority = Helpers::safeArrayGet($json, 'priority');
|
||||
$ticketRequest->subject = Helpers::safeArrayGet($json, 'subject');
|
||||
$ticketRequest->message = Helpers::safeArrayGet($json, 'message');
|
||||
$ticketRequest->html = Helpers::safeArrayGet($json, 'html');
|
||||
$ticketRequest->location = Helpers::safeArrayGet($json, 'location');
|
||||
$ticketRequest->suggestedKnowledgebaseArticleIds = Helpers::safeArrayGet($json, 'suggestedArticles');
|
||||
$ticketRequest->userAgent = Helpers::safeArrayGet($json, 'userAgent');
|
||||
$ticketRequest->screenResolution = Helpers::safeArrayGet($json, 'screenResolution');
|
||||
$ticketRequest->ipAddress = Helpers::safeArrayGet($json, 'ip');
|
||||
$ticketRequest->language = Helpers::safeArrayGet($json, 'language');
|
||||
$ticketRequest->sendEmailToCustomer = true;
|
||||
$ticketRequest->customFields = array();
|
||||
|
||||
$jsonCustomFields = Helpers::safeArrayGet($json, 'customFields');
|
||||
|
||||
if ($jsonCustomFields !== null && !empty($jsonCustomFields)) {
|
||||
foreach ($jsonCustomFields as $key => $value) {
|
||||
$ticketRequest->customFields[intval($key)] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $ticketRequest;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Emails\Addressees;
|
||||
use BusinessLogic\Emails\EmailSenderHelper;
|
||||
use BusinessLogic\Emails\EmailTemplate;
|
||||
use BusinessLogic\Emails\EmailTemplateRetriever;
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Tickets\TicketRetriever;
|
||||
use Controllers\InternalApiController;
|
||||
use DataAccess\Settings\ModsForHeskSettingsGateway;
|
||||
|
||||
class ResendTicketEmailToCustomerController extends InternalApiController {
|
||||
function get($ticketId) {
|
||||
global $applicationContext, $userContext, $hesk_settings;
|
||||
|
||||
$this->checkForInternalUseOnly();
|
||||
|
||||
/* @var $ticketRetriever TicketRetriever */
|
||||
$ticketRetriever = $applicationContext->get[TicketRetriever::class];
|
||||
$ticket = $ticketRetriever->getTicketById($ticketId, $hesk_settings, $userContext);
|
||||
|
||||
/* @var $modsForHeskSettingsGateway ModsForHeskSettingsGateway */
|
||||
$modsForHeskSettingsGateway = $applicationContext->get[ModsForHeskSettingsGateway::class];
|
||||
$modsForHeskSettings = $modsForHeskSettingsGateway->getAllSettings($hesk_settings);
|
||||
|
||||
/* @var $emailSender EmailSenderHelper */
|
||||
$emailSender = $applicationContext->get[EmailSenderHelper::class];
|
||||
|
||||
$language = $ticket->language;
|
||||
|
||||
if ($language === null) {
|
||||
$language = $hesk_settings['language'];
|
||||
}
|
||||
|
||||
if ($ticket === null) {
|
||||
throw new ApiFriendlyException("Ticket {$ticketId} not found!", "Ticket Not Found", 404);
|
||||
}
|
||||
|
||||
$reply = null;
|
||||
$emailTemplate = EmailTemplateRetriever::NEW_TICKET;
|
||||
if (isset($_GET['replyId'])) {
|
||||
$replyId = $_GET['replyId'];
|
||||
$emailTemplate = EmailTemplateRetriever::NEW_REPLY_BY_STAFF;
|
||||
|
||||
foreach ($ticket->replies as $ticketReply) {
|
||||
if ($ticketReply->id === $replyId) {
|
||||
$reply = $ticketReply;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($reply === null) {
|
||||
throw new ApiFriendlyException("Reply {$replyId} not found on ticket {$ticketId}!", "Reply Not Found", 404);
|
||||
}
|
||||
|
||||
// Copy over reply properties onto the Ticket
|
||||
$ticket->lastReplier = $reply->replierName;
|
||||
$ticket->message = $reply->message;
|
||||
$ticket->attachments = $reply->attachments;
|
||||
}
|
||||
|
||||
$addressees = new Addressees();
|
||||
$addressees->to = $ticket->email;
|
||||
|
||||
$emailSender->sendEmailForTicket($emailTemplate, $language, $addressees, $ticket, $hesk_settings, $modsForHeskSettings);
|
||||
|
||||
http_response_code(204);
|
||||
}
|
||||
}
|
68
api/Controllers/Tickets/StaffTicketController.php
Normal file
68
api/Controllers/Tickets/StaffTicketController.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Helpers;
|
||||
use BusinessLogic\Tickets\EditTicketModel;
|
||||
use BusinessLogic\Tickets\TicketDeleter;
|
||||
use BusinessLogic\Tickets\TicketEditor;
|
||||
use BusinessLogic\Tickets\TicketRetriever;
|
||||
use Controllers\JsonRetriever;
|
||||
|
||||
class StaffTicketController {
|
||||
function get($id) {
|
||||
global $applicationContext, $userContext, $hesk_settings;
|
||||
|
||||
/* @var $ticketRetriever TicketRetriever */
|
||||
$ticketRetriever = $applicationContext->get[TicketRetriever::class];
|
||||
|
||||
output($ticketRetriever->getTicketById($id, $hesk_settings, $userContext));
|
||||
}
|
||||
|
||||
function delete($id) {
|
||||
global $applicationContext, $userContext, $hesk_settings;
|
||||
|
||||
/* @var $ticketDeleter TicketDeleter */
|
||||
$ticketDeleter = $applicationContext->get[TicketDeleter::class];
|
||||
|
||||
$ticketDeleter->deleteTicket($id, $userContext, $hesk_settings);
|
||||
|
||||
http_response_code(204);
|
||||
}
|
||||
|
||||
function put($id) {
|
||||
global $applicationContext, $userContext, $hesk_settings;
|
||||
|
||||
/* @var $ticketEditor TicketEditor */
|
||||
$ticketEditor = $applicationContext->get[TicketEditor::class];
|
||||
|
||||
$jsonRequest = JsonRetriever::getJsonData();
|
||||
|
||||
$ticketEditor->editTicket($this->getEditTicketModel($id, $jsonRequest), $userContext, $hesk_settings);
|
||||
|
||||
http_response_code(204);
|
||||
return;
|
||||
}
|
||||
|
||||
private function getEditTicketModel($id, $jsonRequest) {
|
||||
$editTicketModel = new EditTicketModel();
|
||||
$editTicketModel->id = $id;
|
||||
$editTicketModel->language = Helpers::safeArrayGet($jsonRequest, 'language');
|
||||
$editTicketModel->name = Helpers::safeArrayGet($jsonRequest, 'name');
|
||||
$editTicketModel->subject = Helpers::safeArrayGet($jsonRequest, 'subject');
|
||||
$editTicketModel->message = Helpers::safeArrayGet($jsonRequest, 'message');
|
||||
$editTicketModel->html = Helpers::safeArrayGet($jsonRequest, 'html');
|
||||
$editTicketModel->email = Helpers::safeArrayGet($jsonRequest, 'email');
|
||||
|
||||
$jsonCustomFields = Helpers::safeArrayGet($jsonRequest, 'customFields');
|
||||
|
||||
if ($jsonCustomFields !== null && !empty($jsonCustomFields)) {
|
||||
foreach ($jsonCustomFields as $key => $value) {
|
||||
$editTicketModel->customFields[intval($key)] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $editTicketModel;
|
||||
}
|
||||
}
|
16
api/Core/Constants/CustomField.php
Normal file
16
api/Core/Constants/CustomField.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Constants;
|
||||
|
||||
|
||||
class CustomField {
|
||||
const RADIO = 'radio';
|
||||
const SELECT = 'select';
|
||||
const CHECKBOX = 'checkbox';
|
||||
const TEXTAREA = 'textarea';
|
||||
const DATE = 'date';
|
||||
const EMAIL = 'email';
|
||||
const HIDDEN = 'hidden';
|
||||
const READONLY = 'readonly';
|
||||
const TEXT = 'text';
|
||||
}
|
11
api/Core/Constants/Priority.php
Normal file
11
api/Core/Constants/Priority.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Constants;
|
||||
|
||||
|
||||
class Priority {
|
||||
const CRITICAL = 0;
|
||||
const HIGH = 1;
|
||||
const MEDIUM = 2;
|
||||
const LOW = 3;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user