Compare commits
No commits in common. 'master' and '3.0.0' have entirely different histories.
@ -1,90 +0,0 @@
|
||||
stages:
|
||||
- validate
|
||||
- test
|
||||
- package
|
||||
|
||||
before_script:
|
||||
- bash ci/docker_install.sh > /dev/null
|
||||
|
||||
validate:7.2:
|
||||
image: php:7.2
|
||||
stage: validate
|
||||
script:
|
||||
- bash ci/php_lint.sh ./
|
||||
|
||||
validate:7.1:
|
||||
image: php:7.1
|
||||
stage: validate
|
||||
script:
|
||||
- bash ci/php_lint.sh ./
|
||||
|
||||
validate:7.0:
|
||||
image: php:7.0
|
||||
stage: validate
|
||||
script:
|
||||
- bash ci/php_lint.sh ./
|
||||
|
||||
validate:5.6:
|
||||
image: php:5.6
|
||||
stage: validate
|
||||
script:
|
||||
- bash ci/php_lint.sh ./
|
||||
|
||||
validate:5.5:
|
||||
image: php:5.5
|
||||
stage: validate
|
||||
script:
|
||||
- bash ci/php_lint.sh ./
|
||||
|
||||
validate:5.4:
|
||||
image: php:5.4
|
||||
stage: validate
|
||||
script:
|
||||
- bash ci/php_lint.sh ./
|
||||
|
||||
validate:5.3:
|
||||
image: php:5.3
|
||||
stage: validate
|
||||
script:
|
||||
- bash ci/php_lint.sh ./
|
||||
|
||||
test:7.1:
|
||||
image: php:7.1
|
||||
stage: test
|
||||
script:
|
||||
- cd api
|
||||
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||
- php composer-setup.php
|
||||
- php -r "unlink('composer-setup.php');"
|
||||
- php composer.phar update
|
||||
- php composer.phar install
|
||||
- cd Tests
|
||||
- phpunit
|
||||
|
||||
test:7.2:
|
||||
image: php:7.2
|
||||
stage: test
|
||||
script:
|
||||
- cd api
|
||||
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||
- php composer-setup.php
|
||||
- php -r "unlink('composer-setup.php');"
|
||||
- php composer.phar update
|
||||
- php composer.phar install
|
||||
- cd Tests
|
||||
- phpunit
|
||||
|
||||
package:
|
||||
image: tetraweb/php
|
||||
when: manual
|
||||
stage: package
|
||||
script:
|
||||
- apt-get update
|
||||
- apt-get install zip unzip
|
||||
- cd api
|
||||
- composer install --no-dev
|
||||
- cd ../ci
|
||||
- bash build_zip.sh
|
||||
artifacts:
|
||||
paths:
|
||||
- release.zip
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
define('IN_SCRIPT',1);
|
||||
define('HESK_PATH','../');
|
||||
|
||||
/* Get all the required files and functions */
|
||||
require(HESK_PATH . 'hesk_settings.inc.php');
|
||||
require(HESK_PATH . 'inc/common.inc.php');
|
||||
require(HESK_PATH . 'inc/admin_functions.inc.php');
|
||||
require(HESK_PATH . 'inc/privacy_functions.inc.php');
|
||||
hesk_load_database_functions();
|
||||
|
||||
hesk_session_start();
|
||||
hesk_dbConnect();
|
||||
hesk_isLoggedIn();
|
||||
|
||||
// Check permissions for this feature
|
||||
hesk_checkPermission('can_privacy');
|
||||
|
||||
// A security check
|
||||
hesk_token_check();
|
||||
|
||||
// Tracking ID
|
||||
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
|
||||
|
||||
// Anonymize the ticket and redirect back
|
||||
if (hesk_anonymizeTicket(0, $trackingID))
|
||||
{
|
||||
hesk_process_messages($hesklang['success_anon'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
|
||||
}
|
||||
|
||||
hesk_error($hesklang['no_permission']);
|
@ -1,54 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
define('IN_SCRIPT',1);
|
||||
define('HESK_PATH','../');
|
||||
|
||||
/* Get all the required files and functions */
|
||||
require(HESK_PATH . 'hesk_settings.inc.php');
|
||||
require(HESK_PATH . 'inc/common.inc.php');
|
||||
require(HESK_PATH . 'inc/admin_functions.inc.php');
|
||||
require(HESK_PATH . 'inc/privacy_functions.inc.php');
|
||||
hesk_load_database_functions();
|
||||
|
||||
hesk_session_start();
|
||||
hesk_dbConnect();
|
||||
hesk_isLoggedIn();
|
||||
|
||||
// Check permissions for this feature
|
||||
hesk_checkPermission('can_export');
|
||||
|
||||
// A security check
|
||||
hesk_token_check();
|
||||
|
||||
// Tracking ID
|
||||
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
|
||||
|
||||
// Generate SQL for the ticket, make sure the user has access to it
|
||||
$sql = "SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `trackid`='".hesk_dbEscape($trackingID)."' AND ";
|
||||
$sql .= hesk_myCategories();
|
||||
$sql .= " AND " . hesk_myOwnership();
|
||||
$sql .= " LIMIT 1";
|
||||
|
||||
require_once(HESK_PATH . 'inc/custom_fields.inc.php');
|
||||
require_once(HESK_PATH . 'inc/statuses.inc.php');
|
||||
require(HESK_PATH . 'inc/export_functions.inc.php');
|
||||
|
||||
list($success_msg, $tickets_exported) = hesk_export_to_XML($sql, true);
|
||||
|
||||
if ($tickets_exported == 1)
|
||||
{
|
||||
hesk_process_messages($success_msg,'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
|
||||
}
|
||||
|
||||
hesk_error($hesklang['n2ex']);
|
File diff suppressed because it is too large
Load Diff
@ -1,275 +0,0 @@
|
||||
<?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');
|
@ -1,73 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
define('IN_SCRIPT',1);
|
||||
define('HESK_PATH','../');
|
||||
|
||||
/* Get all the required files and functions */
|
||||
require(HESK_PATH . 'hesk_settings.inc.php');
|
||||
require(HESK_PATH . 'inc/common.inc.php');
|
||||
require(HESK_PATH . 'inc/admin_functions.inc.php');
|
||||
hesk_load_database_functions();
|
||||
|
||||
hesk_session_start();
|
||||
hesk_dbConnect();
|
||||
hesk_isLoggedIn();
|
||||
|
||||
/* Check permissions for this feature */
|
||||
hesk_checkPermission('can_view_tickets');
|
||||
hesk_checkPermission('can_reply_tickets');
|
||||
|
||||
/* A security check */
|
||||
hesk_token_check('POST');
|
||||
|
||||
/* Ticket ID */
|
||||
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
|
||||
|
||||
$priority = intval( hesk_POST('priority') );
|
||||
if ($priority < 0 || $priority > 3)
|
||||
{
|
||||
hesk_process_messages($hesklang['inpr'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'NOTICE');
|
||||
}
|
||||
|
||||
$options = array(
|
||||
0 => '<font class="critical">'.$hesklang['critical'].'</font>',
|
||||
1 => '<font class="important">'.$hesklang['high'].'</font>',
|
||||
2 => '<font class="medium">'.$hesklang['medium'].'</font>',
|
||||
3 => $hesklang['low']
|
||||
);
|
||||
|
||||
$plain_options = array(
|
||||
0 => 'critical',
|
||||
1 => 'high',
|
||||
2 => 'medium',
|
||||
3 => 'low'
|
||||
);
|
||||
|
||||
$ticketRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid` = '" . hesk_dbEscape($trackingID) . "'");
|
||||
$ticket = hesk_dbFetchAssoc($ticketRs);
|
||||
|
||||
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `priority`='{$priority}' WHERE `trackid`='".hesk_dbEscape($trackingID)."'");
|
||||
|
||||
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_priority', hesk_date(), array(
|
||||
0 => $_SESSION['name'].' ('.$_SESSION['user'].')',
|
||||
1 => $plain_options[$priority]
|
||||
));
|
||||
|
||||
if (hesk_dbAffectedRows() != 1)
|
||||
{
|
||||
hesk_process_messages($hesklang['inpr'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'NOTICE');
|
||||
}
|
||||
|
||||
hesk_process_messages(sprintf($hesklang['chpri2'],$options[$priority]),'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
class BaseClass {
|
||||
static function clazz() {
|
||||
return get_called_class();
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
<?php
|
||||
|
||||
class BaseException extends Exception {
|
||||
static function clazz() {
|
||||
return get_called_class();
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class Attachment extends \BaseClass {
|
||||
/* @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;
|
||||
}
|
@ -1,479 +0,0 @@
|
||||
<?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 extends \BaseClass {
|
||||
/* @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 $ticketGateway,
|
||||
AttachmentGateway $attachmentGateway,
|
||||
FileWriter $fileWriter,
|
||||
UserToTicketChecker $userToTicketChecker,
|
||||
FileDeleter $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);
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
<?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 extends \BaseClass {
|
||||
/* @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;
|
||||
}
|
||||
|
||||
//-- TODO Test
|
||||
function getAttachmentContentsForTrackingId($trackingId, $attachmentId, $userContext, $heskSettings) {
|
||||
$ticket = $this->ticketGateway->getTicketByTrackingId($trackingId, $heskSettings);
|
||||
|
||||
if ($ticket === null) {
|
||||
throw new ApiFriendlyException("Ticket {$trackingId} not found!", "Ticket Not Found", 404);
|
||||
}
|
||||
|
||||
$attachment = $this->attachmentGateway->getAttachmentById($attachmentId, $heskSettings);
|
||||
|
||||
return array('meta' => $attachment,
|
||||
'contents' => $this->fileReader->readFromFile($attachment->savedName, $heskSettings['attach_dir']));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class AttachmentType extends \BaseClass {
|
||||
const MESSAGE = 0;
|
||||
const REPLY = 1;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class CreateAttachmentForTicketModel extends CreateAttachmentModel {
|
||||
/* @var $ticketId int */
|
||||
public $ticketId;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class CreateAttachmentModel extends \BaseClass {
|
||||
/* @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;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Attachments;
|
||||
|
||||
|
||||
class TicketAttachment extends Attachment {
|
||||
/* @var $ticketTrackingId string */
|
||||
public $ticketTrackingId;
|
||||
|
||||
/* @var $type int [use <code>AttachmentType</code>] */
|
||||
public $type;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Calendar;
|
||||
|
||||
|
||||
class AbstractEvent {
|
||||
public $id;
|
||||
|
||||
public $startTime;
|
||||
|
||||
public $title;
|
||||
|
||||
public $categoryId;
|
||||
|
||||
public $categoryName;
|
||||
|
||||
public $backgroundColor;
|
||||
|
||||
public $foregroundColor;
|
||||
|
||||
public $displayBorder;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Calendar;
|
||||
|
||||
|
||||
class BusinessHours {
|
||||
/* @var $dayOfWeek int */
|
||||
public $dayOfWeek;
|
||||
|
||||
/* @var $startTime string */
|
||||
public $startTime;
|
||||
|
||||
/* @var $endTime string */
|
||||
public $endTime;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Calendar;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\AuditTrail;
|
||||
|
||||
class CalendarEvent extends AbstractEvent {
|
||||
public $type = 'CALENDAR';
|
||||
|
||||
public $endTime;
|
||||
|
||||
/* @var $allDay bool */
|
||||
public $allDay;
|
||||
|
||||
public $location;
|
||||
|
||||
public $comments;
|
||||
|
||||
public $reminderValue;
|
||||
|
||||
public $reminderUnits;
|
||||
|
||||
/* @var $auditTrail AuditTrail[] */
|
||||
public $auditTrail = array();
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Calendar;
|
||||
|
||||
|
||||
use BusinessLogic\DateTimeHelpers;
|
||||
use BusinessLogic\Security\UserContext;
|
||||
use BusinessLogic\Tickets\AuditTrailEntityType;
|
||||
use DataAccess\AuditTrail\AuditTrailGateway;
|
||||
use DataAccess\Calendar\CalendarGateway;
|
||||
|
||||
class CalendarHandler extends \BaseClass {
|
||||
private $calendarGateway;
|
||||
private $auditTrailGateway;
|
||||
|
||||
public function __construct(CalendarGateway $calendarGateway,
|
||||
AuditTrailGateway $auditTrailGateway) {
|
||||
$this->calendarGateway = $calendarGateway;
|
||||
$this->auditTrailGateway = $auditTrailGateway;
|
||||
}
|
||||
|
||||
public function getEventsForStaff($searchEventsFilter, $heskSettings) {
|
||||
return $this->calendarGateway->getEventsForStaff($searchEventsFilter, $heskSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $calendarEvent CalendarEvent
|
||||
* @param $userContext UserContext
|
||||
* @param $heskSettings array
|
||||
* @return CalendarEvent
|
||||
* @throws \Exception If more than one event is returned for the given ID
|
||||
*/
|
||||
public function updateEvent($calendarEvent, $userContext, $heskSettings) {
|
||||
$this->calendarGateway->updateEvent($calendarEvent, $userContext, $heskSettings);
|
||||
|
||||
$this->auditTrailGateway->insertAuditTrailRecord($calendarEvent->id,
|
||||
AuditTrailEntityType::CALENDAR_EVENT,
|
||||
'audit_event_updated',
|
||||
DateTimeHelpers::heskDate($heskSettings),
|
||||
array(0 => $userContext->name . ' (' . $userContext->username . ')'), $heskSettings);
|
||||
|
||||
$eventFilter = new SearchEventsFilter();
|
||||
$eventFilter->eventId = $calendarEvent->id;
|
||||
$eventFilter->reminderUserId = $userContext->id;
|
||||
|
||||
$events = $this->calendarGateway->getEventsForStaff($eventFilter, $heskSettings);
|
||||
|
||||
if (count($events) !== 1) {
|
||||
throw new \Exception("Expected exactly 1 event, found: " . count($events));
|
||||
}
|
||||
|
||||
$event = $events[0];
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $calendarEvent CalendarEvent
|
||||
* @param $userContext UserContext
|
||||
* @param $heskSettings array
|
||||
* @return AbstractEvent
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function createEvent($calendarEvent, $userContext, $heskSettings) {
|
||||
$this->calendarGateway->createEvent($calendarEvent, $userContext, $heskSettings);
|
||||
|
||||
$eventFilter = new SearchEventsFilter();
|
||||
$eventFilter->eventId = $calendarEvent->id;
|
||||
$eventFilter->reminderUserId = $userContext->id;
|
||||
|
||||
$events = $this->calendarGateway->getEventsForStaff($eventFilter, $heskSettings);
|
||||
|
||||
if (count($events) !== 1) {
|
||||
throw new \Exception("Expected exactly 1 event, found: " . count($events));
|
||||
}
|
||||
|
||||
$event = $events[0];
|
||||
|
||||
$this->auditTrailGateway->insertAuditTrailRecord($event->id,
|
||||
AuditTrailEntityType::CALENDAR_EVENT,
|
||||
'audit_event_created',
|
||||
DateTimeHelpers::heskDate($heskSettings),
|
||||
array(0 => $userContext->name . ' (' . $userContext->username . ')'), $heskSettings);
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
public function deleteEvent($id, $userContext, $heskSettings) {
|
||||
$this->calendarGateway->deleteEvent($id, $userContext, $heskSettings);
|
||||
}
|
||||
|
||||
public function getBusinessHours($heskSettings) {
|
||||
return $this->calendarGateway->getBusinessHours($heskSettings);
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Calendar;
|
||||
|
||||
|
||||
class ReminderUnit {
|
||||
const MINUTE = 0;
|
||||
const HOUR = 1;
|
||||
const DAY = 2;
|
||||
const WEEK = 3;
|
||||
|
||||
static function getByValue($value) {
|
||||
switch ($value) {
|
||||
case 0:
|
||||
return 'MINUTE';
|
||||
case 1:
|
||||
return 'HOUR';
|
||||
case 2:
|
||||
return 'DAY';
|
||||
case 3:
|
||||
return 'WEEK';
|
||||
default:
|
||||
return 'UNKNOWN';
|
||||
}
|
||||
}
|
||||
|
||||
static function getByName($name) {
|
||||
switch ($name) {
|
||||
case 'MINUTE':
|
||||
return self::MINUTE;
|
||||
case 'HOUR':
|
||||
return self::HOUR;
|
||||
case 'DAY':
|
||||
return self::DAY;
|
||||
case 'WEEK':
|
||||
return self::WEEK;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Calendar;
|
||||
|
||||
|
||||
class SearchEventsFilter {
|
||||
/* @var $startTime int|null */
|
||||
public $startTime;
|
||||
|
||||
/* @var $endTime int|null */
|
||||
public $endTime;
|
||||
|
||||
/* @var $id int|null */
|
||||
public $eventId;
|
||||
|
||||
/* @var $categories int[]|null */
|
||||
public $categories;
|
||||
|
||||
/* @var $reminderUserId int|null */
|
||||
public $reminderUserId;
|
||||
|
||||
/* @var $includeTickets bool */
|
||||
public $includeTickets;
|
||||
|
||||
/* @var $includeUnassignedTickets bool */
|
||||
public $includeUnassignedTickets;
|
||||
|
||||
/* @var $includeTicketsAssignedToOthers bool */
|
||||
public $includeTicketsAssignedToOthers;
|
||||
|
||||
/* @var $includeTicketsAssignedToMe bool */
|
||||
public $includeTicketsAssignedToMe;
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Calendar;
|
||||
|
||||
|
||||
class TicketEvent extends AbstractEvent {
|
||||
public $type = 'TICKET';
|
||||
|
||||
public $trackingId;
|
||||
|
||||
public $subject;
|
||||
|
||||
public $url;
|
||||
|
||||
public $owner;
|
||||
|
||||
public $priority;
|
||||
|
||||
public $status;
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Categories;
|
||||
|
||||
class Category extends \BaseClass {
|
||||
/**
|
||||
* @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, 0 = 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;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $description;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $numberOfTickets;
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Categories;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\AccessViolationException;
|
||||
use BusinessLogic\Exceptions\ValidationException;
|
||||
use BusinessLogic\Navigation\Direction;
|
||||
use BusinessLogic\Security\PermissionChecker;
|
||||
use BusinessLogic\Security\UserPrivilege;
|
||||
use BusinessLogic\ValidationModel;
|
||||
use DataAccess\Categories\CategoryGateway;
|
||||
use DataAccess\Settings\ModsForHeskSettingsGateway;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class CategoryHandler extends \BaseClass {
|
||||
/* @var $categoryGateway CategoryGateway */
|
||||
private $categoryGateway;
|
||||
|
||||
/* @var $ticketGateway TicketGateway */
|
||||
private $ticketGateway;
|
||||
|
||||
/* @var $permissionChecker PermissionChecker */
|
||||
private $permissionChecker;
|
||||
|
||||
/* @var $modsForHeskSettingsGateway ModsForHeskSettingsGateway */
|
||||
private $modsForHeskSettingsGateway;
|
||||
|
||||
function __construct(CategoryGateway $categoryGateway,
|
||||
TicketGateway $ticketGateway,
|
||||
PermissionChecker $permissionChecker,
|
||||
ModsForHeskSettingsGateway $modsForHeskSettingsGateway) {
|
||||
$this->categoryGateway = $categoryGateway;
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
$this->permissionChecker = $permissionChecker;
|
||||
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $category Category
|
||||
* @param $userContext
|
||||
* @param $heskSettings array
|
||||
* @return Category The newly created category with ID
|
||||
* @throws ValidationException When validation fails
|
||||
* @throws \Exception When the newly created category was not retrieved
|
||||
*/
|
||||
//TODO Test
|
||||
function createCategory($category, $userContext, $heskSettings) {
|
||||
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
|
||||
|
||||
$validationModel = $this->validate($category, $userContext);
|
||||
|
||||
if (count($validationModel->errorKeys) > 0) {
|
||||
throw new ValidationException($validationModel);
|
||||
}
|
||||
|
||||
$id = $this->categoryGateway->createCategory($category, $heskSettings);
|
||||
|
||||
$allCategories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
|
||||
|
||||
foreach ($allCategories as $innerCategory) {
|
||||
if ($innerCategory->id === $id) {
|
||||
return $innerCategory;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \BaseException("Newly created category {$id} lost! :O");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $category Category
|
||||
* @param $userContext
|
||||
* @param $creating bool
|
||||
* @return ValidationModel
|
||||
* @throws AccessViolationException
|
||||
*/
|
||||
//TODO Test
|
||||
private function validate($category, $userContext, $creating = true) {
|
||||
$validationModel = new ValidationModel();
|
||||
|
||||
if (!$this->permissionChecker->doesUserHavePermission($userContext, UserPrivilege::CAN_MANAGE_CATEGORIES)) {
|
||||
throw new AccessViolationException('User cannot manage categories!');
|
||||
}
|
||||
|
||||
if (!$creating && $category->id < 1) {
|
||||
$validationModel->errorKeys[] = 'ID_MISSING';
|
||||
}
|
||||
|
||||
if ($category->backgroundColor === null || trim($category->backgroundColor) === '') {
|
||||
$validationModel->errorKeys[] = 'BACKGROUND_COLOR_MISSING';
|
||||
}
|
||||
|
||||
if ($category->foregroundColor === null || trim($category->foregroundColor) === '') {
|
||||
$validationModel->errorKeys[] = 'FOREGROUND_COLOR_MISSING';
|
||||
}
|
||||
|
||||
if ($category->name === null || trim($category->name) === '') {
|
||||
$validationModel->errorKeys[] = 'NAME_MISSING';
|
||||
}
|
||||
|
||||
if ($category->priority === null || intval($category->priority) < 0 || intval($category->priority) > 3) {
|
||||
$validationModel->errorKeys[] = 'INVALID_PRIORITY';
|
||||
}
|
||||
|
||||
if ($category->autoAssign === null || !is_bool($category->autoAssign)) {
|
||||
$validationModel->errorKeys[] = 'INVALID_AUTOASSIGN';
|
||||
}
|
||||
|
||||
if ($category->displayBorder === null || !is_bool($category->displayBorder)) {
|
||||
$validationModel->errorKeys[] = 'INVALID_DISPLAY_BORDER';
|
||||
}
|
||||
|
||||
if ($category->type === null || (intval($category->type) !== 0 && intval($category->type) !== 1)) {
|
||||
$validationModel->errorKeys[] = 'INVALID_TYPE';
|
||||
}
|
||||
|
||||
return $validationModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $category Category
|
||||
* @param $userContext
|
||||
* @param $heskSettings array
|
||||
* @return Category
|
||||
* @throws ValidationException
|
||||
* @throws \Exception When the category is missing
|
||||
*/
|
||||
function editCategory($category, $userContext, $heskSettings) {
|
||||
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
|
||||
|
||||
$validationModel = $this->validate($category, $userContext, false);
|
||||
|
||||
if (count($validationModel->errorKeys) > 0) {
|
||||
throw new ValidationException($validationModel);
|
||||
}
|
||||
|
||||
$this->categoryGateway->updateCategory($category, $heskSettings);
|
||||
$this->categoryGateway->resortAllCategories($heskSettings);
|
||||
|
||||
$allCategories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
|
||||
|
||||
foreach ($allCategories as $innerCategory) {
|
||||
if ($innerCategory->id === $category->id) {
|
||||
return $innerCategory;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \BaseException("Category {$category->id} vanished! :O");
|
||||
}
|
||||
|
||||
function deleteCategory($id, $userContext, $heskSettings) {
|
||||
if (!$this->permissionChecker->doesUserHavePermission($userContext, UserPrivilege::CAN_MANAGE_CATEGORIES)) {
|
||||
throw new AccessViolationException('User cannot manage categories!');
|
||||
}
|
||||
|
||||
if ($id === 1) {
|
||||
throw new \BaseException("Category 1 cannot be deleted!");
|
||||
}
|
||||
|
||||
$this->ticketGateway->moveTicketsToDefaultCategory($id, $heskSettings);
|
||||
$this->categoryGateway->deleteCategory($id, $heskSettings);
|
||||
$this->categoryGateway->resortAllCategories($heskSettings);
|
||||
}
|
||||
|
||||
function sortCategory($id, $direction, $heskSettings) {
|
||||
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
|
||||
|
||||
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
|
||||
$category = null;
|
||||
foreach ($categories as $innerCategory) {
|
||||
if ($innerCategory->id === intval($id)) {
|
||||
$category = $innerCategory;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($category === null) {
|
||||
throw new \BaseException("Could not find category with ID {$id}!");
|
||||
}
|
||||
|
||||
if ($direction === Direction::UP) {
|
||||
$category->catOrder -= 15;
|
||||
} else {
|
||||
$category->catOrder += 15;
|
||||
}
|
||||
|
||||
$this->categoryGateway->updateCategory($category, $heskSettings);
|
||||
$this->categoryGateway->resortAllCategories($heskSettings);
|
||||
}
|
||||
|
||||
function getPublicCategories($heskSettings) {
|
||||
$allCategories = $this->categoryGateway->getAllCategories($heskSettings, $this->modsForHeskSettingsGateway->getAllSettings($heskSettings));
|
||||
|
||||
$publicCategories = array();
|
||||
foreach ($allCategories as $category) {
|
||||
if ($category->type === 0) {
|
||||
$publicCategories[] = $category;
|
||||
}
|
||||
}
|
||||
|
||||
return $publicCategories;
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Categories;
|
||||
|
||||
use BusinessLogic\Security\UserContext;
|
||||
use DataAccess\Categories\CategoryGateway;
|
||||
use DataAccess\Settings\ModsForHeskSettingsGateway;
|
||||
|
||||
class CategoryRetriever extends \BaseClass {
|
||||
/**
|
||||
* @var CategoryGateway
|
||||
*/
|
||||
private $categoryGateway;
|
||||
|
||||
/**
|
||||
* @var ModsForHeskSettingsGateway
|
||||
*/
|
||||
private $modsForHeskSettingsGateway;
|
||||
|
||||
function __construct(CategoryGateway $categoryGateway,
|
||||
ModsForHeskSettingsGateway $modsForHeskSettingsGateway) {
|
||||
$this->categoryGateway = $categoryGateway;
|
||||
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $heskSettings array
|
||||
* @param $userContext UserContext
|
||||
* @return array
|
||||
*/
|
||||
function getAllCategories($heskSettings, $userContext) {
|
||||
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
|
||||
|
||||
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
|
||||
|
||||
foreach ($categories as $category) {
|
||||
$category->accessible = $userContext->admin ||
|
||||
in_array($category->id, $userContext->categories);
|
||||
}
|
||||
|
||||
return $categories;
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic;
|
||||
|
||||
|
||||
class DateTimeHelpers {
|
||||
static function heskDate($heskSettings, $dt = '', $isStr = true, $return_str = true) {
|
||||
|
||||
if (!$dt) {
|
||||
$dt = time();
|
||||
} elseif ($isStr) {
|
||||
$dt = strtotime($dt);
|
||||
}
|
||||
|
||||
// Return formatted date
|
||||
return $return_str ? date($heskSettings['timeformat'], $dt) : $dt;
|
||||
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
class Addressees extends \BaseClass {
|
||||
/**
|
||||
* @var $to string[]
|
||||
*/
|
||||
public $to;
|
||||
|
||||
/**
|
||||
* @var $cc string[]|null
|
||||
*/
|
||||
public $cc = array();
|
||||
|
||||
/**
|
||||
* @var $bcc string[]|null
|
||||
*/
|
||||
public $bcc = array();
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Attachment;
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use PHPMailer;
|
||||
|
||||
class BasicEmailSender extends \BaseClass implements EmailSender {
|
||||
|
||||
function sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $sendAsHtml) {
|
||||
$toEmails = implode(',', $emailBuilder->to);
|
||||
if (preg_match("/\n|\r|\t|%0A|%0D|%08|%09/", $toEmails . $emailBuilder->subject)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$mailer = new PHPMailer();
|
||||
|
||||
if ($heskSettings['smtp']) {
|
||||
$mailer->isSMTP();
|
||||
$mailer->SMTPAuth = true;
|
||||
|
||||
//-- We'll set this explicitly below if the user has it enabled.
|
||||
$mailer->SMTPAutoTLS = false;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Attachment;
|
||||
|
||||
class EmailBuilder extends \BaseClass {
|
||||
/**
|
||||
* @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;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?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);
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
|
||||
class EmailSenderHelper extends \BaseClass {
|
||||
/**
|
||||
* @var $emailTemplateParser EmailTemplateParser
|
||||
*/
|
||||
private $emailTemplateParser;
|
||||
|
||||
/**
|
||||
* @var $basicEmailSender BasicEmailSender
|
||||
*/
|
||||
private $basicEmailSender;
|
||||
|
||||
/**
|
||||
* @var $mailgunEmailSender MailgunEmailSender
|
||||
*/
|
||||
private $mailgunEmailSender;
|
||||
|
||||
function __construct(EmailTemplateParser $emailTemplateParser,
|
||||
BasicEmailSender $basicEmailSender,
|
||||
MailgunEmailSender $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']);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
class EmailTemplate extends \BaseClass {
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
@ -1,385 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\EmailTemplateNotFoundException;
|
||||
use BusinessLogic\Exceptions\InvalidEmailTemplateException;
|
||||
use BusinessLogic\Helpers;
|
||||
use BusinessLogic\Security\UserContext;
|
||||
use BusinessLogic\Statuses\DefaultStatusForAction;
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use Core\Constants\Priority;
|
||||
use DataAccess\Categories\CategoryGateway;
|
||||
use DataAccess\Logging\LoggingGateway;
|
||||
use DataAccess\Security\UserGateway;
|
||||
use DataAccess\Statuses\StatusGateway;
|
||||
|
||||
class EmailTemplateParser extends \BaseClass {
|
||||
|
||||
/**
|
||||
* @var $statusGateway StatusGateway
|
||||
*/
|
||||
private $statusGateway;
|
||||
|
||||
/**
|
||||
* @var $categoryGateway CategoryGateway
|
||||
*/
|
||||
private $categoryGateway;
|
||||
|
||||
/**
|
||||
* @var $userGateway UserGateway
|
||||
*/
|
||||
private $userGateway;
|
||||
|
||||
/**
|
||||
* @var $emailTemplateRetriever EmailTemplateRetriever
|
||||
*/
|
||||
private $emailTemplateRetriever;
|
||||
|
||||
/**
|
||||
* @var $logger LoggingGateway
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
function __construct(StatusGateway $statusGateway,
|
||||
CategoryGateway $categoryGateway,
|
||||
UserGateway $userGateway,
|
||||
EmailTemplateRetriever $emailTemplateRetriever,
|
||||
LoggingGateway $loggingGateway) {
|
||||
$this->statusGateway = $statusGateway;
|
||||
$this->categoryGateway = $categoryGateway;
|
||||
$this->userGateway = $userGateway;
|
||||
$this->emailTemplateRetriever = $emailTemplateRetriever;
|
||||
$this->logger = $loggingGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $templateId int
|
||||
* @param $languageCode string
|
||||
* @param $ticket Ticket
|
||||
* @param $heskSettings array
|
||||
* @param $modsForHeskSettings array
|
||||
* @return ParsedEmailProperties
|
||||
* @throws InvalidEmailTemplateException
|
||||
* @throws \Exception
|
||||
*/
|
||||
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 \BaseException("Language code {$languageCode} did not return any valid HESK languages!");
|
||||
}
|
||||
|
||||
$subject = $this->parseSubject($subject, $ticket, $fullLanguageName, $heskSettings, $modsForHeskSettings);
|
||||
$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, $modsForHeskSettings) {
|
||||
global $hesklang;
|
||||
|
||||
if (!function_exists('hesk_msgToPlain')) {
|
||||
throw new \BaseException("common.inc.php not loaded!");
|
||||
}
|
||||
|
||||
if ($ticket === null) {
|
||||
return $subjectTemplate;
|
||||
}
|
||||
|
||||
// Status name and category name
|
||||
$defaultStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings);
|
||||
|
||||
if (key_exists($language, $defaultStatus->localizedNames)) {
|
||||
$statusName = $defaultStatus->localizedNames[$language];
|
||||
} elseif (key_exists('English', $defaultStatus->localizedNames)) {
|
||||
$statusName = $defaultStatus->localizedNames['English'];
|
||||
$this->logger->logWarning('EmailTemplateParser', "No localized status found for status '{$defaultStatus->id}' and language '{$language}'. Defaulted to English.", "", new UserContext(), $heskSettings);
|
||||
} else {
|
||||
$statusName = "[ERROR: No localized status found for status '{$defaultStatus->id}']";
|
||||
$this->logger->logError('EmailTemplateParser', "No localized status found for status '{$defaultStatus->id}'", "", new UserContext(), $heskSettings);
|
||||
}
|
||||
|
||||
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
|
||||
$category = null;
|
||||
foreach ($categories as $innerCategory) {
|
||||
if ($innerCategory->id === $ticket->categoryId) {
|
||||
$category = $innerCategory;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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 \BaseException("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]);
|
||||
|
||||
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
|
||||
$category = null;
|
||||
foreach ($categories as $innerCategory) {
|
||||
if ($innerCategory->id === $ticket->categoryId) {
|
||||
$category = $innerCategory;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$category = hesk_msgToPlain($category->name);
|
||||
$owner = $this->userGateway->getUserById($ticket->ownerId, $heskSettings);
|
||||
|
||||
$ownerName = $owner === null ? $hesklang['unas'] : hesk_msgToPlain($owner->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('%%FIRST_NAME%%', Helpers::fullNameToFirstName($ticket->name), $msg);
|
||||
$msg = str_replace('%%CATEGORY%%', $category, $msg);
|
||||
$msg = str_replace('%%PRIORITY%%', $priority, $msg);
|
||||
$msg = str_replace('%%OWNER%%', $ownerName, $msg);
|
||||
$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);
|
||||
$msg = str_replace('%%TIME_WORKED%%', $ticket->timeWorked, $msg);
|
||||
|
||||
$lastReplyBy = '';
|
||||
// Get the last reply by
|
||||
if (!empty($ticket->lastReplier)) {
|
||||
$lastReplyBy = $ticket->lastReplier;
|
||||
} else {
|
||||
$lastReplyBy = $ticket->name;
|
||||
}
|
||||
|
||||
$msg = str_replace('%%LAST_REPLY_BY%%', $lastReplyBy, $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;
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
class EmailTemplateRetriever extends \BaseClass {
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Attachment;
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use Mailgun\Mailgun;
|
||||
|
||||
class MailgunEmailSender extends \BaseClass 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 && count($emailBuilder->cc) > 0) {
|
||||
$mailgunArray['cc'] = implode(',', $emailBuilder->cc);
|
||||
}
|
||||
|
||||
if ($emailBuilder->bcc !== null && count($emailBuilder->bcc) > 0) {
|
||||
$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) {
|
||||
$ssl = !defined('NO_MAILGUN_SSL');
|
||||
|
||||
$messageClient = new Mailgun($modsForHeskSettings['mailgun_api_key'], 'api.mailgun.net', 'v2', $ssl);
|
||||
|
||||
$mailgunAttachments = array();
|
||||
if (count($attachments) > 0) {
|
||||
$mailgunAttachments = array(
|
||||
'attachment' => $attachments
|
||||
);
|
||||
}
|
||||
|
||||
$result = $messageClient->sendMessage($modsForHeskSettings['mailgun_domain'], $mailgunArray, $mailgunAttachments);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Emails;
|
||||
|
||||
|
||||
class ParsedEmailProperties extends \BaseClass {
|
||||
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;
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
class AccessViolationException extends ApiFriendlyException {
|
||||
function __construct($message) {
|
||||
parent::__construct($message, 'Access Exception', 403);
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
use Exception;
|
||||
|
||||
class ApiFriendlyException extends \BaseException {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
|
||||
class InternalUseOnlyException extends ApiFriendlyException {
|
||||
function __construct() {
|
||||
parent::__construct("This endpoint can only be used internally", "Internal Use Only", 401);
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Exceptions;
|
||||
|
||||
class MissingAuthenticationTokenException extends ApiFriendlyException {
|
||||
function __construct() {
|
||||
parent::__construct("An 'X-Auth-Token' is required for this request",
|
||||
'Security Exception',
|
||||
401);
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
@ -1,244 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic;
|
||||
|
||||
|
||||
class Helpers extends \BaseClass {
|
||||
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;
|
||||
}
|
||||
|
||||
static function boolval($val) {
|
||||
return $val == true;
|
||||
}
|
||||
|
||||
static function heskHtmlSpecialCharsDecode($in) {
|
||||
return str_replace(array('&', '<', '>', '"'), array('&', '<', '>', '"'), $in);
|
||||
}
|
||||
|
||||
static function heskMakeUrl($text, $class = '', $shortenLinks = true) {
|
||||
if (!defined('MAGIC_URL_EMAIL')) {
|
||||
define('MAGIC_URL_EMAIL', 1);
|
||||
define('MAGIC_URL_FULL', 2);
|
||||
define('MAGIC_URL_LOCAL', 3);
|
||||
define('MAGIC_URL_WWW', 4);
|
||||
}
|
||||
|
||||
$class = ($class) ? ' class="' . $class . '"' : '';
|
||||
|
||||
// matches a xxxx://aaaaa.bbb.cccc. ...
|
||||
$text = preg_replace_callback(
|
||||
'#(^|[\n\t (>.])(' . "[a-z][a-z\d+]*:/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#iu',
|
||||
function($matches) use ($class, $shortenLinks) {
|
||||
return self::makeClickableCallback(MAGIC_URL_FULL, $matches[1], $matches[2], '', $class, $shortenLinks);
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
// matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
|
||||
$text = preg_replace_callback(
|
||||
'#(^|[\n\t (>])(' . "www\.(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#iu',
|
||||
function($matches) use ($class, $shortenLinks) {
|
||||
return self::makeClickableCallback(MAGIC_URL_WWW, $matches[1], $matches[2], '', $class, $shortenLinks);
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
// matches an email address
|
||||
$text = preg_replace_callback(
|
||||
'/(^|[\n\t (>])(' . '((?:[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&)+)@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)' . ')/iu',
|
||||
function($matches) use ($class, $shortenLinks) {
|
||||
return self::makeClickableCallback(MAGIC_URL_EMAIL, $matches[1], $matches[2], '', $class, $shortenLinks);
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
static function makeClickableCallback($type, $whitespace, $url, $relative_url, $class, $shortenLinks)
|
||||
{
|
||||
global $hesk_settings;
|
||||
|
||||
$orig_url = $url;
|
||||
$orig_relative = $relative_url;
|
||||
$append = '';
|
||||
$url = htmlspecialchars_decode($url);
|
||||
$relative_url = htmlspecialchars_decode($relative_url);
|
||||
|
||||
// make sure no HTML entities were matched
|
||||
$chars = array('<', '>', '"');
|
||||
$split = false;
|
||||
|
||||
foreach ($chars as $char) {
|
||||
$next_split = strpos($url, $char);
|
||||
if ($next_split !== false) {
|
||||
$split = ($split !== false) ? min($split, $next_split) : $next_split;
|
||||
}
|
||||
}
|
||||
|
||||
if ($split !== false) {
|
||||
// an HTML entity was found, so the URL has to end before it
|
||||
$append = substr($url, $split) . $relative_url;
|
||||
$url = substr($url, 0, $split);
|
||||
$relative_url = '';
|
||||
} else if ($relative_url) {
|
||||
// same for $relative_url
|
||||
$split = false;
|
||||
foreach ($chars as $char) {
|
||||
$next_split = strpos($relative_url, $char);
|
||||
if ($next_split !== false) {
|
||||
$split = ($split !== false) ? min($split, $next_split) : $next_split;
|
||||
}
|
||||
}
|
||||
|
||||
if ($split !== false) {
|
||||
$append = substr($relative_url, $split);
|
||||
$relative_url = substr($relative_url, 0, $split);
|
||||
}
|
||||
}
|
||||
|
||||
// if the last character of the url is a punctuation mark, exclude it from the url
|
||||
$last_char = ($relative_url) ? $relative_url[strlen($relative_url) - 1] : $url[strlen($url) - 1];
|
||||
|
||||
switch ($last_char) {
|
||||
case '.':
|
||||
case '?':
|
||||
case '!':
|
||||
case ':':
|
||||
case ',':
|
||||
$append = $last_char;
|
||||
if ($relative_url) {
|
||||
$relative_url = substr($relative_url, 0, -1);
|
||||
} else {
|
||||
$url = substr($url, 0, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
// set last_char to empty here, so the variable can be used later to
|
||||
// check whether a character was removed
|
||||
default:
|
||||
$last_char = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$short_url = ($hesk_settings['short_link'] && strlen($url) > 70 && $shortenLinks) ? substr($url, 0, 54) . ' ... ' . substr($url, -10) : $url;
|
||||
|
||||
switch ($type) {
|
||||
case MAGIC_URL_LOCAL:
|
||||
$tag = 'l';
|
||||
$relative_url = preg_replace('/[&?]sid=[0-9a-f]{32}$/', '', preg_replace('/([&?])sid=[0-9a-f]{32}&/', '$1', $relative_url));
|
||||
$url = $url . '/' . $relative_url;
|
||||
$text = $relative_url;
|
||||
|
||||
// this url goes to http://domain.tld/path/to/board/ which
|
||||
// would result in an empty link if treated as local so
|
||||
// don't touch it and let MAGIC_URL_FULL take care of it.
|
||||
if (!$relative_url) {
|
||||
return $whitespace . $orig_url . '/' . $orig_relative; // slash is taken away by relative url pattern
|
||||
}
|
||||
break;
|
||||
|
||||
case MAGIC_URL_FULL:
|
||||
$tag = 'm';
|
||||
$text = $short_url;
|
||||
break;
|
||||
|
||||
case MAGIC_URL_WWW:
|
||||
$tag = 'w';
|
||||
$url = 'http://' . $url;
|
||||
$text = $short_url;
|
||||
break;
|
||||
|
||||
case MAGIC_URL_EMAIL:
|
||||
$tag = 'e';
|
||||
$text = $short_url;
|
||||
$url = 'mailto:' . $url;
|
||||
break;
|
||||
}
|
||||
|
||||
$url = htmlspecialchars($url);
|
||||
$text = htmlspecialchars($text);
|
||||
$append = htmlspecialchars($append);
|
||||
|
||||
$html = "$whitespace<a href=\"$url\" target=\"blank\" $class>$text</a>$append";
|
||||
|
||||
return $html;
|
||||
} // END make_clickable_callback()
|
||||
|
||||
static function fullNameToFirstName($full_name) {
|
||||
$name_parts = explode(' ', $full_name);
|
||||
|
||||
// Only one part, return back the original
|
||||
if (count($name_parts) < 2){
|
||||
return $full_name;
|
||||
}
|
||||
|
||||
$first_name = self::heskMbStrToLower($name_parts[0]);
|
||||
|
||||
// Name prefixes without dots
|
||||
$prefixes = array('mr', 'ms', 'mrs', 'miss', 'dr', 'rev', 'fr', 'sr', 'prof', 'sir');
|
||||
|
||||
if (in_array($first_name, $prefixes) || in_array($first_name, array_map(function ($i) {return $i . '.';}, $prefixes))) {
|
||||
if(isset($name_parts[2])) {
|
||||
// Mr James Smith -> James
|
||||
$first_name = $name_parts[1];
|
||||
} else {
|
||||
// Mr Smith (no first name given)
|
||||
return $full_name;
|
||||
}
|
||||
}
|
||||
|
||||
// Detect LastName, FirstName
|
||||
if (self::heskMbSubstr($first_name, -1, 1) == ',') {
|
||||
if (count($name_parts) == 2) {
|
||||
$first_name = $name_parts[1];
|
||||
} else {
|
||||
return $full_name;
|
||||
}
|
||||
}
|
||||
|
||||
// If the first name doesn't have at least 3 chars, return the original
|
||||
if(self::heskMbStrlen($first_name) < 3) {
|
||||
return $full_name;
|
||||
}
|
||||
|
||||
// Return the name with first character uppercase
|
||||
return self::heskUcfirst($first_name);
|
||||
}
|
||||
|
||||
static function heskMbStrToLower($in) {
|
||||
return function_exists('mb_strtolower') ? mb_strtolower($in) : strtolower($in);
|
||||
}
|
||||
|
||||
static function heskMbStrlen($in) {
|
||||
return function_exists('mb_strlen') ? mb_strlen($in, 'UTF-8') : strlen($in);
|
||||
}
|
||||
|
||||
static function heskMbSubstr($in, $start, $length) {
|
||||
return function_exists('mb_substr') ? mb_substr($in, $start, $length, 'UTF-8') : substr($in, $start, $length);
|
||||
}
|
||||
|
||||
static function heskUcfirst($in) {
|
||||
return function_exists('mb_convert_case') ? mb_convert_case($in, MB_CASE_TITLE, 'UTF-8') : ucfirst($in);
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
|
||||
class CustomNavElement extends \BaseClass {
|
||||
/* @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;
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
// TODO Test!
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use DataAccess\Navigation\CustomNavElementGateway;
|
||||
|
||||
class CustomNavElementHandler extends \BaseClass {
|
||||
/* @var $customNavElementGateway CustomNavElementGateway */
|
||||
private $customNavElementGateway;
|
||||
|
||||
function __construct(CustomNavElementGateway $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);
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
|
||||
class CustomNavElementPlace extends \BaseClass {
|
||||
const HOMEPAGE_BLOCK = 1;
|
||||
const CUSTOMER_NAVIGATION = 2;
|
||||
const ADMIN_NAVIGATION = 3;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Navigation;
|
||||
|
||||
|
||||
class Direction extends \BaseClass {
|
||||
const UP = 'up';
|
||||
const DOWN = 'down';
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
use DataAccess\Security\BanGateway;
|
||||
|
||||
class BanRetriever extends \BaseClass {
|
||||
/**
|
||||
* @var BanGateway
|
||||
*/
|
||||
private $banGateway;
|
||||
|
||||
function __construct(BanGateway $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;
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class BannedEmail extends \BaseClass {
|
||||
/**
|
||||
* @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;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class BannedIp extends \BaseClass {
|
||||
/**
|
||||
* @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;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class PermissionChecker extends \BaseClass {
|
||||
/**
|
||||
* @param $userContext UserContext
|
||||
* @param $permission string
|
||||
* @return bool
|
||||
*/
|
||||
function doesUserHavePermission($userContext, $permission) {
|
||||
if ($userContext->admin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($permission, $userContext->permissions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
use BusinessLogic\Helpers;
|
||||
|
||||
class UserContext extends \BaseClass {
|
||||
/* @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;
|
||||
|
||||
function isAnonymousUser() {
|
||||
return $this->id === -1;
|
||||
}
|
||||
|
||||
static function buildAnonymousUser() {
|
||||
$userContext = new UserContext();
|
||||
$userContext->id = -1;
|
||||
$userContext->username = "API - ANONYMOUS USER"; // Usernames can't have spaces, so no one will take this username
|
||||
$userContext->admin = false;
|
||||
$userContext->name = "ANONYMOUS USER";
|
||||
$userContext->email = "anonymous-user@example.com";
|
||||
$userContext->categories = array();
|
||||
$userContext->permissions = array();
|
||||
$userContext->autoAssign = false;
|
||||
$userContext->active = true;
|
||||
|
||||
return $userContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = Helpers::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 = Helpers::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 = Helpers::boolval($dataRow['active']);
|
||||
|
||||
$preferences = new UserContextPreferences();
|
||||
$preferences->afterReply = intval($dataRow['afterreply']);
|
||||
$preferences->autoStartTimeWorked = Helpers::boolval($dataRow['autostart']);
|
||||
$preferences->autoreload = intval($dataRow['autoreload']);
|
||||
$preferences->defaultNotifyCustomerNewTicket = Helpers::boolval($dataRow['notify_customer_new']);
|
||||
$preferences->defaultNotifyCustomerReply = Helpers::boolval($dataRow['notify_customer_reply']);
|
||||
$preferences->showSuggestedKnowledgebaseArticles = Helpers::boolval($dataRow['show_suggested']);
|
||||
$preferences->defaultCalendarView = intval($dataRow['default_calendar_view']);
|
||||
$preferences->defaultTicketView = $dataRow['default_list'];
|
||||
$userContext->preferences = $preferences;
|
||||
|
||||
$notifications = new UserContextNotifications();
|
||||
$notifications->newUnassigned = Helpers::boolval($dataRow['notify_new_unassigned']);
|
||||
$notifications->newAssignedToMe = Helpers::boolval($dataRow['notify_new_my']);
|
||||
$notifications->replyUnassigned = Helpers::boolval($dataRow['notify_reply_unassigned']);
|
||||
$notifications->replyToMe = Helpers::boolval($dataRow['notify_reply_my']);
|
||||
$notifications->ticketAssignedToMe = Helpers::boolval($dataRow['notify_assigned']);
|
||||
$notifications->privateMessage = Helpers::boolval($dataRow['notify_pm']);
|
||||
$notifications->noteOnTicketAssignedToMe = Helpers::boolval($dataRow['notify_note']);
|
||||
$notifications->noteOnTicketNotAssignedToMe = Helpers::boolval($dataRow['notify_note_unassigned']);
|
||||
$notifications->overdueTicketUnassigned = Helpers::boolval($dataRow['notify_overdue_unassigned']);
|
||||
$userContext->notificationSettings = $notifications;
|
||||
|
||||
return $userContext;
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
use BusinessLogic\Exceptions\InvalidAuthenticationTokenException;
|
||||
use BusinessLogic\Exceptions\MissingAuthenticationTokenException;
|
||||
use BusinessLogic\Helpers;
|
||||
use DataAccess\Security\UserGateway;
|
||||
|
||||
class UserContextBuilder extends \BaseClass {
|
||||
/**
|
||||
* @var UserGateway
|
||||
*/
|
||||
private $userGateway;
|
||||
|
||||
function __construct(UserGateway $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;
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class UserContextNotifications extends \BaseClass {
|
||||
public $newUnassigned;
|
||||
public $newAssignedToMe;
|
||||
public $replyUnassigned;
|
||||
public $replyToMe;
|
||||
public $ticketAssignedToMe;
|
||||
public $privateMessage;
|
||||
public $noteOnTicketAssignedToMe;
|
||||
public $noteOnTicketNotAssignedToMe;
|
||||
public $overdueTicketUnassigned;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class UserContextPreferences extends \BaseClass {
|
||||
public $afterReply;
|
||||
public $autoStartTimeWorked;
|
||||
public $autoreload;
|
||||
public $defaultNotifyCustomerNewTicket;
|
||||
public $defaultNotifyCustomerReply;
|
||||
public $showSuggestedKnowledgebaseArticles;
|
||||
public $defaultCalendarView;
|
||||
public $defaultTicketView;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: mkoch
|
||||
* Date: 3/12/2017
|
||||
* Time: 12:11 PM
|
||||
*/
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
class UserPrivilege extends \BaseClass {
|
||||
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';
|
||||
const CAN_MANAGE_CATEGORIES = 'can_man_cat';
|
||||
const CAN_VIEW_ASSIGNED_TO_OTHER = 'can_view_ass_others';
|
||||
const CAN_VIEW_UNASSIGNED = 'can_view_unassigned';
|
||||
const CAN_VIEW_ASSIGNED_BY_ME = 'can_view_ass_by';
|
||||
const CAN_MANAGE_SERVICE_MESSAGES = 'can_service_msg';
|
||||
const CAN_CHANGE_DUE_DATE = 'can_change_due_date';
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Security;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\Ticket;
|
||||
use DataAccess\Security\UserGateway;
|
||||
|
||||
class UserToTicketChecker extends \BaseClass {
|
||||
/* @var $userGateway UserGateway */
|
||||
private $userGateway;
|
||||
|
||||
function __construct(UserGateway $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(UserPrivilege::CAN_VIEW_ASSIGNED_BY_ME, $user->permissions) &&
|
||||
$ticket->assignedBy === $user->id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!in_array($ticket->categoryId, $user->categories)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$categoryManager = $this->userGateway->getManagerForCategory($ticket->categoryId, $heskSettings);
|
||||
|
||||
if ($categoryManager !== null && $user->id === $categoryManager->id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$extraPermissions[] = UserPrivilege::CAN_VIEW_TICKETS;
|
||||
|
||||
foreach ($extraPermissions as $permission) {
|
||||
if (!in_array($permission, $user->permissions)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\ServiceMessages;
|
||||
|
||||
|
||||
class GetServiceMessagesFilter {
|
||||
/* @var $includeStaffServiceMessages bool */
|
||||
public $includeStaffServiceMessages = true;
|
||||
|
||||
/* @var $includeDrafts bool */
|
||||
public $includeDrafts = true;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\ServiceMessages;
|
||||
|
||||
|
||||
class ServiceMessage extends \BaseClass {
|
||||
/* @var $id int */
|
||||
public $id;
|
||||
|
||||
/* @var $dateCreated string */
|
||||
public $dateCreated;
|
||||
|
||||
/* @var $createdBy int */
|
||||
public $createdBy;
|
||||
|
||||
/* @var $title string */
|
||||
public $title;
|
||||
|
||||
/* @var $message string */
|
||||
public $message;
|
||||
|
||||
/* @var $style string */
|
||||
public $style;
|
||||
|
||||
/* @var $published bool */
|
||||
public $published;
|
||||
|
||||
/* @var $order int */
|
||||
public $order;
|
||||
|
||||
/* @var $icon string */
|
||||
public $icon;
|
||||
|
||||
/* @var $locations string[] */
|
||||
public $locations;
|
||||
|
||||
/* @var $language string */
|
||||
public $language;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue