Update to 2018.2.0
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
define('IN_SCRIPT',1);
|
||||
define('HESK_PATH','../');
|
||||
|
||||
/* Get all the required files and functions */
|
||||
require(HESK_PATH . 'hesk_settings.inc.php');
|
||||
require(HESK_PATH . 'inc/common.inc.php');
|
||||
require(HESK_PATH . 'inc/admin_functions.inc.php');
|
||||
require(HESK_PATH . 'inc/privacy_functions.inc.php');
|
||||
hesk_load_database_functions();
|
||||
|
||||
hesk_session_start();
|
||||
hesk_dbConnect();
|
||||
hesk_isLoggedIn();
|
||||
|
||||
// Check permissions for this feature
|
||||
hesk_checkPermission('can_privacy');
|
||||
|
||||
// A security check
|
||||
hesk_token_check();
|
||||
|
||||
// Tracking ID
|
||||
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
|
||||
|
||||
// Anonymize the ticket and redirect back
|
||||
if (hesk_anonymizeTicket(0, $trackingID))
|
||||
{
|
||||
hesk_process_messages($hesklang['success_anon'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
|
||||
}
|
||||
|
||||
hesk_error($hesklang['no_permission']);
|
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
define('IN_SCRIPT',1);
|
||||
define('HESK_PATH','../');
|
||||
|
||||
/* Get all the required files and functions */
|
||||
require(HESK_PATH . 'hesk_settings.inc.php');
|
||||
require(HESK_PATH . 'inc/common.inc.php');
|
||||
require(HESK_PATH . 'inc/admin_functions.inc.php');
|
||||
require(HESK_PATH . 'inc/privacy_functions.inc.php');
|
||||
hesk_load_database_functions();
|
||||
|
||||
hesk_session_start();
|
||||
hesk_dbConnect();
|
||||
hesk_isLoggedIn();
|
||||
|
||||
// Check permissions for this feature
|
||||
hesk_checkPermission('can_export');
|
||||
|
||||
// A security check
|
||||
hesk_token_check();
|
||||
|
||||
// Tracking ID
|
||||
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
|
||||
|
||||
// Generate SQL for the ticket, make sure the user has access to it
|
||||
$sql = "SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `trackid`='".hesk_dbEscape($trackingID)."' AND ";
|
||||
$sql .= hesk_myCategories();
|
||||
$sql .= " AND " . hesk_myOwnership();
|
||||
$sql .= " LIMIT 1";
|
||||
|
||||
require_once(HESK_PATH . 'inc/custom_fields.inc.php');
|
||||
require_once(HESK_PATH . 'inc/statuses.inc.php');
|
||||
require(HESK_PATH . 'inc/export_functions.inc.php');
|
||||
|
||||
list($success_msg, $tickets_exported) = hesk_export_to_XML($sql, true);
|
||||
|
||||
if ($tickets_exported == 1)
|
||||
{
|
||||
hesk_process_messages($success_msg,'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
|
||||
}
|
||||
|
||||
hesk_error($hesklang['n2ex']);
|
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
class CreateReplyRequest {
|
||||
public $ticketId;
|
||||
public $trackingId;
|
||||
public $emailAddress;
|
||||
public $replyMessage;
|
||||
public $hasHtml;
|
||||
public $ipAddress;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
class CustomerCreatedReplyModel {
|
||||
public $id;
|
||||
public $ticketId;
|
||||
public $replierName;
|
||||
public $message;
|
||||
public $dateCreated;
|
||||
public $html;
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
namespace BusinessLogic\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Emails\Addressees;
|
||||
use BusinessLogic\Emails\EmailSenderHelper;
|
||||
use BusinessLogic\Emails\EmailTemplateRetriever;
|
||||
use BusinessLogic\Exceptions\ApiFriendlyException;
|
||||
use BusinessLogic\Exceptions\ValidationException;
|
||||
use BusinessLogic\Helpers;
|
||||
use BusinessLogic\Security\UserContext;
|
||||
use BusinessLogic\Statuses\Closable;
|
||||
use BusinessLogic\Statuses\DefaultStatusForAction;
|
||||
use BusinessLogic\ValidationModel;
|
||||
use DataAccess\AuditTrail\AuditTrailGateway;
|
||||
use DataAccess\Security\LoginGateway;
|
||||
use DataAccess\Security\UserGateway;
|
||||
use DataAccess\Statuses\StatusGateway;
|
||||
use DataAccess\Tickets\ReplyGateway;
|
||||
use DataAccess\Tickets\TicketGateway;
|
||||
|
||||
class ReplyCreator extends \BaseClass {
|
||||
private $statusGateway;
|
||||
private $ticketGateway;
|
||||
private $emailSenderHelper;
|
||||
private $userGateway;
|
||||
private $auditTrailGateway;
|
||||
private $loginGateway;
|
||||
private $replyGateway;
|
||||
|
||||
public function __construct(StatusGateway $statusGateway,
|
||||
TicketGateway $ticketGateway,
|
||||
EmailSenderHelper $emailSenderHelper,
|
||||
UserGateway $userGateway,
|
||||
AuditTrailGateway $auditTrailGateway,
|
||||
LoginGateway $loginGateway,
|
||||
ReplyGateway $replyGateway) {
|
||||
$this->statusGateway = $statusGateway;
|
||||
$this->ticketGateway = $ticketGateway;
|
||||
$this->emailSenderHelper = $emailSenderHelper;
|
||||
$this->userGateway = $userGateway;
|
||||
$this->auditTrailGateway = $auditTrailGateway;
|
||||
$this->loginGateway = $loginGateway;
|
||||
$this->replyGateway = $replyGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $replyRequest CreateReplyRequest
|
||||
* @param $heskSettings array
|
||||
* @param $modsForHeskSettings array
|
||||
* @throws ApiFriendlyException
|
||||
* @throws \Exception
|
||||
*/
|
||||
function createReplyByCustomer($replyRequest, $heskSettings, $modsForHeskSettings) {
|
||||
$ticket = $this->ticketGateway->getTicketByTrackingId($replyRequest->trackingId, $heskSettings);
|
||||
|
||||
if ($ticket === null) {
|
||||
throw new ApiFriendlyException("Ticket with tracking ID {$replyRequest->trackingId} not found.",
|
||||
"Ticket not found", 404);
|
||||
}
|
||||
|
||||
$validationModel = new ValidationModel();
|
||||
if ($ticket->id !== $replyRequest->ticketId) {
|
||||
$validationModel->errorKeys[] = 'TICKET_ID_TRACKING_NUMBER_MISMATCH';
|
||||
}
|
||||
if ($replyRequest->replyMessage === null || trim($replyRequest->replyMessage) === '') {
|
||||
$validationModel->errorKeys[] = 'MESSAGE_REQUIRED';
|
||||
}
|
||||
|
||||
if ($replyRequest->ipAddress === null || trim($replyRequest->ipAddress) === '') {
|
||||
$validationModel->errorKeys[] = 'IP_REQUIRED';
|
||||
}
|
||||
|
||||
if ($replyRequest->hasHtml === null) {
|
||||
$validationModel->errorKeys[] = 'HAS_HTML_REQUIRED';
|
||||
}
|
||||
|
||||
if ($heskSettings['email_view_ticket']) {
|
||||
if ($replyRequest->emailAddress === null || trim($replyRequest->emailAddress) === '') {
|
||||
$validationModel->errorKeys[] = 'EMAIL_REQUIRED';
|
||||
} elseif (!in_array($replyRequest->emailAddress, $ticket->email)) {
|
||||
$validationModel->errorKeys[] = 'EMAIL_NOT_FOUND_ON_TICKET';
|
||||
}
|
||||
}
|
||||
|
||||
if (count($validationModel->errorKeys) > 0) {
|
||||
throw new ValidationException($validationModel);
|
||||
}
|
||||
|
||||
if ($replyRequest->hasHtml) {
|
||||
$replyRequest->replyMessage = Helpers::heskMakeUrl($replyRequest->replyMessage);
|
||||
$replyRequest->replyMessage = nl2br($replyRequest->replyMessage);
|
||||
}
|
||||
|
||||
if ($this->loginGateway->isIpLockedOut($replyRequest->ipAddress, $heskSettings)) {
|
||||
throw new ApiFriendlyException("The IP address entered has been locked out of the system for {$heskSettings['attempt_banmin']} minutes because of too many login failures",
|
||||
"Locked Out",
|
||||
403);
|
||||
}
|
||||
|
||||
if ($this->ticketGateway->areRepliesBeingFlooded($replyRequest->ticketId, $replyRequest->ipAddress, $heskSettings)) {
|
||||
throw new ApiFriendlyException("You have been locked out of the system for {$heskSettings['attempt_banmin']} minutes because of too many replies to a ticket.",
|
||||
"Locked Out",
|
||||
403);
|
||||
}
|
||||
|
||||
// If staff hasn't replied yet, don't change the status; otherwise set it to the status for customer replies
|
||||
$currentStatus = $this->statusGateway->getStatusById($ticket->statusId, $heskSettings);
|
||||
if ($currentStatus->closable === Closable::YES || $currentStatus->closable === Closable::CUSTOMERS_ONLY) {
|
||||
$customerReplyStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::CUSTOMER_REPLY, $heskSettings);
|
||||
$defaultNewTicketStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings);
|
||||
|
||||
$ticket->statusId = $ticket->statusId === $defaultNewTicketStatus->id ?
|
||||
$defaultNewTicketStatus->id :
|
||||
$customerReplyStatus->id;
|
||||
}
|
||||
|
||||
$this->ticketGateway->updateMetadataForReply($ticket->id, $ticket->statusId, $heskSettings);
|
||||
$createdReply = $this->replyGateway->insertReply($ticket->id, $ticket->name, $replyRequest->replyMessage, $replyRequest->hasHtml, $heskSettings);
|
||||
|
||||
//-- Changing the ticket message to the reply's
|
||||
$ticket->message = $replyRequest->replyMessage;
|
||||
|
||||
$addressees = new Addressees();
|
||||
if ($ticket->ownerId !== null && $ticket->ownerId !== 0) {
|
||||
$owner = $this->userGateway->getUserById($ticket->ownerId, $heskSettings);
|
||||
|
||||
if ($owner->notificationSettings->replyToMe) {
|
||||
$addressees->to[] = $owner->email;
|
||||
$language = $owner->language === null ? $heskSettings['language'] : $owner->language;
|
||||
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_REPLY_BY_CUSTOMER,
|
||||
$language,
|
||||
$addressees,
|
||||
$ticket,
|
||||
$heskSettings,
|
||||
$modsForHeskSettings);
|
||||
}
|
||||
} else {
|
||||
$users = $this->userGateway->getUsersForUnassignedReplyNotification($heskSettings);
|
||||
foreach ($users as $user) {
|
||||
$addressees->to[] = $user->email;
|
||||
$language = $user->language === null ? $heskSettings['language'] : $user->language;
|
||||
|
||||
$this->emailSenderHelper->sendEmailForTicket(EmailTemplateRetriever::NEW_REPLY_BY_CUSTOMER,
|
||||
$language,
|
||||
$addressees,
|
||||
$ticket,
|
||||
$heskSettings,
|
||||
$modsForHeskSettings);
|
||||
}
|
||||
}
|
||||
|
||||
return $createdReply;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Controllers\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Helpers;
|
||||
use BusinessLogic\Tickets\CreateReplyRequest;
|
||||
use BusinessLogic\Tickets\ReplyCreator;
|
||||
use Controllers\JsonRetriever;
|
||||
use DataAccess\Settings\ModsForHeskSettingsGateway;
|
||||
|
||||
class CustomerReplyController extends \BaseClass {
|
||||
function post($ticketId) {
|
||||
global $applicationContext, $hesk_settings;
|
||||
|
||||
$jsonRequest = JsonRetriever::getJsonData();
|
||||
|
||||
$createReplyByCustomerModel = new CreateReplyRequest();
|
||||
$createReplyByCustomerModel->ticketId = intval($ticketId);
|
||||
$createReplyByCustomerModel->emailAddress = Helpers::safeArrayGet($jsonRequest, 'email');
|
||||
$createReplyByCustomerModel->trackingId = Helpers::safeArrayGet($jsonRequest, 'trackingId');
|
||||
$createReplyByCustomerModel->replyMessage = Helpers::safeArrayGet($jsonRequest, 'message');
|
||||
$html = Helpers::safeArrayGet($jsonRequest, 'html');
|
||||
$createReplyByCustomerModel->hasHtml = $html === null ? null : $html === true;
|
||||
$createReplyByCustomerModel->ipAddress = Helpers::safeArrayGet($jsonRequest, 'ip');
|
||||
|
||||
/* @var $modsForHeskSettingsGateway ModsForHeskSettingsGateway */
|
||||
$modsForHeskSettingsGateway = $applicationContext->get(ModsForHeskSettingsGateway::clazz());
|
||||
$modsForHesk_settings = $modsForHeskSettingsGateway->getAllSettings($hesk_settings);
|
||||
|
||||
/* @var $replyCreator ReplyCreator */
|
||||
$replyCreator = $applicationContext->get(ReplyCreator::clazz());
|
||||
$createdReply = $replyCreator->createReplyByCustomer($createReplyByCustomerModel, $hesk_settings, $modsForHesk_settings);
|
||||
|
||||
return output($createdReply, 201);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace DataAccess\Security;
|
||||
|
||||
|
||||
use DataAccess\CommonDao;
|
||||
|
||||
class LoginGateway extends CommonDao {
|
||||
function isIpLockedOut($ipAddress, $heskSettings) {
|
||||
$this->init();
|
||||
|
||||
$rs = hesk_dbQuery("SELECT `number` FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "logins`
|
||||
WHERE `ip` = '" . hesk_dbEscape($ipAddress) . "'
|
||||
AND `last_attempt` IS NOT NULL
|
||||
AND DATE_ADD(`last_attempt`, INTERVAL ".intval($heskSettings['attempt_banmin'])." MINUTE ) > NOW() LIMIT 1");
|
||||
|
||||
$result = hesk_dbNumRows($rs) == 1 &&
|
||||
hesk_dbResult($rs) >= $heskSettings['attempt_limit'];
|
||||
|
||||
$this->close();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace DataAccess\Tickets;
|
||||
|
||||
|
||||
use BusinessLogic\Tickets\CustomerCreatedReplyModel;
|
||||
use DataAccess\CommonDao;
|
||||
|
||||
class ReplyGateway extends CommonDao {
|
||||
function insertReply($ticketId, $name, $message, $html, $heskSettings) {
|
||||
$this->init();
|
||||
|
||||
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($heskSettings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`, `html`)
|
||||
VALUES ({$ticketId},'" . hesk_dbEscape($name) . "','" . hesk_dbEscape($message) . "',NOW(),'','" . $html . "')");
|
||||
|
||||
$customerCreatedReplyModel = new CustomerCreatedReplyModel();
|
||||
$id = hesk_dbInsertID();
|
||||
|
||||
$rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($heskSettings['db_pfix']) . "replies` WHERE `id` = " . intval($id));
|
||||
$row = hesk_dbFetchAssoc($rs);
|
||||
|
||||
$customerCreatedReplyModel->id = $row['id'];
|
||||
$customerCreatedReplyModel->message = $row['message'];
|
||||
$customerCreatedReplyModel->ticketId = $row['replyto'];
|
||||
$customerCreatedReplyModel->dateCreated = hesk_date($row['dt'], true);
|
||||
$customerCreatedReplyModel->html = $row['html'] === '1';
|
||||
$customerCreatedReplyModel->replierName = $row['name'];
|
||||
|
||||
$this->close();
|
||||
|
||||
return $customerCreatedReplyModel;
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?php
|
||||
|
||||
// Define the current build
|
||||
define('MODS_FOR_HESK_BUILD', 50);
|
||||
define('MODS_FOR_HESK_BUILD', 53);
|
||||
|
@ -0,0 +1,479 @@
|
||||
/* required styles */
|
||||
|
||||
.leaflet-map-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-pane,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-overlay-pane,
|
||||
.leaflet-shadow-pane,
|
||||
.leaflet-marker-pane,
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-overlay-pane svg,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container img {
|
||||
max-width: none !important;
|
||||
}
|
||||
/* stupid Android 2 doesn't understand "max-width: none" properly */
|
||||
.leaflet-container img.leaflet-image-layer {
|
||||
max-width: 15000px !important;
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-tile-pane { z-index: 2; }
|
||||
.leaflet-objects-pane { z-index: 3; }
|
||||
.leaflet-overlay-pane { z-index: 4; }
|
||||
.leaflet-shadow-pane { z-index: 5; }
|
||||
.leaflet-marker-pane { z-index: 6; }
|
||||
.leaflet-popup-pane { z-index: 7; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 7;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-tile,
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
-o-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-tile-loaded,
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile,
|
||||
.leaflet-touching .leaflet-zoom-animated {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
-o-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-container {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-container,
|
||||
.leaflet-dragging .leaflet-clickable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
}
|
||||
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline: 0;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-container a.leaflet-active {
|
||||
outline: 2px solid orange;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
.leaflet-control-zoom-out {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in {
|
||||
font-size: 22px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(../img/leaflet/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(../img/leaflet/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-container .leaflet-control-attribution,
|
||||
.leaflet-container .leaflet-control-scale {
|
||||
font-size: 11px;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 19px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 18px 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
margin: 0 auto;
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
-o-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 4px 4px 0 0;
|
||||
text-align: center;
|
||||
width: 18px;
|
||||
height: 14px;
|
||||
font: 16px/14px Tahoma, Verdana, sans-serif;
|
||||
color: #c3c3c3;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover {
|
||||
color: #999;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
After Width: | Height: | Size: 434 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 797 B |
@ -0,0 +1,383 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
/* Check if this is a valid include */
|
||||
if (!defined('IN_SCRIPT')) {die('Invalid attempt');}
|
||||
|
||||
/*** FUNCTIONS ***/
|
||||
|
||||
function hesk_export_to_XML($sql, $export_selected = false)
|
||||
{
|
||||
global $hesk_settings, $hesklang, $ticket, $my_cat;
|
||||
|
||||
// We'll need HH:MM:SS format for hesk_date() here
|
||||
$hesk_settings['timeformat'] = 'H:i:s';
|
||||
|
||||
// Get staff names
|
||||
$admins = array();
|
||||
$result = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` ORDER BY `name` ASC");
|
||||
while ($row = hesk_dbFetchAssoc($result)) {
|
||||
$admins[$row['id']] = $row['name'];
|
||||
}
|
||||
|
||||
// Get category names
|
||||
if ( ! isset($my_cat))
|
||||
{
|
||||
$my_cat = array();
|
||||
$res2 = hesk_dbQuery("SELECT `id`, `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."categories` WHERE " . hesk_myCategories('id') . " ORDER BY `cat_order` ASC");
|
||||
while ($row=hesk_dbFetchAssoc($res2))
|
||||
{
|
||||
$my_cat[$row['id']] = hesk_msgToPlain($row['name'], 1);
|
||||
}
|
||||
}
|
||||
|
||||
// This will be the export directory
|
||||
$export_dir = HESK_PATH.$hesk_settings['cache_dir'].'/';
|
||||
|
||||
// This will be the name of the export and the XML file
|
||||
$export_name = 'hesk_export_' . date('Y-m-d_H-i-s') . '_' . mt_rand(10000, 99999);
|
||||
$save_to = $export_dir . $export_name . '.xml';
|
||||
|
||||
// Do we have the export directory?
|
||||
if (is_dir($export_dir) || (@mkdir($export_dir, 0777) && is_writable($export_dir))) {
|
||||
// Is there an index.htm file?
|
||||
if (!file_exists($export_dir.'index.htm')) {
|
||||
@file_put_contents($export_dir.'index.htm', '');
|
||||
}
|
||||
|
||||
// Cleanup old files
|
||||
hesk_purge_cache('export', 86400);
|
||||
} else {
|
||||
hesk_error($hesklang['ede']);
|
||||
}
|
||||
|
||||
// Make sure the file can be saved and written to
|
||||
@file_put_contents($save_to, '');
|
||||
if (!file_exists($save_to)) {
|
||||
hesk_error($hesklang['eef']);
|
||||
}
|
||||
|
||||
// Start generating the report message and generating the export
|
||||
$success_msg = '';
|
||||
$flush_me = '<br /><br />';
|
||||
$flush_me .= hesk_date() . " | {$hesklang['inite']} ";
|
||||
|
||||
// Is this export of a date or date range?
|
||||
if ($export_selected === false)
|
||||
{
|
||||
global $date_from, $date_to;
|
||||
|
||||
if ($date_from == $date_to)
|
||||
{
|
||||
$flush_me .= "(" . hesk_dateToString($date_from,0) . ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
$flush_me .= "(" . hesk_dateToString($date_from,0) . " - " . hesk_dateToString($date_to,0) . ")";
|
||||
}
|
||||
}
|
||||
|
||||
// Start generating file contents
|
||||
$tmp = '<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?mso-application progid="Excel.Sheet"?>
|
||||
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||
xmlns:x="urn:schemas-microsoft-com:office:excel"
|
||||
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
|
||||
xmlns:html="http://www.w3.org/TR/REC-html40">
|
||||
<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
|
||||
<AllowPNG/>
|
||||
</OfficeDocumentSettings>
|
||||
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<WindowHeight>8250</WindowHeight>
|
||||
<WindowWidth>16275</WindowWidth>
|
||||
<WindowTopX>360</WindowTopX>
|
||||
<WindowTopY>90</WindowTopY>
|
||||
<ProtectStructure>False</ProtectStructure>
|
||||
<ProtectWindows>False</ProtectWindows>
|
||||
</ExcelWorkbook>
|
||||
<Styles>
|
||||
<Style ss:ID="Default" ss:Name="Normal">
|
||||
<Alignment ss:Vertical="Bottom"/>
|
||||
<Borders/>
|
||||
<Font ss:FontName="Calibri" x:CharSet="238" x:Family="Swiss" ss:Size="11"
|
||||
ss:Color="#000000"/>
|
||||
<Interior/>
|
||||
<NumberFormat/>
|
||||
<Protection/>
|
||||
</Style>
|
||||
<Style ss:ID="s62">
|
||||
<NumberFormat ss:Format="General Date"/>
|
||||
</Style>
|
||||
<Style ss:ID="s63">
|
||||
<NumberFormat ss:Format="Short Date"/>
|
||||
</Style>
|
||||
<Style ss:ID="s65">
|
||||
<NumberFormat ss:Format="[h]:mm:ss"/>
|
||||
</Style>
|
||||
</Styles>
|
||||
<Worksheet ss:Name="Sheet1">
|
||||
<Table>
|
||||
';
|
||||
|
||||
// Define column width
|
||||
$tmp .= '
|
||||
<Column ss:AutoFitWidth="0" ss:Width="50"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="84" ss:Span="1"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="110"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="110"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="90"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="90"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="87"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="57.75"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="57.75"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="100"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="100"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="80"/>
|
||||
<Column ss:AutoFitWidth="0" ss:Width="80"/>
|
||||
';
|
||||
|
||||
foreach ($hesk_settings['custom_fields'] as $k => $v) {
|
||||
if ($v['use']) {
|
||||
$tmp .= '<Column ss:AutoFitWidth="0" ss:Width="80"/>' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Define first row (header)
|
||||
$tmp .= '
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">#</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['trackID'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['date'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['last_update'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['name'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['email'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['category'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['priority'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['status'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['subject'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['message'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['owner'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String">' . $hesklang['ts'] . '</Data></Cell>
|
||||
';
|
||||
|
||||
foreach ($hesk_settings['custom_fields'] as $k => $v) {
|
||||
if ($v['use']) {
|
||||
$tmp .= '<Cell><Data ss:Type="String">' . $v['name'] . '</Data></Cell>' . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$tmp .= "</Row>\n";
|
||||
|
||||
// Write what we have by now into the XML file
|
||||
file_put_contents($save_to, $tmp, FILE_APPEND);
|
||||
$flush_me .= hesk_date() . " | {$hesklang['gXML']}<br />\n";
|
||||
|
||||
// OK, now start dumping data and writing it into the file
|
||||
$tickets_exported = 0;
|
||||
$save_after = 100;
|
||||
$this_round = 0;
|
||||
$tmp = '';
|
||||
|
||||
$result = hesk_dbQuery($sql);
|
||||
while ($ticket = hesk_dbFetchAssoc($result)) {
|
||||
$ticket['status'] = mfh_getDisplayTextForStatusId($ticket['status']);
|
||||
|
||||
switch ($ticket['priority']) {
|
||||
case 0:
|
||||
$ticket['priority'] = $hesklang['critical'];
|
||||
break;
|
||||
case 1:
|
||||
$ticket['priority'] = $hesklang['high'];
|
||||
break;
|
||||
case 2:
|
||||
$ticket['priority'] = $hesklang['medium'];
|
||||
break;
|
||||
default:
|
||||
$ticket['priority'] = $hesklang['low'];
|
||||
}
|
||||
|
||||
$ticket['archive'] = !($ticket['archive']) ? $hesklang['no'] : $hesklang['yes'];
|
||||
$ticket['message'] = hesk_msgToPlain($ticket['message'], 1, 0);
|
||||
$ticket['subject'] = hesk_msgToPlain($ticket['subject'], 1, 0);
|
||||
$ticket['owner'] = isset($admins[$ticket['owner']]) ? $admins[$ticket['owner']] : '';
|
||||
$ticket['category'] = isset($my_cat[$ticket['category']]) ? $my_cat[$ticket['category']] : '';
|
||||
|
||||
// Format for export dates
|
||||
$hesk_settings['timeformat'] = "Y-m-d\TH:i:s\.000";
|
||||
|
||||
// Create row for the XML file
|
||||
$tmp .= '
|
||||
<Row>
|
||||
<Cell><Data ss:Type="Number">' . $ticket['id'] . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['trackid'] . ']]></Data></Cell>
|
||||
<Cell ss:StyleID="s62"><Data ss:Type="DateTime">' . hesk_date($ticket['dt'], true) . '</Data></Cell>
|
||||
<Cell ss:StyleID="s62"><Data ss:Type="DateTime">' . hesk_date($ticket['lastchange'], true) . '</Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . hesk_msgToPlain($ticket['name'], 1) . ']]></Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['email'] . ']]></Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['category'] . ']]></Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['priority'] . ']]></Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['status'] . ']]></Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['subject'] . ']]></Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['message'] . ']]></Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['owner'] . ']]></Data></Cell>
|
||||
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['time_worked'] . ']]></Data></Cell>
|
||||
';
|
||||
|
||||
// Add custom fields
|
||||
foreach ($hesk_settings['custom_fields'] as $k=>$v) {
|
||||
if ($v['use']) {
|
||||
switch ($v['type']) {
|
||||
case 'date':
|
||||
$tmp_dt = hesk_custom_date_display_format($ticket[$k], 'Y-m-d\T00:00:00.000');
|
||||
$tmp .= strlen($tmp_dt) ? '<Cell ss:StyleID="s63"><Data ss:Type="DateTime">'.$tmp_dt : '<Cell><Data ss:Type="String">';
|
||||
$tmp .= "</Data></Cell> \n";
|
||||
break;
|
||||
default:
|
||||
$tmp .= '<Cell><Data ss:Type="String"><![CDATA['.hesk_msgToPlain($ticket[$k], 1, 0).']]></Data></Cell> ' . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tmp .= "</Row>\n";
|
||||
|
||||
// Write every 100 rows into the file
|
||||
if ($this_round >= $save_after) {
|
||||
file_put_contents($save_to, $tmp, FILE_APPEND);
|
||||
$this_round = 0;
|
||||
$tmp = '';
|
||||
usleep(1);
|
||||
}
|
||||
|
||||
$tickets_exported++;
|
||||
$this_round++;
|
||||
} // End of while loop
|
||||
|
||||
// Go back to the HH:MM:SS format for hesk_date()
|
||||
$hesk_settings['timeformat'] = 'H:i:s';
|
||||
|
||||
// Append any remaining rows into the file
|
||||
if ($this_round > 0) {
|
||||
file_put_contents($save_to, $tmp, FILE_APPEND);
|
||||
}
|
||||
|
||||
// If any tickets were exported, continue, otherwise cleanup
|
||||
if ($tickets_exported > 0) {
|
||||
// Finish the XML file
|
||||
$tmp = '
|
||||
</Table>
|
||||
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<PageSetup>
|
||||
<Header x:Margin="0.3"/>
|
||||
<Footer x:Margin="0.3"/>
|
||||
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
|
||||
</PageSetup>
|
||||
<Selected/>
|
||||
<Panes>
|
||||
<Pane>
|
||||
<Number>3</Number>
|
||||
<ActiveRow>4</ActiveRow>
|
||||
</Pane>
|
||||
</Panes>
|
||||
<ProtectObjects>False</ProtectObjects>
|
||||
<ProtectScenarios>False</ProtectScenarios>
|
||||
</WorksheetOptions>
|
||||
</Worksheet>
|
||||
<Worksheet ss:Name="Sheet2">
|
||||
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1"
|
||||
x:FullRows="1" ss:DefaultRowHeight="15">
|
||||
</Table>
|
||||
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<PageSetup>
|
||||
<Header x:Margin="0.3"/>
|
||||
<Footer x:Margin="0.3"/>
|
||||
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
|
||||
</PageSetup>
|
||||
<ProtectObjects>False</ProtectObjects>
|
||||
<ProtectScenarios>False</ProtectScenarios>
|
||||
</WorksheetOptions>
|
||||
</Worksheet>
|
||||
<Worksheet ss:Name="Sheet3">
|
||||
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1"
|
||||
x:FullRows="1" ss:DefaultRowHeight="15">
|
||||
</Table>
|
||||
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<PageSetup>
|
||||
<Header x:Margin="0.3"/>
|
||||
<Footer x:Margin="0.3"/>
|
||||
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
|
||||
</PageSetup>
|
||||
<ProtectObjects>False</ProtectObjects>
|
||||
<ProtectScenarios>False</ProtectScenarios>
|
||||
</WorksheetOptions>
|
||||
</Worksheet>
|
||||
</Workbook>
|
||||
';
|
||||
file_put_contents($save_to, $tmp, FILE_APPEND);
|
||||
|
||||
// Log how many rows we exported
|
||||
$flush_me .= hesk_date() . " | " . sprintf($hesklang['nrow'], $tickets_exported) . "<br />\n";
|
||||
|
||||
// We will convert XML to Zip to save a lot of space
|
||||
$save_to_zip = $export_dir . $export_name . '.zip';
|
||||
|
||||
// Log start of Zip creation
|
||||
$flush_me .= hesk_date() . " | {$hesklang['cZIP']}<br />\n";
|
||||
|
||||
// Preferrably use the zip extension
|
||||
if (extension_loaded('zip')) {
|
||||
$save_to_zip = $export_dir . $export_name . '.zip';
|
||||
|
||||
$zip = new ZipArchive;
|
||||
$res = $zip->open($save_to_zip, ZipArchive::CREATE);
|
||||
if ($res === TRUE) {
|
||||
$zip->addFile($save_to, "{$export_name}.xml");
|
||||
$zip->close();
|
||||
} else {
|
||||
die("{$hesklang['eZIP']} <$save_to_zip>\n");
|
||||
}
|
||||
|
||||
} // Some servers have ZipArchive class enabled anyway - can we use it?
|
||||
elseif (class_exists('ZipArchive')) {
|
||||
require(HESK_PATH . 'inc/zip/Zip.php');
|
||||
$zip = new Zip();
|
||||
$zip->addLargeFile($save_to, "{$export_name}.xml");
|
||||
$zip->finalize();
|
||||
$zip->setZipFile($save_to_zip);
|
||||
} // If not available, use a 3rd party Zip class included with HESK
|
||||
else {
|
||||
require(HESK_PATH . 'inc/zip/pclzip.lib.php');
|
||||
$zip = new PclZip($save_to_zip);
|
||||
$zip->add($save_to, PCLZIP_OPT_REMOVE_ALL_PATH);
|
||||
}
|
||||
|
||||
// Delete XML, just leave the Zip archive
|
||||
hesk_unlink($save_to);
|
||||
|
||||
// Echo memory peak usage
|
||||
$flush_me .= hesk_date() . " | " . sprintf($hesklang['pmem'], (@memory_get_peak_usage(true) / 1048576)) . "<br />\r\n";
|
||||
|
||||
// We're done!
|
||||
$flush_me .= hesk_date() . " | {$hesklang['fZIP']}<br /><br />";
|
||||
|
||||
// Success message
|
||||
$success_msg .= $hesk_settings['debug_mode'] ? $flush_me : '<br /><br />';
|
||||
$success_msg .= $hesklang['step1'] . ': <a href="' . $save_to_zip . '">' . $hesklang['ch2d'] . '</a><br /><br />' . $hesklang['step2'] . ': <a href="export.php?delete='.urlencode($export_name).'">' . $hesklang['dffs'] . '</a>';
|
||||
} // No tickets exported, cleanup
|
||||
else {
|
||||
hesk_unlink($save_to);
|
||||
}
|
||||
|
||||
return array($success_msg, $tickets_exported);
|
||||
|
||||
} // END hesk_export_to_XML()
|
@ -0,0 +1,151 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
/* Check if this is a valid include */
|
||||
if (!defined('IN_SCRIPT')) {die('Invalid attempt');}
|
||||
|
||||
// Ticket priority
|
||||
switch ($ticket['priority']) {
|
||||
case 0:
|
||||
$ticket['priority'] = '<b>' . $hesklang['critical'] . '</b>';
|
||||
break;
|
||||
case 1:
|
||||
$ticket['priority'] = '<b>' . $hesklang['high'] . '</b>';
|
||||
break;
|
||||
case 2:
|
||||
$ticket['priority'] = $hesklang['medium'];
|
||||
break;
|
||||
default:
|
||||
$ticket['priority'] = $hesklang['low'];
|
||||
}
|
||||
|
||||
// Set last replier name
|
||||
if ($ticket['lastreplier']) {
|
||||
if (empty($ticket['repliername'])) {
|
||||
$ticket['repliername'] = $hesklang['staff'];
|
||||
}
|
||||
} else {
|
||||
$ticket['repliername'] = $ticket['name'];
|
||||
}
|
||||
|
||||
// Other variables that need processing
|
||||
$ticket['dt'] = hesk_date($ticket['dt'], true);
|
||||
$ticket['lastchange'] = hesk_date($ticket['lastchange'], true);
|
||||
$random = mt_rand(10000, 99999);
|
||||
|
||||
// Print ticket head
|
||||
echo '
|
||||
<h3>' . $ticket['subject'] . '</h3>
|
||||
<hr/>
|
||||
<table border="1" bordercolor="#FFFFFF" cellspacing="0" cellpadding="2" width="100%">
|
||||
|
||||
<tr>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['trackID'] . ':</b></td><td bgcolor="#DDD">' . $ticket['trackid'] . '</td>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['ticket_status'] . ':</b></td><td bgcolor="#DDD">' . $hesklang[$ticket['statusKey']] . '</td>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['created_on'] . ':</b></td><td bgcolor="#DDD">' . $ticket['dt'] . '</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['last_update'] . ':</b></td><td bgcolor="#DDD">' . $ticket['lastchange'] . '</td>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['last_replier'] . ':</b></td><td bgcolor="#DDD">' . $ticket['repliername'] . '</td>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['category'] . ':</b></td><td bgcolor="#DDD">' . $category['name'] . '</td>
|
||||
</tr>
|
||||
';
|
||||
|
||||
// Show IP and time worked to staff
|
||||
if (!empty($_SESSION['id'])) {
|
||||
echo '
|
||||
<tr>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['ts'] . ':</b></td><td bgcolor="#DDD">' . $ticket['time_worked'] . '</td>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['ip'] . ':</b></td><td bgcolor="#DDD">' . $ticket['ip'] . '</td>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['email'] . ':</b></td><td bgcolor="#DDD">' . $ticket['email'] . '</td>
|
||||
</tr>
|
||||
';
|
||||
}
|
||||
|
||||
echo '<tr>';
|
||||
// Assigned to?
|
||||
if ($ticket['owner'] && !empty($_SESSION['id'])) {
|
||||
$ticket['owner'] = hesk_getOwnerName($ticket['owner']);
|
||||
echo '
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['taso3'] . '</b></td>
|
||||
<td bgcolor="#DDD">' . $ticket['owner'] . '</td>
|
||||
';
|
||||
}
|
||||
|
||||
|
||||
echo '
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['name'] . ':</b></td>
|
||||
<td bgcolor="#DDD">' . $ticket['name'] . '</td>
|
||||
';
|
||||
echo '</tr>';
|
||||
|
||||
// Custom fields
|
||||
$num_cols = 0;
|
||||
echo '<tr>';
|
||||
foreach ($hesk_settings['custom_fields'] as $k => $v) {
|
||||
if (($v['use'] == 1 || (! empty($_SESSION['id']) && $v['use'] == 2)) && hesk_is_custom_field_in_category($k, $ticket['category'])) {
|
||||
if ($num_cols == 3) {
|
||||
echo '</tr><tr>';
|
||||
$num_cols = 0;
|
||||
}
|
||||
|
||||
switch ($v['type']) {
|
||||
case 'date':
|
||||
$ticket[$k] = hesk_custom_date_display_format($ticket[$k], $v['value']['date_format']);
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<td bgcolor="#EEE"><b><?php echo $v['name']; ?>:</b></td>
|
||||
<td bgcolor="#DDD"><?php echo hesk_unhortenUrl($ticket[$k]); ?></td>
|
||||
<?php
|
||||
$num_cols++;
|
||||
}
|
||||
}
|
||||
|
||||
// Close ticket head table
|
||||
echo '</table><br>';
|
||||
|
||||
// Print initial ticket message
|
||||
if ($ticket['message'] != '') {
|
||||
$newMessage = hesk_unhortenUrl($ticket['message']);
|
||||
if ($ticket['html']) {
|
||||
$newMessage = hesk_html_entity_decode($newMessage);
|
||||
}
|
||||
echo '<p>' . $newMessage . '</p>';
|
||||
}
|
||||
|
||||
|
||||
// Print replies
|
||||
while ($reply = hesk_dbFetchAssoc($res)) {
|
||||
$reply['dt'] = hesk_date($reply['dt'], true);
|
||||
$theReply = hesk_unhortenUrl($reply['message']);
|
||||
if ($reply['html']) {
|
||||
$theReply = hesk_html_entity_decode($theReply);
|
||||
}
|
||||
|
||||
echo '
|
||||
<hr />
|
||||
|
||||
<table border="1" bordercolor="#FFFFFF" cellspacing="0" cellpadding="2" width="100%">
|
||||
<tr>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['date'] . ':</b></td><td bgcolor="#DDD">' . $reply['dt'] . '</td>
|
||||
<td bgcolor="#EEE"><b>' . $hesklang['name'] . ':</b></td><td bgcolor="#DDD">' . $reply['name'] . '</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="message">' . $theReply . '</div>
|
||||
';
|
||||
}
|
||||
|
||||
// Print "end of ticket" message
|
||||
echo '<div style="page-break-after: always">' . $hesklang['end_ticket'] . "</div>";
|
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of HESK - PHP Help Desk Software.
|
||||
*
|
||||
* (c) Copyright Klemen Stirn. All rights reserved.
|
||||
* https://www.hesk.com
|
||||
*
|
||||
* For the full copyright and license agreement information visit
|
||||
* https://www.hesk.com/eula.php
|
||||
*
|
||||
*/
|
||||
|
||||
/* Check if this is a valid include */
|
||||
if (!defined('IN_SCRIPT')) {die('Invalid attempt');}
|
||||
|
||||
|
||||
/*** FUNCTIONS ***/
|
||||
|
||||
|
||||
function hesk_anonymizeTicket($id, $trackingID = null, $have_ticket = false)
|
||||
{
|
||||
global $hesk_settings, $hesklang;
|
||||
|
||||
// Do we already have ticket info?
|
||||
if ($have_ticket)
|
||||
{
|
||||
global $ticket;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get ticket info by tracking or numerical ID
|
||||
if ($trackingID !== null)
|
||||
{
|
||||
$res = hesk_dbQuery("SELECT `id`, `trackid`, `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `trackid`='".hesk_dbEscape($trackingID)."' AND ".hesk_myOwnership());
|
||||
}
|
||||
else
|
||||
{
|
||||
$res = hesk_dbQuery("SELECT `id`, `trackid`, `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `id`=".intval($id)." AND ".hesk_myOwnership());
|
||||
}
|
||||
if ( ! hesk_dbNumRows($res))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$ticket = hesk_dbFetchAssoc($res);
|
||||
}
|
||||
|
||||
// Delete attachment files
|
||||
$res = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."attachments` WHERE `ticket_id`='".hesk_dbEscape($ticket['trackid'])."'");
|
||||
if (hesk_dbNumRows($res))
|
||||
{
|
||||
$hesk_settings['server_path'] = dirname(dirname(__FILE__));
|
||||
|
||||
while ($file = hesk_dbFetchAssoc($res))
|
||||
{
|
||||
hesk_unlink($hesk_settings['server_path'].'/'.$hesk_settings['attach_dir'].'/'.$file['saved_name']);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete attachments info from the database
|
||||
hesk_dbQuery("DELETE FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."attachments` WHERE `ticket_id`='".hesk_dbEscape($ticket['trackid'])."'");
|
||||
|
||||
// Anonymize ticket
|
||||
$sql = "UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET
|
||||
`name` = '".hesk_dbEscape($hesklang['anon_name'])."',
|
||||
`email` = '".hesk_dbEscape($hesklang['anon_email'])."',
|
||||
`subject` = '".hesk_dbEscape($hesklang['anon_subject'])."',
|
||||
`message` = '".hesk_dbEscape($hesklang['anon_message'])."',
|
||||
`ip` = '".hesk_dbEscape($hesklang['anon_IP'])."',
|
||||
`latitude`= 'E-6',
|
||||
`longitude`='E-6',
|
||||
`user_agent`= '" . hesk_dbEscape($hesklang['anon_user_agent']) . "',
|
||||
`screen_resolution_width`= '" . hesk_dbEscape($hesklang['anon_screen_resolution']) . "',
|
||||
`screen_resolution_height`= '" . hesk_dbEscape($hesklang['anon_screen_resolution']) . "',
|
||||
";
|
||||
for($i=1; $i<=50; $i++)
|
||||
{
|
||||
$sql .= "`custom{$i}` = '',";
|
||||
}
|
||||
$sql .= "
|
||||
attachments='',
|
||||
`history`=REPLACE(`history`, ' ".hesk_dbEscape(addslashes($ticket['name']))."</li>', ' ".hesk_dbEscape($hesklang['anon_name'])."</li>')
|
||||
WHERE `id`='".intval($ticket['id'])."'";
|
||||
hesk_dbQuery($sql);
|
||||
mfh_anonymize_audit_trail_records($ticket['id'],'TICKET', $ticket['name']);
|
||||
|
||||
// Anonymize replies
|
||||
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."replies` SET `name` = '".hesk_dbEscape($hesklang['anon_name'])."', `message` = '".hesk_dbEscape($hesklang['anon_message'])."', attachments='' WHERE `replyto`='".intval($ticket['id'])."'");
|
||||
|
||||
// Delete ticket notes
|
||||
hesk_dbQuery("DELETE FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."notes` WHERE `ticket`='".intval($ticket['id'])."'");
|
||||
|
||||
// Delete ticket reply drafts
|
||||
hesk_dbQuery("DELETE FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."reply_drafts` WHERE `ticket`=".intval($ticket['id']));
|
||||
|
||||
return true;
|
||||
} // END hesk_anonymizeTicket()
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 557 KiB |
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace vv201820;
|
||||
|
||||
|
||||
class MigrateServiceMessageLanguages extends \AbstractUpdatableMigration {
|
||||
function innerUp($hesk_settings) {
|
||||
// Get all service messages with non-null language (only HESK will populate this; MFH won't)
|
||||
$rs = hesk_dbQuery("SELECT `id`, `language` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages`
|
||||
WHERE `language` IS NOT NULL");
|
||||
|
||||
$languageMap = array();
|
||||
while ($row = hesk_dbFetchAssoc($rs)) {
|
||||
// Get the MFH language
|
||||
if (count($languageMap) === 0) {
|
||||
// Initialize the map for the first run
|
||||
foreach($hesk_settings['languages'] as $name => $info) {
|
||||
$languageMap[$name] = $info['folder'];
|
||||
}
|
||||
}
|
||||
|
||||
$mfh_language = $languageMap[$row['language']];
|
||||
|
||||
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages`
|
||||
SET `mfh_language` = '" . hesk_dbEscape($mfh_language) . "' WHERE `id` = " . intval($row['id']));
|
||||
}
|
||||
}
|
||||
|
||||
function innerDown($hesk_settings) {
|
||||
// Get all service messages with non-null language (only HESK will populate this; MFH won't)
|
||||
$rs = hesk_dbQuery("SELECT `id`, `mfh_language` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages`");
|
||||
|
||||
$language_map = array();
|
||||
while ($row = hesk_dbFetchAssoc($rs)) {
|
||||
// Get the language
|
||||
if (count($language_map) === 0) {
|
||||
// Initialize the map for the first run
|
||||
foreach($hesk_settings['languages'] as $name => $info) {
|
||||
$language_map[$info['folder']] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$language = $row['mfh_language'] === 'ALL' ? 'NULL' : "'" . hesk_dbEscape($language_map[$row['mfh_language']]) . "'";
|
||||
|
||||
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "service_messages`
|
||||
SET `language` = {$language} WHERE `id` = " . intval($row['id']));
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 797 B |
@ -1,56 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Interactive help for Hesk settings</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<link href="help_style.css" type="text/css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- next: 58 -->
|
||||
|
||||
<h2>Interactive help for Hesk settings</h2>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<a name="41"></a><h3>Custom fields</h3>
|
||||
|
||||
<p>Custom fields can be used to collect additional information from your customers. You can enable up to 20 custom fields by selecting YES in the Enable column. Once a field is enabled you have several options to set.</p>
|
||||
|
||||
<h4>Type</h4>
|
||||
<p>Choose field type. It can be one of the following options:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Text field</b> - a normal one-line text field (<input type="text">)</li>
|
||||
<li><b>Large text box</b> - text area, a larger text field with multiple lines (<textarea></textarea>)</li>
|
||||
<li><b>Radio button</b> - a radio button with at least two options (<input type="radio">)</li>
|
||||
<li><b>Select box</b> - a drop-down select box with at least two options (<select></select>)</li>
|
||||
<li><b>Checkbox</b> - checkbox with at least two options (<input type="checkbox">). Multiple options can be chosen (ticked).</li>
|
||||
</ul>
|
||||
|
||||
<h4>Required</h4>
|
||||
<p>Check to make the custom field a required, otherwise it is an optional one.</p>
|
||||
|
||||
<h4>Field name</h4>
|
||||
<p>Give the custom field a unique name that what will be displayed next to the field, for example "Postal address".</p>
|
||||
|
||||
<h4>Location</h4>
|
||||
<p>Choose whether the custom field should be displayed before or after the "Message" field when submitting a new support ticket.</p>
|
||||
|
||||
<h4>Options</h4>
|
||||
<p></p>Options you can set for each field depending on the selected Type:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>Text field</b> - you can set maximum input length (in chars) and default value</li>
|
||||
<li><b>Large text box</b> - you can set number of rows and columns (<textarea rows="<b>Y</b>" cols="<b>X</b>">)</li>
|
||||
<li><b>Radio button</b> - list radio button options, one per line</li>
|
||||
<li><b>Select box</b> - list select box options, one per line</li>
|
||||
</ul>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p align="center"><a href="#" onclick="Javascript:window.close()">Close window</a></p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|