diff --git a/.gitignore b/.gitignore index f601f707..a9854684 100644 --- a/.gitignore +++ b/.gitignore @@ -11,10 +11,9 @@ uploads/users/* !uploads/users/index.php uploads/tmp/* !uploads/tmp/index.php -backups/* -!backups/index.php -!backups/.htaccess +uploads/tickets/* +!uploads/tickets/index.php .idea/* plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/HTML/* plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/URI/* -plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/CSS/* \ No newline at end of file +plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/CSS/* diff --git a/cron_ticket_email_parser.php b/cron_ticket_email_parser.php index 1f74aaf4..d1df9746 100644 --- a/cron_ticket_email_parser.php +++ b/cron_ticket_email_parser.php @@ -37,6 +37,7 @@ if (!function_exists('mailparse_msg_parse_file')) { } // PHP Mail Parser +use PhpMimeMailParser\Parser; require_once("plugins/php-mime-mail-parser/src/Contracts/CharsetManager.php"); require_once("plugins/php-mime-mail-parser/src/Contracts/Middleware.php"); require_once("plugins/php-mime-mail-parser/src/Attachment.php"); @@ -47,9 +48,11 @@ require_once("plugins/php-mime-mail-parser/src/MiddlewareStack.php"); require_once("plugins/php-mime-mail-parser/src/MimePart.php"); require_once("plugins/php-mime-mail-parser/src/Parser.php"); +// Allowed attachment extensions +$allowed_extensions = array('jpg', 'jpeg', 'gif', 'png', 'webp', 'pdf', 'txt', 'md', 'doc', 'docx', 'csv', 'xls', 'xlsx', 'xlsm', 'zip', 'tar', 'gz'); // Function to raise a new ticket for a given contact and email them confirmation (if configured) -function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message) { +function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message, $attachments) { // Access global variables global $mysqli, $config_ticket_prefix, $config_ticket_client_general_notifications, $config_base_url, $config_ticket_from_name, $config_ticket_from_email, $config_smtp_host, $config_smtp_port, $config_smtp_encryption, $config_smtp_username, $config_smtp_password; @@ -71,6 +74,41 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date echo "Created new ticket.
"; mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Ticket', log_action = 'Create', log_description = 'Email parser: Client contact $contact_email created ticket $config_ticket_prefix$ticket_number ($subject) ($id)', log_client_id = $client_id"); + // Process attachments (after ticket is logged as created) + mkdirMissing('uploads/tickets/'); + foreach ($attachments as $attachment) { + + // Get name and extension + $att_name = $attachment->getFileName(); + $att_extarr = explode('.', $att_name); + $att_extension = strtolower(end($att_extarr)); + + // Check the extension is allowed + global $allowed_extensions; + if (in_array($att_extension, $allowed_extensions)) { + + // Setup directory for this ticket ID + $att_dir = "uploads/tickets/" . $id . "/"; + mkdirMissing($att_dir); + + // Save attachment with a random name + $att_saved_path = $attachment->save($att_dir, Parser::ATTACHMENT_RANDOM_FILENAME); + + // Access the random name to add into the database (this won't work on Windows) + $att_tmparr = explode($att_dir, $att_saved_path); + + $ticket_attachment_name = sanitizeInput($att_name); + $ticket_attachment_reference_name = sanitizeInput(end($att_tmparr)); + + mysqli_query($mysqli, "INSERT INTO ticket_attachments SET ticket_attachment_name = '$ticket_attachment_name', ticket_attachment_reference_name = '$ticket_attachment_reference_name', ticket_attachment_ticket_id = $id"); + + } else { + $ticket_attachment_name = sanitizeInput($att_name); + mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Ticket', log_action = 'Update', log_description = 'Email parser: Blocked attachment $ticket_attachment_name from Client contact $contact_email for ticket $config_ticket_prefix$ticket_number', log_client_id = $client_id"); + } + + } + // Get company name & phone $sql = mysqli_query($mysqli, "SELECT company_name, company_phone FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql); @@ -109,7 +147,7 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date } -function addReply($from_email, $date, $subject, $ticket_number, $message) { +function addReply($from_email, $date, $subject, $ticket_number, $message, $attachments) { // Add email as a comment/reply to an existing ticket // Access global variables @@ -170,6 +208,43 @@ function addReply($from_email, $date, $subject, $ticket_number, $message) { // Add the comment mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = '$comment', ticket_reply_type = '$ticket_reply_type', ticket_reply_time_worked = '00:00:00', ticket_reply_by = $ticket_reply_contact, ticket_reply_ticket_id = $ticket_id"); + $reply_id = mysqli_insert_id($mysqli); + + // Process attachments + mkdirMissing('uploads/tickets/'); + foreach ($attachments as $attachment) { + + // Get name and extension + $att_name = $attachment->getFileName(); + $att_extarr = explode('.', $att_name); + $att_extension = strtolower(end($att_extarr)); + + // Check the extension is allowed + global $allowed_extensions; + if (in_array($att_extension, $allowed_extensions)) { + + // Setup directory for this ticket ID + $att_dir = "uploads/tickets/" . $ticket_id . "/"; + mkdirMissing($att_dir); + + // Save attachment with a random name + $att_saved_path = $attachment->save($att_dir, Parser::ATTACHMENT_RANDOM_FILENAME); + + // Access the random name to add into the database (this won't work on Windows) + $att_tmparr = explode($att_dir, $att_saved_path); + + $ticket_attachment_name = sanitizeInput($att_name); + $ticket_attachment_reference_name = sanitizeInput(end($att_tmparr)); + + mysqli_query($mysqli, "INSERT INTO ticket_attachments SET ticket_attachment_name = '$ticket_attachment_name', ticket_attachment_reference_name = '$ticket_attachment_reference_name', ticket_attachment_reply_id = $reply_id, ticket_attachment_ticket_id = $ticket_id"); + + } else { + $ticket_attachment_name = sanitizeInput($att_name); + mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Ticket', log_action = 'Update', log_description = 'Email parser: Blocked attachment $ticket_attachment_name from Client contact $from_email for ticket $config_ticket_prefix$ticket_number', log_client_id = $client_id"); + } + + } + // Update Ticket Last Response Field & set ticket to open as client has replied mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 'Open' WHERE ticket_id = $ticket_id AND ticket_client_id = $client_id LIMIT 1"); @@ -234,16 +309,11 @@ if ($emails) { $subject = sanitizeInput($parser->getHeader('subject')); $date = trim(mysqli_real_escape_string($mysqli, htmlentities(strip_tags($parser->getHeader('date'))))); - + $attachments = $parser->getAttachments(); $message = $parser->getMessageBody('text'); //$message .= $parser->getMessageBody('htmlEmbedded'); - //$text = "Some Text"; - //$message = str_replace("", "

{$text}

", $message); - - - // Check if we can identify a ticket number (in square brackets) if (preg_match("/\[$config_ticket_prefix\d+\]/", $subject, $ticket_number)) { @@ -254,7 +324,7 @@ if ($emails) { preg_match('/\d+/', $ticket_number[0], $ticket_number); $ticket_number = intval($ticket_number[0]); - if (addReply($from_email, $date, $subject, $ticket_number, $message)) { + if (addReply($from_email, $date, $subject, $ticket_number, $message, $attachments)) { $email_processed = true; } @@ -272,7 +342,7 @@ if ($emails) { $contact_email = $row['contact_email']; $client_id = intval($row['contact_client_id']); - if (addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message)) { + if (addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message, $attachments)) { $email_processed = true; } @@ -301,7 +371,7 @@ if ($emails) { echo "Created new contact.
"; mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Contact', log_action = 'Create', log_description = 'Email parser: created contact $contact_name', log_client_id = $client_id"); - if (addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message)) { + if (addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message, $attachments)) { $email_processed = true; } diff --git a/database_updates.php b/database_updates.php index 1d121b63..d72000a4 100644 --- a/database_updates.php +++ b/database_updates.php @@ -947,17 +947,33 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { } if (CURRENT_DATABASE_VERSION == '0.4.9') { - // Insert queries here required to update to DB version 0.5.0 + // Insert queries here required to update to DB version 0.5.0 mysqli_query($mysqli, "ALTER TABLE `clients` ADD `client_tax_id_number` VARCHAR(255) NULL DEFAULT NULL AFTER `client_net_terms`"); - // Then, update the database to the next sequential version + // Then, update the database to the next sequential version mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '0.5.0'"); } - //if (CURRENT_DATABASE_VERSION == '0.5.0') { - // Insert queries here required to update to DB version 0.5.1 + if (CURRENT_DATABASE_VERSION == '0.5.0') { + // Insert queries here required to update to DB version 0.5.1 + mysqli_query($mysqli, "CREATE TABLE `ticket_attachments` ( + `ticket_attachment_id` int(11) NOT NULL AUTO_INCREMENT, + `ticket_attachment_name` varchar(255) NOT NULL, + `ticket_attachment_reference_name` varchar(255) NOT NULL, + `ticket_attachment_created_at` datetime NOT NULL DEFAULT current_timestamp(), + `ticket_attachment_ticket_id` int(11) NOT NULL, + `ticket_attachment_reply_id` int(11) DEFAULT NULL, + PRIMARY KEY (`ticket_attachment_id`) + )"); + + // Then, update the database to the next sequential version + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '0.5.1'"); + } + + //if (CURRENT_DATABASE_VERSION == '0.5.1') { + // Insert queries here required to update to DB version 0.5.2 // Then, update the database to the next sequential version - // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '0.5.1'"); + // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '0.5.2'"); //} } else { diff --git a/database_version.php b/database_version.php index a464a0e4..2e959d54 100644 --- a/database_version.php +++ b/database_version.php @@ -5,4 +5,4 @@ * It is used in conjunction with database_updates.php */ -DEFINE("LATEST_DATABASE_VERSION", "0.5.0"); +DEFINE("LATEST_DATABASE_VERSION", "0.5.1"); diff --git a/db.sql b/db.sql index 08a37b9d..417ad0f9 100644 --- a/db.sql +++ b/db.sql @@ -1304,6 +1304,20 @@ CREATE TABLE `tickets` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `ticket_attachments` +-- + +CREATE TABLE `ticket_attachments` ( + `ticket_attachment_id` int(11) NOT NULL AUTO_INCREMENT, + `ticket_attachment_name` varchar(255) NOT NULL, + `ticket_attachment_reference_name` varchar(255) NOT NULL, + `ticket_attachment_created_at` datetime NOT NULL DEFAULT current_timestamp(), + `ticket_attachment_ticket_id` int(11) NOT NULL, + `ticket_attachment_reply_id` int(11) DEFAULT NULL, + PRIMARY KEY (`ticket_attachment_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + -- -- Table structure for table `transfers` -- diff --git a/ticket.php b/ticket.php index 8aa1586c..b6c731d1 100644 --- a/ticket.php +++ b/ticket.php @@ -19,7 +19,7 @@ if (isset($_GET['ticket_id'])) { LEFT JOIN locations ON ticket_location_id = location_id LEFT JOIN assets ON ticket_asset_id = asset_id LEFT JOIN vendors ON ticket_vendor_id = vendor_id - WHERE ticket_id = $ticket_id" + WHERE ticket_id = $ticket_id LIMIT 1" ); if (mysqli_num_rows($sql) == 0) { @@ -167,9 +167,9 @@ if (isset($_GET['ticket_id'])) { $client_tags_display = implode(' ', $client_tag_name_display_array); // Get the number of responses - $ticket_responses_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_responses FROM ticket_replies WHERE ticket_reply_ticket_id = $ticket_id"); - $row = mysqli_fetch_array($ticket_responses_sql); - $ticket_responses = intval($row['ticket_responses']); + $ticket_responses_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_responses FROM ticket_replies WHERE ticket_reply_ticket_id = $ticket_id"); + $row = mysqli_fetch_array($ticket_responses_sql); + $ticket_responses = intval($row['ticket_responses']); // Get & format asset warranty expiry $date = date('Y-m-d H:i:s'); @@ -205,6 +205,13 @@ if (isset($_GET['ticket_id'])) { ORDER BY user_name ASC" ); + $sql_ticket_attachments = mysqli_query( + $mysqli, + "SELECT * FROM ticket_attachments + WHERE ticket_attachment_reply_id IS NULL + AND ticket_attachment_ticket_id = $ticket_id" + ); + ?> @@ -241,8 +248,8 @@ if (isset($_GET['ticket_id'])) { - Delete - + Delete + @@ -262,6 +269,14 @@ if (isset($_GET['ticket_id'])) {
+ + $name
"; + } + ?>
@@ -346,6 +361,13 @@ if (isset($_GET['ticket_id'])) { $ticket_reply_time_worked = date_create($row['ticket_reply_time_worked']); } + $sql_ticket_reply_attachments = mysqli_query( + $mysqli, + "SELECT * FROM ticket_attachments + WHERE ticket_attachment_reply_id = $ticket_reply_id + AND ticket_attachment_ticket_id = $ticket_id" + ); + ?>
mb-3"> @@ -398,6 +420,14 @@ if (isset($_GET['ticket_id'])) {
+ + $name
"; + } + ?>