From d0dd43bef9ebbdf8059f9d4b399c4a2d8396fbd1 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 19 Jan 2024 10:31:09 -0500 Subject: [PATCH 01/98] Fixed issue with email failing to send on password updates and email name changes was using the old formatting for the legacy way of sending emails out --- post/profile.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/post/profile.php b/post/profile.php index 34d40abb..90f75f36 100644 --- a/post/profile.php +++ b/post/profile.php @@ -21,7 +21,7 @@ if (isset($_POST['edit_your_user_details'])) { // Email notification when password or email is changed $user_old_email_sql = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT user_email FROM users WHERE user_id = $session_user_id")); - $user_old_email = $user_old_email_sql['user_email']; + $user_old_email = sanitizeInput($user_old_email_sql['user_email']); if (!empty($config_smtp_host) && ($user_old_email !== $email)) { @@ -94,8 +94,8 @@ if (isset($_POST['edit_your_user_password'])) { // Email notification when password or email is changed $user_sql = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT user_name, user_email FROM users WHERE user_id = $session_user_id")); - $name = $user_sql['user_name']; - $user_email = $user_sql['user_email']; + $name = sanitizeInput($user_sql['user_name']); + $user_email = sanitizeInput($user_sql['user_email']); if (!empty($config_smtp_host)){ From 6af48594f62f1e81fb3d3c84f3582e72e383e0c4 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 19 Jan 2024 13:14:57 -0500 Subject: [PATCH 02/98] Added Scheduled Ticket Count --- cron.php | 5 +++++ post/setting.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/cron.php b/cron.php index c0d67664..2a032d66 100644 --- a/cron.php +++ b/cron.php @@ -732,6 +732,10 @@ if ($config_telemetry > 0 OR $config_telemetry = 2) { $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('recurring_id') AS num FROM tickets")); $ticket_count = $row['num']; + // Scheduled Ticket Count + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('scheduled_ticket_id') AS num FROM scheduled_tickets")); + $scheduled_ticket_count = $row['num']; + // Calendar Event Count $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('event_id') AS num FROM events")); $calendar_event_count = $row['num']; @@ -896,6 +900,7 @@ if ($config_telemetry > 0 OR $config_telemetry = 2) { 'currency' => "$company_currency", 'client_count' => $client_count, 'ticket_count' => $ticket_count, + 'scheduled_ticket_count' => $scheduled_ticket_count, 'calendar_event_count' => $calendar_event_count, 'quote_count' => $quote_count, 'invoice_count' => $invoice_count, diff --git a/post/setting.php b/post/setting.php index 750d5414..78a57ee8 100644 --- a/post/setting.php +++ b/post/setting.php @@ -626,6 +626,10 @@ if (isset($_GET['update'])) { $row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('recurring_id') AS num FROM tickets")); $ticket_count = $row['num']; + // Scheduled Ticket Count + $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('scheduled_ticket_id') AS num FROM scheduled_tickets")); + $scheduled_ticket_count = $row['num']; + // Calendar Event Count $row = mysqli_fetch_assoc(mysqli_query($mysqli,"SELECT COUNT('event_id') AS num FROM events")); $calendar_event_count = $row['num']; @@ -791,6 +795,7 @@ if (isset($_GET['update'])) { 'comments' => "$comments", 'client_count' => $client_count, 'ticket_count' => $ticket_count, + 'scheduled_ticket_count' => $scheduled_ticket_count, 'calendar_event_count' => $calendar_event_count, 'quote_count' => $quote_count, 'invoice_count' => $invoice_count, From 9559c11c252532179e7c192ca2c00aecaf594110 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 19 Jan 2024 17:28:17 -0500 Subject: [PATCH 03/98] Cleaned up the initial create ticket email, removed customization for now, added some better comments to cron mailer etc --- cron_mail_queue.php | 17 +++++--- post/ticket.php | 96 ++++++++++++++++++--------------------------- 2 files changed, 49 insertions(+), 64 deletions(-) diff --git a/cron_mail_queue.php b/cron_mail_queue.php index 63497247..cad46435 100644 --- a/cron_mail_queue.php +++ b/cron_mail_queue.php @@ -61,8 +61,14 @@ file_put_contents($lock_file_path, "Locked"); // Process Mail Queue -// Get Mail Queue that hasnt been sent yet -// Email Status: 0 Queued, 1 Sending, 2 Failed, 3 Sent +// Email Status: +// 0 Queued +// 1 Sending +// 2 Failed +// 3 Sent + +// Get Mail Queue that has status of Queued and send it to the function sendSingleEmail() located in functions.php + $sql_queue = mysqli_query($mysqli, "SELECT * FROM email_queue WHERE email_status = 0"); if (mysqli_num_rows($sql_queue) > 0) { @@ -115,10 +121,9 @@ if (mysqli_num_rows($sql_queue) > 0) { } } -// Process Failed Mail up to 4 times every 30 mins +// -// Get Mail Queue that hasnt been sent yet -// Email Status: 0 Queued, 1 Sending, 2 Failed, 3 Sent +// Get Mail that failed to send and attempt to send Failed Mail up to 4 times every 30 mins $sql_failed_queue = mysqli_query($mysqli, "SELECT * FROM email_queue WHERE email_status = 2 AND email_attempts < 4 AND email_failed_at < NOW() + INTERVAL 30 MINUTE"); if (mysqli_num_rows($sql_failed_queue) > 0) { @@ -173,5 +178,5 @@ if (mysqli_num_rows($sql_failed_queue) > 0) { } } -// Remove the lock file +// Remove the lock file once mail has finished processing so it doesnt get overun causing possible duplicates unlink($lock_file_path); diff --git a/post/ticket.php b/post/ticket.php index 9b42986f..012398d1 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -41,6 +41,11 @@ if (isset($_POST['add_ticket'])) { //Get the next Ticket Number and add 1 for the new ticket number $ticket_number = $config_ticket_next_number; $new_config_ticket_next_number = $config_ticket_next_number + 1; + + // Sanitize Config Vars from get_settings.php and Session Vars from check_login.php + $config_ticket_prefix = sanitizeInput($config_ticket_prefix); + $company_name = sanitizeInput($session_company_name); + mysqli_query($mysqli,"UPDATE settings SET config_ticket_next_number = $new_config_ticket_next_number WHERE company_id = 1"); mysqli_query($mysqli,"INSERT INTO tickets SET ticket_prefix = '$config_ticket_prefix', ticket_number = $ticket_number, ticket_subject = '$subject', ticket_details = '$details', ticket_priority = '$priority', ticket_billable = '$billable', ticket_status = '$ticket_status', ticket_vendor_ticket_number = '$vendor_ticket_number', ticket_vendor_id = $vendor_id, ticket_asset_id = $asset_id, ticket_created_by = $session_user_id, ticket_assigned_to = $assigned_to, ticket_contact_id = $contact, ticket_client_id = $client_id, ticket_invoice_id = 0"); @@ -65,86 +70,61 @@ if (isset($_POST['add_ticket'])) { WHERE ticket_id = $ticket_id"); $row = mysqli_fetch_array($sql); - // Unescaped Content used for email body and subject because it will get escaped as a whole - $contact_name = $row['contact_name']; - $ticket_prefix = $row['ticket_prefix']; + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); + $ticket_prefix = sanitizeInput($row['ticket_prefix']); $ticket_number = intval($row['ticket_number']); - $ticket_category = $row['ticket_category']; - $ticket_subject = $row['ticket_subject']; - $ticket_details = $row['ticket_details']; - $ticket_priority = $row['ticket_priority']; - $ticket_status = $row['ticket_status']; + $ticket_category = sanitizeInput($row['ticket_category']); + $ticket_subject = sanitizeInput($row['ticket_subject']); + $ticket_details = mysqli_escape_string($mysqli, $row['ticket_details']); + $ticket_priority = sanitizeInput($row['ticket_priority']); + $ticket_status = sanitizeInput($row['ticket_status']); $client_id = intval($row['ticket_client_id']); $ticket_created_by = intval($row['ticket_created_by']); $ticket_assigned_to = intval($row['ticket_assigned_to']); - // Escaped content used for everything else except email subject and body - $contact_name_escaped = sanitizeInput($row['contact_name']); - $contact_email_escaped = sanitizeInput($row['contact_email']); - $ticket_prefix_escaped = sanitizeInput($row['ticket_prefix']); - $ticket_subject_escaped = sanitizeInput($row['ticket_subject']); - - // Sanitize Config vars from get_settings.php - $config_ticket_from_name_escaped = sanitizeInput($config_ticket_from_name); - $config_ticket_from_email_escaped = sanitizeInput($config_ticket_from_email); + // Get Config ticket from name and from email vars from get_settings.php and sanitize them. + $email_from_name = sanitizeInput($config_ticket_from_name); + $email_from = sanitizeInput($config_ticket_from_email); + // Get Company Phone Number $sql = mysqli_query($mysqli,"SELECT company_phone FROM companies WHERE company_id = 1"); - - $company_phone = formatPhoneNumber($row['company_phone']); // TODO: Check if this even works + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); // Verify contact email is valid - if (filter_var($contact_email_escaped, FILTER_VALIDATE_EMAIL)) { + if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { - $email_custom_vars = array( - "#TICKET_CONTACT_NAME#" => $contact_name, - "#TICKET_PREFIX#" => $ticket_prefix, - "#TICKET_NUMBER#" => $ticket_number, - "#TICKET_URL#" => "https://$config_base_url/portal/ticket.php?id=$ticket_id", - "#TICKET_SUBJECT#" => $ticket_subject, - "#TICKET_PRIORITY#" => $ticket_priority, - "#TICKET_STATUS#" => $ticket_status, - "#TICKET_CATEGORY#" => $ticket_category, - "#TICKET_AGENT#", // todo - "#TICKET_COMPANY_NAME#" => $session_company_name, - "#TICKET_COMPANY_EMAIL" => $config_ticket_from_email, - ); - $ticket_subject_base = "Ticket created - [#TICKET_PREFIX##TICKET_NUMBER#] - #TICKET_SUBJECT#"; // Eventually this will come from the DB instead + $email_subject = "Ticket created [$ticket_prefix$ticket_number] - $ticket_subject"; + $email_body = "##- Please type your reply above this line -##

Hello\, $contact_name

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$session_company_name
Support
$email_from
$company_phone"; - foreach ($email_custom_vars as $key => $item) { - $ticket_subject_base = str_replace($key, $item, $ticket_subject_base); - } - - $subject_escaped = mysqli_escape_string($mysqli, "$ticket_subject_base"); - $body_escaped = mysqli_escape_string($mysqli, "##- Please type your reply above this line -##

Hello, $contact_name

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$session_company_name
Support Department
$config_ticket_from_email
$company_phone"); - - // Email Ticket Contact + // Email Ticket Contact // Queue Mail $data = [ [ - 'from' => $config_ticket_from_email, - 'from_name' => $config_ticket_from_name, - 'recipient' => $contact_email_escaped, - 'recipient_name' => $contact_name_escaped, - 'subject' => $subject_escaped, - 'body' => $body_escaped, + 'from' => $email_from, + 'from_name' => $email_from_name, + 'recipient' => $contact_email, + 'recipient_name' => $contact_name, + 'subject' => $email_subject, + 'body' => $email_body, ] ]; // Also Email all the watchers $sql_watchers = mysqli_query($mysqli, "SELECT watcher_email FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id"); - $body_escaped .= "

----------------------------------------
DO NOT REPLY - YOU ARE RECEIVING THIS EMAIL BECAUSE YOU ARE A WATCHER"; + $email_body .= "

----------------------------------------
DO NOT REPLY - YOU ARE RECEIVING THIS EMAIL BECAUSE YOU ARE A WATCHER"; while ($row = mysqli_fetch_array($sql_watchers)) { - $watcher_email_escaped = sanitizeInput($row['watcher_email']); + $watcher_email = sanitizeInput($row['watcher_email']); // Queue Mail $data = [ [ - 'from' => $config_ticket_from_email, - 'from_name' => $config_ticket_from_name, - 'recipient' => $watcher_email_escaped, - 'recipient_name' => $watcher_email_escaped, - 'subject' => $subject_escaped, - 'body' => $body_escaped, + 'from' => $email_from, + 'from_name' => $email_from_name, + 'recipient' => $watcher_email, + 'recipient_name' => $watcher_email, + 'subject' => $email_subject, + 'body' => $email_body, ] ]; } @@ -153,9 +133,9 @@ if (isset($_POST['add_ticket'])) { } // Logging - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Create', log_description = '$session_name created ticket $config_ticket_prefix_escaped$ticket_number - $ticket_subject_escaped', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Create', log_description = '$session_name created ticket $config_ticket_prefix$ticket_number - $ticket_subject', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); - $_SESSION['alert_message'] = "Ticket $config_ticket_prefix$ticket_number created"; + $_SESSION['alert_message'] = "$session_name created Ticket $ticket_subject for $contact_name - $client_name$config_ticket_prefix$ticket_number created"; header("Location: ticket.php?ticket_id=" . $ticket_id); From 289031b69195fe216a15068ae83b9685d76c50a3 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 19 Jan 2024 17:39:28 -0500 Subject: [PATCH 04/98] Updated Cron Mail Queuer - Removed HTMLPurify and HTML Encoding using HTMLEntities as these are unnessaery and were cuasing extra cpu load and possible data corruption and are passed off to PHPMailer which handles this by default plus recipient email clients should handle XSS as well --- cron_mail_queue.php | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/cron_mail_queue.php b/cron_mail_queue.php index cad46435..5f9933cf 100644 --- a/cron_mail_queue.php +++ b/cron_mail_queue.php @@ -1,16 +1,8 @@ set('URI.AllowedSchemes', ['data' => true, 'src' => true, 'http' => true, 'https' => true]); -$purifier = new HTMLPurifier($purifier_config); - $sql_settings = mysqli_query($mysqli, "SELECT * FROM settings WHERE company_id = 1"); $row = mysqli_fetch_array($sql_settings); @@ -74,14 +66,14 @@ $sql_queue = mysqli_query($mysqli, "SELECT * FROM email_queue WHERE email_status if (mysqli_num_rows($sql_queue) > 0) { while ($row = mysqli_fetch_array($sql_queue)) { $email_id = intval($row['email_id']); - $email_from = nullable_htmlentities($row['email_from']); - $email_from_name = nullable_htmlentities($row['email_from_name']); - $email_recipient = nullable_htmlentities($row['email_recipient']); - $email_recipient_name = nullable_htmlentities($row['email_recipient_name']); - $email_subject = $purifier->purify($row['email_subject']); - $email_content = $purifier->purify($row['email_content']); - $email_queued_at = nullable_htmlentities($row['email_queued_at']); - $email_sent_at = nullable_htmlentities($row['email_sent_at']); + $email_from = $row['email_from']; + $email_from_name = $row['email_from_name']; + $email_recipient = $row['email_recipient']; + $email_recipient_name = $row['email_recipient_name']; + $email_subject = $row['email_subject']; + $email_content = $row['email_content']; + $email_queued_at = $row['email_queued_at']; + $email_sent_at = $row['email_sent_at']; // Sanitized Input $email_recipient_logging = sanitizeInput($row['email_recipient']); @@ -129,14 +121,14 @@ $sql_failed_queue = mysqli_query($mysqli, "SELECT * FROM email_queue WHERE email if (mysqli_num_rows($sql_failed_queue) > 0) { while ($row = mysqli_fetch_array($sql_failed_queue)) { $email_id = intval($row['email_id']); - $email_from = nullable_htmlentities($row['email_from']); - $email_from_name = nullable_htmlentities($row['email_from_name']); - $email_recipient = nullable_htmlentities($row['email_recipient']); - $email_recipient_name = nullable_htmlentities($row['email_recipient_name']); - $email_subject = $purifier->purify($row['email_subject']); - $email_content = $purifier->purify($row['email_content']); - $email_queued_at = nullable_htmlentities($row['email_queued_at']); - $email_sent_at = nullable_htmlentities($row['email_sent_at']); + $email_from = $row['email_from']; + $email_from_name = $row['email_from_name']; + $email_recipient = $row['email_recipient']; + $email_recipient_name = $row['email_recipient_name']; + $email_subject = $row['email_subject']; + $email_content = $row['email_content']; + $email_queued_at = $row['email_queued_at']; + $email_sent_at = $row['email_sent_at']; // Increment the attempts $email_attempts = intval($row['email_attempts']) + 1; From 56d0188ccb5cd68bd99de083e62982d4a2bffd29 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 19 Jan 2024 17:56:04 -0500 Subject: [PATCH 05/98] Fix Oppps --- post/ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/post/ticket.php b/post/ticket.php index 012398d1..17e22912 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -95,7 +95,7 @@ if (isset($_POST['add_ticket'])) { if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { $email_subject = "Ticket created [$ticket_prefix$ticket_number] - $ticket_subject"; - $email_body = "##- Please type your reply above this line -##

Hello\, $contact_name

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$session_company_name
Support
$email_from
$company_phone"; + $email_body = "##- Please type your reply above this line -##

Hello $contact_name\,

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name
Support
$email_from
$company_phone"; // Email Ticket Contact // Queue Mail From ee68bf10b87b53e19f678cdfe178a4a92b5eeb2e Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Fri, 19 Jan 2024 23:39:15 +0000 Subject: [PATCH 06/98] Don't require admin role to edit user profiles (otherwise techs/accountants can't edit their page) --- inc_all_user.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/inc_all_user.php b/inc_all_user.php index 614bfc4d..5ecd87d2 100644 --- a/inc_all_user.php +++ b/inc_all_user.php @@ -6,8 +6,6 @@ require_once "functions.php"; require_once "check_login.php"; -validateAdminRole(); - require_once "header.php"; require_once "top_nav.php"; From 1fcf559e13556a6ba847f4f76edbbd5d5788142a Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Fri, 19 Jan 2024 23:45:02 +0000 Subject: [PATCH 07/98] Prevent users setting/hashing an empty password --- post/profile.php | 5 +++++ user_security.php | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/post/profile.php b/post/profile.php index 90f75f36..38410fbf 100644 --- a/post/profile.php +++ b/post/profile.php @@ -92,6 +92,11 @@ if (isset($_POST['edit_your_user_password'])) { $new_password = trim($_POST['new_password']); + if (empty($new_password)) { + header('Location: user_security.php'); + exit; + } + // Email notification when password or email is changed $user_sql = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT user_name, user_email FROM users WHERE user_id = $session_user_id")); $name = sanitizeInput($user_sql['user_name']); diff --git a/user_security.php b/user_security.php index d0076403..542603ad 100644 --- a/user_security.php +++ b/user_security.php @@ -12,12 +12,12 @@ require_once "inc_all_user.php";
- +
- +
From 2f3e26b285b836ebf264928ca89723d4f1aafd93 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 19 Jan 2024 19:01:26 -0500 Subject: [PATCH 08/98] Fix Ticket Settings --- post/setting.php | 2 +- post/ticket.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/post/setting.php b/post/setting.php index 78a57ee8..ab1070bf 100644 --- a/post/setting.php +++ b/post/setting.php @@ -271,7 +271,7 @@ if (isset($_POST['edit_ticket_settings'])) { $config_ticket_autoclose_hours = intval($_POST['config_ticket_autoclose_hours']); $config_ticket_new_ticket_notification_email = sanitizeInput($_POST['config_ticket_new_ticket_notification_email']); - mysqli_query($mysqli,"UPDATE settings SET config_ticket_prefix = '$config_ticket_prefix', config_ticket_next_number = $config_ticket_next_number, config_ticket_from_email = '$config_ticket_from_email', config_ticket_from_name = '$config_ticket_from_name', config_ticket_email_parse = '$config_ticket_email_parse', config_ticket_autoclose = $config_ticket_autoclose, config_ticket_autoclose_hours = $config_ticket_autoclose_hours, config_ticket_new_ticket_notification_email = '$config_ticket_new_ticket_notification_email' WHERE company_id = 1"); + mysqli_query($mysqli,"UPDATE settings SET config_ticket_prefix = '$config_ticket_prefix', config_ticket_next_number = $config_ticket_next_number, config_ticket_email_parse = $config_ticket_email_parse, config_ticket_autoclose = $config_ticket_autoclose, config_ticket_autoclose_hours = $config_ticket_autoclose_hours, config_ticket_new_ticket_notification_email = '$config_ticket_new_ticket_notification_email' WHERE company_id = 1"); //Logging mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Settings', log_action = 'Modify', log_description = '$session_name modified ticket settings', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); diff --git a/post/ticket.php b/post/ticket.php index 17e22912..183c0543 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -135,7 +135,7 @@ if (isset($_POST['add_ticket'])) { // Logging mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Create', log_description = '$session_name created ticket $config_ticket_prefix$ticket_number - $ticket_subject', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); - $_SESSION['alert_message'] = "$session_name created Ticket $ticket_subject for $contact_name - $client_name$config_ticket_prefix$ticket_number created"; + $_SESSION['alert_message'] = "You created Ticket $ticket_subject $config_ticket_prefix$ticket_number"; header("Location: ticket.php?ticket_id=" . $ticket_id); From 79175b9e70130f206bb9ddda630ae74317f47299 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 19 Jan 2024 19:18:26 -0500 Subject: [PATCH 09/98] Sanitize Ticket Prefix and From Name in Cron Ticket Email Parser --- cron_ticket_email_parser.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cron_ticket_email_parser.php b/cron_ticket_email_parser.php index 2bfceb8c..18d2a255 100644 --- a/cron_ticket_email_parser.php +++ b/cron_ticket_email_parser.php @@ -23,6 +23,8 @@ require_once "functions.php"; // Get settings for the "default" company require_once "get_settings.php"; +$config_ticket_prefix = sanitizeInput($config_ticket_prefix); +$config_ticket_from_name = sanitizeInput($config_ticket_from_name); // Get company name & phone $sql = mysqli_query($mysqli, "SELECT company_name, company_phone FROM companies WHERE company_id = 1"); From a656340c8bf858069e0fd99fda370cf18bd69b4c Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 19 Jan 2024 19:37:34 -0500 Subject: [PATCH 10/98] Fix mis-spelling sanitize not santize --- cron_ticket_email_parser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cron_ticket_email_parser.php b/cron_ticket_email_parser.php index 18d2a255..336ef697 100644 --- a/cron_ticket_email_parser.php +++ b/cron_ticket_email_parser.php @@ -329,7 +329,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac // Get tech details $tech_sql = mysqli_query($mysqli, "SELECT user_email, user_name FROM users WHERE user_id = $ticket_assigned_to LIMIT 1"); $tech_row = mysqli_fetch_array($tech_sql); - $tech_email = santizeInput($tech_row['user_email']); + $tech_email = sanitizeInput($tech_row['user_email']); $tech_name = sanitizeInput($tech_row['user_name']); $subject = mysqli_escape_string($mysqli, "Ticket updated - [$config_ticket_prefix$ticket_number] - $subject"); From b942bf0e18361ac979349d3c95352fffb1e953fd Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 13:18:17 -0500 Subject: [PATCH 11/98] Update/Fix Mail Functions in POST/ticket.php - sanitize POST vars instead the whole mail subject and body which prevents having a mixed of confusing redundant escaped and unescaped vars, also fixed watchers where if a watcher was added it would just emai the last watcher selected and skip the main contact and any other watchers selected --- post/ticket.php | 228 ++++++++++++++++++++++-------------------------- 1 file changed, 105 insertions(+), 123 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index 183c0543..c0a62621 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -44,7 +44,9 @@ if (isset($_POST['add_ticket'])) { // Sanitize Config Vars from get_settings.php and Session Vars from check_login.php $config_ticket_prefix = sanitizeInput($config_ticket_prefix); - $company_name = sanitizeInput($session_company_name); + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $config_base_url = sanitizeInput($config_base_url); mysqli_query($mysqli,"UPDATE settings SET config_ticket_next_number = $new_config_ticket_next_number WHERE company_id = 1"); @@ -83,52 +85,51 @@ if (isset($_POST['add_ticket'])) { $ticket_created_by = intval($row['ticket_created_by']); $ticket_assigned_to = intval($row['ticket_assigned_to']); - // Get Config ticket from name and from email vars from get_settings.php and sanitize them. - $email_from_name = sanitizeInput($config_ticket_from_name); - $email_from = sanitizeInput($config_ticket_from_email); - // Get Company Phone Number - $sql = mysqli_query($mysqli,"SELECT company_phone FROM companies WHERE company_id = 1"); + $sql = mysqli_query($mysqli,"SELECT company_name, company_phone FROM companies WHERE company_id = 1"); + $row = mysqli_fetch_array($sql); + $company_name = sanitizeInput($row['company_name']); $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); // Verify contact email is valid if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { - $email_subject = "Ticket created [$ticket_prefix$ticket_number] - $ticket_subject"; - $email_body = "##- Please type your reply above this line -##

Hello $contact_name\,

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name
Support
$email_from
$company_phone"; + $subject = "Ticket created [$ticket_prefix$ticket_number] - $ticket_subject"; + $body = "##- Please type your reply above this line -##

Hello $contact_name\,

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; // Email Ticket Contact // Queue Mail $data = [ [ - 'from' => $email_from, - 'from_name' => $email_from_name, + 'from' => $config_ticket_from_email, + 'from_name' => $config_ticket_from_name, 'recipient' => $contact_email, 'recipient_name' => $contact_name, - 'subject' => $email_subject, - 'body' => $email_body, + 'subject' => $subject, + 'body' => $body ] ]; + addToMailQueue($mysqli, $data); // Also Email all the watchers $sql_watchers = mysqli_query($mysqli, "SELECT watcher_email FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id"); - $email_body .= "

----------------------------------------
DO NOT REPLY - YOU ARE RECEIVING THIS EMAIL BECAUSE YOU ARE A WATCHER"; + $body .= "

----------------------------------------
DO NOT REPLY - YOU ARE RECEIVING THIS EMAIL BECAUSE YOU ARE A WATCHER"; while ($row = mysqli_fetch_array($sql_watchers)) { $watcher_email = sanitizeInput($row['watcher_email']); // Queue Mail $data = [ [ - 'from' => $email_from, - 'from_name' => $email_from_name, + 'from' => $config_ticket_from_email, + 'from_name' => $config_ticket_from_name, 'recipient' => $watcher_email, 'recipient_name' => $watcher_email, - 'subject' => $email_subject, - 'body' => $email_body, + 'subject' => $subject, + 'body' => $body ] ]; + addToMailQueue($mysqli, $data); } - addToMailQueue($mysqli, $data); } } @@ -347,7 +348,7 @@ if (isset($_POST['assign_ticket'])) { // Allow for un-assigning tickets if ($assigned_to == 0) { - $ticket_reply = "Ticket unassigned, pending re-assignment."; + $ticket_reply = "Ticket unassigned\, pending re-assignment."; $agent_name = "No One"; $ticket_status = "Pending-Assignment"; } else { @@ -355,17 +356,11 @@ if (isset($_POST['assign_ticket'])) { $agent_details_sql = mysqli_query($mysqli, "SELECT user_name, user_email FROM users LEFT JOIN user_settings ON users.user_id = user_settings.user_id WHERE users.user_id = $assigned_to AND user_settings.user_role > 1"); $agent_details = mysqli_fetch_array($agent_details_sql); - //Unescaped - $agent_name = $agent_details['user_name']; - $agent_email = $agent_details['user_email']; + $agent_name = sanitizeInput($agent_details['user_name']); + $agent_email = sanitizeInput($agent_details['user_email']); $ticket_reply = "Ticket re-assigned to $agent_name."; - // Escaped - $agent_name_escaped = sanitizeInput($agent_details['user_name']); - $agent_email_escaped = sanitizeInput($agent_details['user_email']); - $ticket_reply_escaped = mysqli_real_escape_string($mysqli, "Ticket re-assigned to $agent_name."); - - if (!$agent_name_escaped) { + if (!$agent_name) { $_SESSION['alert_type'] = "error"; $_SESSION['alert_message'] = "Invalid agent!"; header("Location: " . $_SERVER["HTTP_REFERER"]); @@ -377,17 +372,12 @@ if (isset($_POST['assign_ticket'])) { $ticket_details_sql = mysqli_query($mysqli, "SELECT ticket_prefix, ticket_number, ticket_subject, ticket_client_id FROM tickets WHERE ticket_id = '$ticket_id' AND ticket_status != 'Closed'"); $ticket_details = mysqli_fetch_array($ticket_details_sql); - //Unescaped - $ticket_prefix = $ticket_details['ticket_prefix']; - $ticket_subject = $ticket_details['ticket_subject']; - - //Escaped - $ticket_prefix_escaped = sanitizeInput($ticket_details['ticket_prefix']); + $ticket_prefix = sanitizeInput($ticket_details['ticket_prefix']); $ticket_number = intval($ticket_details['ticket_number']); - $ticket_subject_escaped = sanitizeInput($ticket_details['ticket_subject']); + $ticket_subject = sanitizeInput($ticket_details['ticket_subject']); $client_id = intval($ticket_details['ticket_client_id']); - if (!$ticket_subject_escaped) { + if (!$ticket_subject) { $_SESSION['alert_type'] = "error"; $_SESSION['alert_message'] = "Invalid ticket!"; header("Location: " . $_SERVER["HTTP_REFERER"]); @@ -397,27 +387,28 @@ if (isset($_POST['assign_ticket'])) { // Update ticket & insert reply mysqli_query($mysqli,"UPDATE tickets SET ticket_assigned_to = $assigned_to, ticket_status = '$ticket_status' WHERE ticket_id = $ticket_id"); - mysqli_query($mysqli,"INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply_escaped', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli,"INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); // Logging - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Edit', log_description = '$session_name reassigned ticket $ticket_prefix_escaped$ticket_number - $ticket_subject_escaped to $agent_name_escaped', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Edit', log_description = '$session_name reassigned ticket $ticket_prefix$ticket_number - $ticket_subject to $agent_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); // Notification if ($session_user_id != $assigned_to && $assigned_to != 0) { // App Notification - mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Ticket', notification = 'Ticket $ticket_prefix_escaped$ticket_number - Subject: $ticket_subject_escaped has been assigned to you by $session_name', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id, notification_user_id = $assigned_to"); + mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Ticket', notification = 'Ticket $ticket_prefix$ticket_number - Subject: $ticket_subject has been assigned to you by $session_name', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id, notification_user_id = $assigned_to"); // Email Notification if (!empty($config_smtp_host)) { // Sanitize Config vars from get_settings.php - $config_ticket_from_name_escaped = sanitizeInput($config_ticket_from_name); - $config_ticket_from_email_escaped = sanitizeInput($config_ticket_from_email); + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $company_name = sanitizeInput($session_company_name); - $subject_escaped = mysqli_escape_string($mysqli, "$config_app_name ticket $ticket_prefix$ticket_number assigned to you"); - $body_escaped = mysqli_escape_string($mysqli, "Hi $agent_name,

A ticket has been assigned to you!

Ticket Number: $ticket_prefix$ticket_number
Subject: $ticket_subject

Thanks,
$session_name
$session_company_name"); + $subject = "$config_app_name ticket $ticket_prefix$ticket_number assigned to you"; + $body = "Hi $agent_name\,

A ticket has been assigned to you!

Ticket Number: $ticket_prefix$ticket_number
Subject: $ticket_subject

Thanks\,
$session_name
$company_name"; // Email Ticket Agent // Queue Mail @@ -425,10 +416,10 @@ if (isset($_POST['assign_ticket'])) { [ 'from' => $config_ticket_from_email, 'from_name' => $config_ticket_from_name, - 'recipient' => $agent_email_escaped, - 'recipient_name' => $agent_name_escaped, - 'subject' => $subject_escaped, - 'body' => $body_escaped, + 'recipient' => $agent_email, + 'recipient_name' => $agent_name, + 'subject' => $subject, + 'body' => $body, ] ]; addToMailQueue($mysqli, $data); @@ -482,10 +473,8 @@ if (isset($_POST['add_ticket_reply'])) { validateTechRole(); $ticket_id = intval($_POST['ticket_id']); - $ticket_reply_escaped = mysqli_real_escape_string($mysqli,$_POST['ticket_reply']); - $ticket_reply = $_POST['ticket_reply']; - $ticket_status_escaped = sanitizeInput($_POST['status']); - $ticket_status = $_POST['status']; + $ticket_reply = mysqli_real_escape_string($mysqli,$_POST['ticket_reply']); + $ticket_status = sanitizeInput($_POST['status']); // Handle the time inputs for hours, minutes, and seconds $hours = intval($_POST['hours']); $minutes = intval($_POST['minutes']); @@ -495,8 +484,7 @@ if (isset($_POST['add_ticket_reply'])) { //exit; // Combine into a single time string - $ticket_reply_time_worked = sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds); - $ticket_reply_time_worked_escaped = sanitizeInput($ticket_reply_time_worked); + $ticket_reply_time_worked = sanitizeInput(sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds)); $client_id = intval($_POST['client_id']); @@ -507,12 +495,12 @@ if (isset($_POST['add_ticket_reply'])) { } // Add reply - mysqli_query($mysqli,"INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply_escaped', ticket_reply_time_worked = '$ticket_reply_time_worked_escaped', ticket_reply_type = '$ticket_reply_type', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id") or die(mysqli_error($mysqli)); + mysqli_query($mysqli,"INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply', ticket_reply_time_worked = '$ticket_reply_time_worked', ticket_reply_type = '$ticket_reply_type', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); $ticket_reply_id = mysqli_insert_id($mysqli); // Update Ticket Last Response Field - mysqli_query($mysqli,"UPDATE tickets SET ticket_status = '$ticket_status_escaped' WHERE ticket_id = $ticket_id") or die(mysqli_error($mysqli)); + mysqli_query($mysqli,"UPDATE tickets SET ticket_status = '$ticket_status' WHERE ticket_id = $ticket_id"); if ($ticket_status == 'Closed') { mysqli_query($mysqli,"UPDATE tickets SET ticket_closed_at = NOW() WHERE ticket_id = $ticket_id"); @@ -528,47 +516,43 @@ if (isset($_POST['add_ticket_reply'])) { $row = mysqli_fetch_array($ticket_sql); - // Unescaped Content used for email body and subject because it will get escaped as a whole - $contact_name = $row['contact_name']; - $ticket_prefix = $row['ticket_prefix']; + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); + $ticket_prefix = sanitizeInput($row['ticket_prefix']); $ticket_number = intval($row['ticket_number']); - $ticket_subject = $row['ticket_subject']; + $ticket_subject = sanitizeInput($row['ticket_subject']); $client_id = intval($row['ticket_client_id']); $ticket_created_by = intval($row['ticket_created_by']); $ticket_assigned_to = intval($row['ticket_assigned_to']); - // Escaped content used for everything else except email subject and body - $contact_name_escaped = sanitizeInput($row['contact_name']); - $contact_email_escaped = sanitizeInput($row['contact_email']); - $ticket_prefix_escaped = sanitizeInput($row['ticket_prefix']); - $ticket_subject_escaped = sanitizeInput($row['ticket_subject']); - // Sanitize Config vars from get_settings.php - $config_ticket_from_name_escaped = sanitizeInput($config_ticket_from_name); - $config_ticket_from_email_escaped = sanitizeInput($config_ticket_from_email); + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $config_base_url = sanitizeInput($config_base_url); - $sql = mysqli_query($mysqli,"SELECT company_phone FROM companies WHERE company_id = 1"); - - $company_phone = formatPhoneNumber($row['company_phone']); + $sql = mysqli_query($mysqli,"SELECT company_name, company_phone FROM companies WHERE company_id = 1"); + $row = mysqli_fetch_array($sql); + $company_name = sanitizeInput($row['company_name']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); // Send e-mail to client if public update & email is set up if ($ticket_reply_type == 'Public' && !empty($config_smtp_host)) { - if (filter_var($contact_email_escaped, FILTER_VALIDATE_EMAIL)) { + if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { // Slightly different email subject/text depending on if this update closed the ticket or not if ($ticket_status == 'Closed') { - $subject_escaped = mysqli_escape_string($mysqli, "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"); - $body_escaped = mysqli_escape_string($mysqli, "Hello, $contact_name

Your ticket regarding $ticket_subject has been closed.

--------------------------------
$ticket_reply
--------------------------------

We hope the issue was resolved to your satisfaction. If you need further assistance, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$session_company_name
Support Department
$config_ticket_from_email
$company_phone"); + $subject = "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"; + $body = "Hello $contact_name\,

Your ticket regarding $ticket_subject has been closed.

--------------------------------
$ticket_reply
--------------------------------

We hope the issue was resolved to your satisfaction. If you need further assistance\, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; } elseif ($ticket_status == 'Auto Close') { - $subject_escaped = mysqli_escape_string($mysqli, "Ticket update - [$ticket_prefix$ticket_number] - $ticket_subject | (pending closure)"); - $body_escaped = mysqli_escape_string($mysqli, "##- Please type your reply above this line -##

Hello, $contact_name

Your ticket regarding $ticket_subject has been updated and is pending closure.

--------------------------------
$ticket_reply
--------------------------------

If your issue is resolved, you can ignore this email. If you need further assistance, please respond!

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$session_company_name
Support Department
$config_ticket_from_email
$company_phone"); + $subject = "Ticket update - [$ticket_prefix$ticket_number] - $ticket_subject | (pending closure)"; + $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Your ticket regarding $ticket_subject has been updated and is pending closure.

--------------------------------
$ticket_reply
--------------------------------

If your issue is resolved\, you can ignore this email. If you need further assistance\, please respond!

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; } else { - $subject_escaped = mysqli_escape_string($mysqli, "Ticket update - [$ticket_prefix$ticket_number] - $ticket_subject"); - $body_escaped = mysqli_escape_string($mysqli, "##- Please type your reply above this line -##

Hello, $contact_name

Your ticket regarding $ticket_subject has been updated.

--------------------------------
$ticket_reply
--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$session_company_name
Support Department
$config_ticket_from_email
$company_phone"); + $subject = "Ticket update - [$ticket_prefix$ticket_number] - $ticket_subject"; + $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Your ticket regarding $ticket_subject has been updated.

--------------------------------
$ticket_reply
--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; } @@ -579,29 +563,30 @@ if (isset($_POST['add_ticket_reply'])) { $data[] = [ 'from' => $config_ticket_from_email, 'from_name' => $config_ticket_from_name, - 'recipient' => $contact_email_escaped, - 'recipient_name' => $contact_name_escaped, - 'subject' => $subject_escaped, - 'body' => $body_escaped, + 'recipient' => $contact_email, + 'recipient_name' => $contact_name, + 'subject' => $subject, + 'body' => $body ]; + addToMailQueue($mysqli, $data); // Also Email all the watchers $sql_watchers = mysqli_query($mysqli, "SELECT watcher_email FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id"); - $body_escaped .= "

----------------------------------------
DO NOT REPLY - YOU ARE RECEIVING THIS EMAIL BECAUSE YOU ARE A WATCHER"; + $body .= "

----------------------------------------
DO NOT REPLY - YOU ARE RECEIVING THIS EMAIL BECAUSE YOU ARE A WATCHER"; while ($row = mysqli_fetch_array($sql_watchers)) { - $watcher_email_escaped = sanitizeInput($row['watcher_email']); + $watcher_email = sanitizeInput($row['watcher_email']); // Queue Mail $data[] = [ 'from' => $config_ticket_from_email, 'from_name' => $config_ticket_from_name, - 'recipient' => $watcher_email_escaped, - 'recipient_name' => $watcher_email_escaped, - 'subject' => $subject_escaped, - 'body' => $body_escaped, + 'recipient' => $watcher_email, + 'recipient_name' => $watcher_email, + 'subject' => $subject, + 'body' => $body ]; - } - addToMailQueue($mysqli, $data); + addToMailQueue($mysqli, $data); + } } } //End Mail IF @@ -609,17 +594,17 @@ if (isset($_POST['add_ticket_reply'])) { // Notification for assigned ticket user if ($session_user_id != $ticket_assigned_to && $ticket_assigned_to != 0) { - mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Ticket', notification = '$session_name updated Ticket $ticket_prefix_escaped$ticket_number - Subject: $ticket_subject_escaped that is assigned to you', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id, notification_user_id = $ticket_assigned_to"); + mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Ticket', notification = '$session_name updated Ticket $ticket_prefix$ticket_number - Subject: $ticket_subject that is assigned to you', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id, notification_user_id = $ticket_assigned_to"); } // Notification for user that opened the ticket if ($session_user_id != $ticket_created_by && $ticket_created_by != 0) { - mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Ticket', notification = '$session_name updated Ticket $ticket_prefix_escaped$ticket_number - Subject: $ticket_subject_escaped that you opened', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id, notification_user_id = $ticket_created_by"); + mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Ticket', notification = '$session_name updated Ticket $ticket_prefix$ticket_number - Subject: $ticket_subject that you opened', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id, notification_user_id = $ticket_created_by"); } // Logging - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket Reply', log_action = 'Create', log_description = '$session_name replied to ticket $ticket_prefix_escaped$ticket_number - $ticket_subject_escaped and was a $ticket_reply_type reply', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_reply_id"); + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket Reply', log_action = 'Create', log_description = '$session_name replied to ticket $ticket_prefix$ticket_number - $ticket_subject and was a $ticket_reply_type reply', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_reply_id"); $_SESSION['alert_message'] = "Ticket $ticket_prefix$ticket_number has been updated with your reply and was $ticket_reply_type"; @@ -767,37 +752,34 @@ if (isset($_GET['close_ticket'])) { "); $row = mysqli_fetch_array($ticket_sql); - // Unescaped Content used for email body and subject because it will get escaped as a whole - $contact_name = $row['contact_name']; - $ticket_prefix = $row['ticket_prefix']; + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); + $ticket_prefix = sanitizeInput($row['ticket_prefix']); $ticket_number = intval($row['ticket_number']); - $ticket_subject = $row['ticket_subject']; - $ticket_details = $row['ticket_details']; + $ticket_subject = sanitizeInput($row['ticket_subject']); + $ticket_details = sanitizeInput($row['ticket_details']); $client_id = intval($row['ticket_client_id']); $ticket_created_by = intval($row['ticket_created_by']); $ticket_assigned_to = intval($row['ticket_assigned_to']); - // Escaped content used for everything else except email subject and body - $contact_name_escaped = sanitizeInput($row['contact_name']); - $contact_email_escaped = sanitizeInput($row['contact_email']); - $ticket_prefix_escaped = sanitizeInput($row['ticket_prefix']); - $ticket_subject_escaped = sanitizeInput($row['ticket_subject']); - // Sanitize Config vars from get_settings.php - $config_ticket_from_name_escaped = sanitizeInput($config_ticket_from_name); - $config_ticket_from_email_escaped = sanitizeInput($config_ticket_from_email); + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $config_base_url = sanitizeInput($config_base_url); - $sql = mysqli_query($mysqli,"SELECT company_phone FROM companies WHERE company_id = 1"); - - $company_phone = formatPhoneNumber($row['company_phone']); + // Get Company Info + $sql = mysqli_query($mysqli,"SELECT company_name, company_phone FROM companies WHERE company_id = 1"); + $row = mysqli_fetch_array($sql); + $company_name = sanitizeInput($row['company_name']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); // Check email valid - if (filter_var($contact_email_escaped, FILTER_VALIDATE_EMAIL)) { + if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { $data = []; - $subject_escaped = mysqli_escape_string($mysqli, "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"); - $body_escaped = mysqli_escape_string($mysqli, "Hello, $contact_name

Your ticket regarding \"$ticket_subject\" has been closed.

We hope the issue was resolved to your satisfaction. If you need further assistance, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$session_company_name
Support Department
$config_ticket_from_email
$company_phone"); + $subject = "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"; + $body = "Hello $contact_name\,

Your ticket regarding \"$ticket_subject\" has been closed.

We hope the issue was resolved to your satisfaction. If you need further assistance\, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; // Email Ticket Contact // Queue Mail @@ -805,31 +787,31 @@ if (isset($_GET['close_ticket'])) { $data[] = [ 'from' => $config_ticket_from_email, 'from_name' => $config_ticket_from_name, - 'recipient' => $contact_email_escaped, - 'recipient_name' => $contact_name_escaped, - 'subject' => $subject_escaped, - 'body' => $body_escaped, + 'recipient' => $contact_email, + 'recipient_name' => $contact_name, + 'subject' => $subject, + 'body' => $body ]; + addToMailQueue($mysqli, $data); // Also Email all the watchers $sql_watchers = mysqli_query($mysqli, "SELECT watcher_email FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id"); - $body_escaped .= "

----------------------------------------
DO NOT REPLY - YOU ARE RECEIVING THIS EMAIL BECAUSE YOU ARE A WATCHER"; + $body .= "

----------------------------------------
DO NOT REPLY - YOU ARE RECEIVING THIS EMAIL BECAUSE YOU ARE A WATCHER"; while ($row = mysqli_fetch_array($sql_watchers)) { - $watcher_email_escaped = sanitizeInput($row['watcher_email']); + $watcher_email = sanitizeInput($row['watcher_email']); // Queue Mail $data[] = [ 'from' => $config_ticket_from_email, 'from_name' => $config_ticket_from_name, - 'recipient' => $watcher_email_escaped, - 'recipient_name' => $watcher_email_escaped, - 'subject' => $subject_escaped, - 'body' => $body_escaped, + 'recipient' => $watcher_email, + 'recipient_name' => $watcher_email, + 'subject' => $subject, + 'body' => $body ]; + addToMailQueue($mysqli, $data); } - addToMailQueue($mysqli, $data); - } } From 5f3b08a5438a7ed468933277b65a35654a5fe441 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 13:33:54 -0500 Subject: [PATCH 12/98] Fix Mail Array causing duplicate sending --- post/ticket.php | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index c0a62621..81075871 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -99,17 +99,16 @@ if (isset($_POST['add_ticket'])) { // Email Ticket Contact // Queue Mail - $data = [ - [ - 'from' => $config_ticket_from_email, - 'from_name' => $config_ticket_from_name, - 'recipient' => $contact_email, - 'recipient_name' => $contact_name, - 'subject' => $subject, - 'body' => $body - ] + $data = []; + + $data[] = [ + 'from' => $config_ticket_from_email, + 'from_name' => $config_ticket_from_name, + 'recipient' => $contact_email, + 'recipient_name' => $contact_name, + 'subject' => $subject, + 'body' => $body ]; - addToMailQueue($mysqli, $data); // Also Email all the watchers $sql_watchers = mysqli_query($mysqli, "SELECT watcher_email FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id"); @@ -118,18 +117,17 @@ if (isset($_POST['add_ticket'])) { $watcher_email = sanitizeInput($row['watcher_email']); // Queue Mail - $data = [ - [ - 'from' => $config_ticket_from_email, - 'from_name' => $config_ticket_from_name, - 'recipient' => $watcher_email, - 'recipient_name' => $watcher_email, - 'subject' => $subject, - 'body' => $body - ] + $data[] = [ + 'from' => $config_ticket_from_email, + 'from_name' => $config_ticket_from_name, + 'recipient' => $watcher_email, + 'recipient_name' => $watcher_email, + 'subject' => $subject, + 'body' => $body ]; - addToMailQueue($mysqli, $data); + } + addToMailQueue($mysqli, $data); } } @@ -568,7 +566,6 @@ if (isset($_POST['add_ticket_reply'])) { 'subject' => $subject, 'body' => $body ]; - addToMailQueue($mysqli, $data); // Also Email all the watchers $sql_watchers = mysqli_query($mysqli, "SELECT watcher_email FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id"); @@ -585,8 +582,9 @@ if (isset($_POST['add_ticket_reply'])) { 'subject' => $subject, 'body' => $body ]; - addToMailQueue($mysqli, $data); - } + + } + addToMailQueue($mysqli, $data); } } //End Mail IF @@ -792,7 +790,6 @@ if (isset($_GET['close_ticket'])) { 'subject' => $subject, 'body' => $body ]; - addToMailQueue($mysqli, $data); // Also Email all the watchers $sql_watchers = mysqli_query($mysqli, "SELECT watcher_email FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id"); @@ -809,9 +806,8 @@ if (isset($_GET['close_ticket'])) { 'subject' => $subject, 'body' => $body ]; - addToMailQueue($mysqli, $data); } - + addToMailQueue($mysqli, $data); } } From 669d2f74edc6ea44b81c3ab66213da5ebe2930ba Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 13:49:27 -0500 Subject: [PATCH 13/98] Update Ticket POST Email body to Use -- instead of ~ for closing signature --- post/ticket.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index 81075871..e7f0b059 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -95,7 +95,7 @@ if (isset($_POST['add_ticket'])) { if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { $subject = "Ticket created [$ticket_prefix$ticket_number] - $ticket_subject"; - $body = "##- Please type your reply above this line -##

Hello $contact_name\,

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "##- Please type your reply above this line -##

Hello $contact_name\,

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; // Email Ticket Contact // Queue Mail @@ -542,15 +542,15 @@ if (isset($_POST['add_ticket_reply'])) { if ($ticket_status == 'Closed') { $subject = "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"; - $body = "Hello $contact_name\,

Your ticket regarding $ticket_subject has been closed.

--------------------------------
$ticket_reply
--------------------------------

We hope the issue was resolved to your satisfaction. If you need further assistance\, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "Hello $contact_name\,

Your ticket regarding $ticket_subject has been closed.

--------------------------------
$ticket_reply
--------------------------------

We hope the issue was resolved to your satisfaction. If you need further assistance\, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; } elseif ($ticket_status == 'Auto Close') { $subject = "Ticket update - [$ticket_prefix$ticket_number] - $ticket_subject | (pending closure)"; - $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Your ticket regarding $ticket_subject has been updated and is pending closure.

--------------------------------
$ticket_reply
--------------------------------

If your issue is resolved\, you can ignore this email. If you need further assistance\, please respond!

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Your ticket regarding $ticket_subject has been updated and is pending closure.

--------------------------------
$ticket_reply
--------------------------------

If your issue is resolved\, you can ignore this email. If you need further assistance\, please respond!

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; } else { $subject = "Ticket update - [$ticket_prefix$ticket_number] - $ticket_subject"; - $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Your ticket regarding $ticket_subject has been updated.

--------------------------------
$ticket_reply
--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Your ticket regarding $ticket_subject has been updated.

--------------------------------
$ticket_reply
--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; } @@ -777,7 +777,7 @@ if (isset($_GET['close_ticket'])) { $data = []; $subject = "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"; - $body = "Hello $contact_name\,

Your ticket regarding \"$ticket_subject\" has been closed.

We hope the issue was resolved to your satisfaction. If you need further assistance\, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "Hello $contact_name\,

Your ticket regarding \"$ticket_subject\" has been closed.

We hope the issue was resolved to your satisfaction. If you need further assistance\, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; // Email Ticket Contact // Queue Mail From 0a32415b38b325079ed0cfcbd33ab8c6c74865ba Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 15:11:07 -0500 Subject: [PATCH 14/98] Updated ticket mail parser to not escape the entire subject and body of sending emails as this is all done by vars instead --- cron_ticket_email_parser.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cron_ticket_email_parser.php b/cron_ticket_email_parser.php index 336ef697..29b2a0a5 100644 --- a/cron_ticket_email_parser.php +++ b/cron_ticket_email_parser.php @@ -30,7 +30,7 @@ $config_ticket_from_name = sanitizeInput($config_ticket_from_name); $sql = mysqli_query($mysqli, "SELECT company_name, company_phone FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql); $company_name = sanitizeInput($row['company_name']); -$company_phone = formatPhoneNumber($row['company_phone']); +$company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); // Check setting enabled if ($config_ticket_email_parse == 0) { @@ -163,8 +163,8 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date // E-mail client notification that ticket has been created if ($config_ticket_client_general_notifications == 1) { - $subject_email = mysqli_escape_string($mysqli, "Ticket created - [$config_ticket_prefix$ticket_number] - $subject"); - $body = mysqli_escape_string($mysqli, "##- Please type your reply above this line -##

Hello, $contact_name

Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$id

~
$company_name
Support Department
$config_ticket_from_email
$company_phone"); + $subject_email = "Ticket created - [$config_ticket_prefix$ticket_number] - $subject"; + $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $data[] = [ 'from' => $config_ticket_from_email, @@ -184,8 +184,8 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date $client_row = mysqli_fetch_array($client_sql); $client_name = sanitizeInput($client_row['client_name']); - $email_subject = mysqli_escape_string($mysqli, "ITFlow - New Ticket - $client_name: $subject"); - $email_body = "Hello,

This is a notification that a new ticket has been raised in ITFlow.
Client: $client_name
Priority: Low (email parsed)
Link: https://$config_base_url/ticket.php?ticket_id=$id

--------------------------------

$subject
$details"; + $email_subject = "ITFlow - New Ticket - $client_name: $subject"; + $email_body = "Hello\,

This is a notification that a new ticket has been raised in ITFlow.
Client: $client_name
Priority: Low (email parsed)
Link: https://$config_base_url/ticket.php?ticket_id=$id

--------------------------------

$subject
$details"; $data[] = [ 'from' => $config_ticket_from_email, @@ -240,7 +240,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Ticket', notification = 'Email parser: $from_email attempted to re-open ticket $config_ticket_prefix$ticket_number (ID $ticket_id) - check inbox manually to see email', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id"); $email_subject = "Action required: This ticket is already closed"; - $email_body = "Hi there,

You've tried to reply to a ticket that is closed - we won't see your response.

Please raise a new ticket by sending a fresh e-mail to our support address.

~
$company_name
Support Department
$config_ticket_from_email
$company_phone"; + $email_body = "Hi there,

You've tried to reply to a ticket that is closed - we won't see your response.

Please raise a new ticket by sending a fresh e-mail to our support address.

--
$company_name
Support Department
$config_ticket_from_email
$company_phone"; $data = [ [ @@ -332,8 +332,8 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac $tech_email = sanitizeInput($tech_row['user_email']); $tech_name = sanitizeInput($tech_row['user_name']); - $subject = mysqli_escape_string($mysqli, "Ticket updated - [$config_ticket_prefix$ticket_number] - $subject"); - $body = mysqli_escape_string($mysqli, "##- Please type your reply above this line -##

Hello, $tech_name

A new reply has been added to the ticket \"$subject\".

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name
Support Department
$config_ticket_from_email
$company_phone"); + $subject = "Ticket updated - [$config_ticket_prefix$ticket_number] - $subject"; + $body = "##- Please type your reply above this line -##

Hello $tech_name\,

A new reply has been added to the ticket \"$subject\".

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support Department
$config_ticket_from_email
$company_phone"; $data = [ [ @@ -365,7 +365,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac return false; } } -// End Add Reply Function +// END ADD REPLY FUNCTION ------------------------------------------------- // Prepare connection string with encryption (TLS/SSL/) $imap_mailbox = "$config_imap_host:$config_imap_port/imap/$config_imap_encryption"; From 31d6605647282629a883a54da113b077e9326b64 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 15:15:49 -0500 Subject: [PATCH 15/98] Updated Closed Ticket Email as well --- cron_ticket_email_parser.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cron_ticket_email_parser.php b/cron_ticket_email_parser.php index 29b2a0a5..702a62e3 100644 --- a/cron_ticket_email_parser.php +++ b/cron_ticket_email_parser.php @@ -240,7 +240,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Ticket', notification = 'Email parser: $from_email attempted to re-open ticket $config_ticket_prefix$ticket_number (ID $ticket_id) - check inbox manually to see email', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id"); $email_subject = "Action required: This ticket is already closed"; - $email_body = "Hi there,

You've tried to reply to a ticket that is closed - we won't see your response.

Please raise a new ticket by sending a fresh e-mail to our support address.

--
$company_name
Support Department
$config_ticket_from_email
$company_phone"; + $email_body = "Hi there\,

You\'ve tried to reply to a ticket that is closed - we won\'t see your response.

Please raise a new ticket by sending a fresh e-mail to our support address below.

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $data = [ [ @@ -333,7 +333,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac $tech_name = sanitizeInput($tech_row['user_name']); $subject = "Ticket updated - [$config_ticket_prefix$ticket_number] - $subject"; - $body = "##- Please type your reply above this line -##

Hello $tech_name\,

A new reply has been added to the ticket \"$subject\".

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support Department
$config_ticket_from_email
$company_phone"; + $body = "##- Please type your reply above this line -##

Hello $tech_name\,

A new reply has been added to the ticket \"$subject\".

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $data = [ [ From d3aa2e7239a8013808f00dfb4bedc99d5ab494ed Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 16:45:39 -0500 Subject: [PATCH 16/98] Only allow A-Za-z- for Ticket Prefix --- cron_ticket_email_parser.php | 3 ++- settings_ticket.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cron_ticket_email_parser.php b/cron_ticket_email_parser.php index 702a62e3..9d9cd316 100644 --- a/cron_ticket_email_parser.php +++ b/cron_ticket_email_parser.php @@ -255,7 +255,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac addToMailQueue($mysqli, $data); - return false; + return true; } // Check WHO replied (was it the owner of the ticket or someone else on CC?) @@ -517,6 +517,7 @@ if ($emails) { imap_setflag_full($imap, $email, "\\Seen"); imap_mail_move($imap, $email, $imap_folder); } else { + // Basically just flags all emails keep them unread and it doesnt move closed tickets echo "Failed to process email - flagging for manual review."; imap_setflag_full($imap, $email, "\\Flagged"); } diff --git a/settings_ticket.php b/settings_ticket.php index ad699b67..29afe15b 100644 --- a/settings_ticket.php +++ b/settings_ticket.php @@ -18,7 +18,7 @@ require_once "inc_all_settings.php";
- +
From a46e41ce9c3ba548a27b3ed867c07d64d1d8ed95 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 17:58:54 -0500 Subject: [PATCH 17/98] Update/Fix Mail Functions in POST/invoice.php - sanitize POST vars instead the whole mail subject and body which prevents having a mixed of confusing redundant escaped and unescaped vars --- post/invoice.php | 190 ++++++++++++++++++++++------------------------- 1 file changed, 90 insertions(+), 100 deletions(-) diff --git a/post/invoice.php b/post/invoice.php index 6e964d16..41321cb5 100644 --- a/post/invoice.php +++ b/post/invoice.php @@ -631,39 +631,35 @@ if (isset($_POST['add_payment'])) { $row = mysqli_fetch_array($sql); $invoice_amount = floatval($row['invoice_amount']); - $invoice_prefix = $row['invoice_prefix']; + $invoice_prefix = sanitizeInput($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); - $invoice_url_key = $row['invoice_url_key']; - $invoice_currency_code = $row['invoice_currency_code']; + $invoice_url_key = sanitizeInput($row['invoice_url_key']); + $invoice_currency_code = sanitizeInput($row['invoice_currency_code']); $client_id = intval($row['client_id']); - $client_name = $row['client_name']; - $contact_name = $row['contact_name']; - $contact_email = $row['contact_email']; - $contact_phone = formatPhoneNumber($row['contact_phone']); + $client_name = sanitizeInput($row['client_name']); + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); + $contact_phone = sanitizeInput(formatPhoneNumber($row['contact_phone'])); $contact_extension = preg_replace("/[^0-9]/", '',$row['contact_extension']); - $contact_mobile = formatPhoneNumber($row['contact_mobile']); - - $invoice_prefix_escaped = sanitizeInput($row['invoice_prefix']); - $contact_name_escaped = sanitizeInput($row['contact_name']); - $contact_email_escaped = sanitizeInput($row['contact_email']); + $contact_mobile = sanitizeInput(formatPhoneNumber($row['contact_mobile'])); $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql); - $company_name = $row['company_name']; - $company_country = $row['company_country']; - $company_address = $row['company_address']; - $company_city = $row['company_city']; - $company_state = $row['company_state']; - $company_zip = $row['company_zip']; - $company_phone = formatPhoneNumber($row['company_phone']); - $company_email = $row['company_email']; - $company_website = $row['company_website']; - $company_logo = $row['company_logo']; + $company_name = sanitizeInput($row['company_name']); + $company_country = sanitizeInput($row['company_country']); + $company_address = sanitizeInput($row['company_address']); + $company_city = sanitizeInput($row['company_city']); + $company_state = sanitizeInput($row['company_state']); + $company_zip = sanitizeInput($row['company_zip']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); + $company_email = sanitizeInput($row['company_email']); + $company_website = sanitizeInput($row['company_website']); + $company_logo = sanitizeInput($row['company_logo']); // Sanitize Config vars from get_settings.php - $config_invoice_from_name_escaped = sanitizeInput($config_invoice_from_name); - $config_invoice_from_email_escaped = sanitizeInput($config_invoice_from_email); + $config_invoice_from_name = sanitizeInput($config_invoice_from_name); + $config_invoice_from_email = sanitizeInput($config_invoice_from_email); //Calculate the Invoice balance $invoice_balance = $invoice_amount - $total_payments_amount; @@ -677,15 +673,15 @@ if (isset($_POST['add_payment'])) { if ($email_receipt == 1) { - $subject = sanitizeInput("Payment Received - Invoice $invoice_prefix$invoice_number"); - $body = mysqli_real_escape_string($mysqli, "Hello $contact_name,

We have received your payment in the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, $invoice_balance, $invoice_currency_code) . "

Thank you for your business!


~
$company_name
Billing Department
$config_invoice_from_email
$company_phone"); + $subject = "Payment Received - Invoice $invoice_prefix$invoice_number"; + $body = "Hello $contact_name\,

We have received your payment in the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, $invoice_balance, $invoice_currency_code) . "

Thank you for your business!


--
$company_name - Billing Department
$config_invoice_from_email
$company_phone"; // Queue Mail $email = [ 'from' => $config_invoice_from_email, 'from_name' => $config_invoice_from_name, - 'recipient' => $contact_email_escaped, - 'recipient_name' => $contact_name_escaped, + 'recipient' => $contact_email, + 'recipient_name' => $contact_name, 'subject' => $subject, 'body' => $body ]; @@ -710,15 +706,15 @@ if (isset($_POST['add_payment'])) { if ($email_receipt == 1) { - $subject = sanitizeInput("Partial Payment Recieved - Invoice $invoice_prefix$invoice_number"); - $body = mysqli_real_escape_string($mysqli, "Hello $contact_name,

We have recieved partial payment in the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " and it has been applied to invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, $invoice_balance, $invoice_currency_code) . "

Thank you for your business!


~
$company_name
Billing Department
$config_invoice_from_email
$company_phone"); + $subject = "Partial Payment Recieved - Invoice $invoice_prefix$invoice_number"; + $body = "Hello $contact_name\,

We have recieved partial payment in the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " and it has been applied to invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, $invoice_balance, $invoice_currency_code) . "

Thank you for your business!


~
$company_name - Billing
$config_invoice_from_email
$company_phone"; // Queue Mail $email = [ 'from' => $config_invoice_from_email, 'from_name' => $config_invoice_from_name, - 'recipient' => $contact_email_escaped, - 'recipient_name' => $contact_name_escaped, + 'recipient' => $contact_email, + 'recipient_name' => $contact_name, 'subject' => $subject, 'body' => $body ]; @@ -753,7 +749,7 @@ if (isset($_POST['add_payment'])) { mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Payment', log_action = 'Create', log_description = '$payment_amount', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $payment_id"); if ($email_receipt == 1) { - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Payment', log_action = 'Email', log_description = 'Payment receipt for invoice $invoice_prefix_escaped$invoice_number queued to $contact_email_escaped Email ID: $email_id', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $payment_id"); + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Payment', log_action = 'Email', log_description = 'Payment receipt for invoice $invoice_prefix$invoice_number queued to $contact_email Email ID: $email_id', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $payment_id"); } $_SESSION['alert_message'] .= "Payment added"; @@ -839,7 +835,7 @@ if (isset($_POST['add_bulk_payment'])) { // Add to Email Body Invoice Portion - $email_body_invoices .= mysqli_real_escape_string($mysqli, "
Invoice $invoice_prefix$invoice_number - Outstanding Amount: " . numfmt_format_currency($currency_format, $invoice_balance, $currency_code) . " - Payment Applied: " . numfmt_format_currency($currency_format, $payment_amount, $currency_code) . " - New Balance: " . numfmt_format_currency($currency_format, $remaining_invoice_balance, $currency_code)); + $email_body_invoices .= "
Invoice $invoice_prefix$invoice_number - Outstanding Amount: " . numfmt_format_currency($currency_format, $invoice_balance, $currency_code) . " - Payment Applied: " . numfmt_format_currency($currency_format, $payment_amount, $currency_code) . " - New Balance: " . numfmt_format_currency($currency_format, $remaining_invoice_balance, $currency_code); } // End Invoice Loop @@ -855,34 +851,31 @@ if (isset($_POST['add_bulk_payment'])) { ); $row = mysqli_fetch_array($sql_client); - $client_name = $row['client_name']; - $contact_name = $row['contact_name']; - $contact_email = $row['contact_email']; + $client_name = sanitizeInput($row['client_name']); + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); - $contact_name_escaped = sanitizeInput($row['contact_name']); - $contact_email_escaped = sanitizeInput($row['contact_email']); - - $sql_company = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $sql_company = mysqli_query($mysqli,"SELECT company_name, company_phone FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql_company); - $company_name = $row['company_name']; - $company_phone = formatPhoneNumber($row['company_phone']); + $company_name = sanitizeInput($row['company_name']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); // Sanitize Config vars from get_settings.php - $config_invoice_from_name_escaped = sanitizeInput($config_invoice_from_name); - $config_invoice_from_email_escaped = sanitizeInput($config_invoice_from_email); + $config_invoice_from_name = sanitizeInput($config_invoice_from_name); + $config_invoice_from_email = sanitizeInput($config_invoice_from_email); - $subject = sanitizeInput("Payment Received - Multiple Invoices"); - $body = mysqli_real_escape_string($mysqli, "Hello $contact_name,

Thank you for your payment of " . numfmt_format_currency($currency_format, $bulk_payment_amount_static, $currency_code) . " We've applied your payment to the following invoices, updating their balances accordingly:

$email_body_invoices


We appreciate your continued business!

Sincerely,
$company_name Billing Department
$config_invoice_from_email
$company_phone"); + $subject = "Payment Received - Multiple Invoices"; + $body = "Hello $contact_name\,

Thank you for your payment of " . numfmt_format_currency($currency_format, $bulk_payment_amount_static, $currency_code) . " We\'ve applied your payment to the following invoices\, updating their balances accordingly:

$email_body_invoices


We appreciate your continued business!

Sincerely\,
$company_name - Billing
$config_invoice_from_email
$company_phone"; // Queue Mail - mysqli_query($mysqli, "INSERT INTO email_queue SET email_recipient = '$contact_email_escaped', email_recipient_name = '$contact_name_escaped', email_from = '$config_invoice_from_email_escaped', email_from_name = '$config_invoice_from_name_escaped', email_subject = '$subject', email_content = '$body'"); + mysqli_query($mysqli, "INSERT INTO email_queue SET email_recipient = '$contact_email', email_recipient_name = '$contact_name', email_from = '$config_invoice_from_email', email_from_name = '$config_invoice_from_name', email_subject = '$subject', email_content = '$body'"); // Get Email ID for reference $email_id = mysqli_insert_id($mysqli); // Email Logging - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Payment', log_action = 'Email', log_description = 'Bulk Payment receipt for multiple Invoices queued to $contact_email_escaped Email ID: $email_id', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $payment_id"); + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Payment', log_action = 'Email', log_description = 'Bulk Payment receipt for multiple Invoices queued to $contact_email Email ID: $email_id', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $payment_id"); $_SESSION['alert_message'] .= "Email receipt sent and "; @@ -954,39 +947,36 @@ if (isset($_GET['email_invoice'])) { $row = mysqli_fetch_array($sql); $invoice_id = intval($row['invoice_id']); - $invoice_prefix = $row['invoice_prefix']; + $invoice_prefix = sanitizeInput($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); - $invoice_status = $row['invoice_status']; - $invoice_date = $row['invoice_date']; - $invoice_due = $row['invoice_due']; + $invoice_status = sanitizeInput($row['invoice_status']); + $invoice_date = sanitizeInput($row['invoice_date']); + $invoice_due = sanitizeInput($row['invoice_due']); $invoice_amount = floatval($row['invoice_amount']); - $invoice_url_key = $row['invoice_url_key']; - $invoice_currency_code = $row['invoice_currency_code']; + $invoice_url_key = sanitizeInput($row['invoice_url_key']); + $invoice_currency_code = sanitizeInput($row['invoice_currency_code']); $client_id = intval($row['client_id']); - $client_name = $row['client_name']; - $contact_name = $row['contact_name']; - $contact_email = $row['contact_email']; - $invoice_prefix_escaped = sanitizeInput($row['invoice_prefix']); - $contact_name_escaped = sanitizeInput($row['contact_name']); - $contact_email_escaped = sanitizeInput($row['contact_email']); + $client_name = sanitizeInput($row['client_name']); + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql); - $company_name = $row['company_name']; - $company_country = $row['company_country']; - $company_address = $row['company_address']; - $company_city = $row['company_city']; - $company_state = $row['company_state']; - $company_zip = $row['company_zip']; - $company_phone = formatPhoneNumber($row['company_phone']); - $company_email = $row['company_email']; - $company_website = $row['company_website']; - $company_logo = $row['company_logo']; + $company_name = sanitizeInput($row['company_name']); + $company_country = sanitizeInput($row['company_country']); + $company_address = sanitizeInput($row['company_address']); + $company_city = sanitizeInput($row['company_city']); + $company_state = sanitizeInput($row['company_state']); + $company_zip = sanitizeInput($row['company_zip']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); + $company_email = sanitizeInput($row['company_email']); + $company_website = sanitizeInput($row['company_website']); + $company_logo = sanitizeInput($row['company_logo']); // Sanitize Config vars from get_settings.php - $config_invoice_from_name_escaped = sanitizeInput($config_invoice_from_name); - $config_invoice_from_email_escaped = sanitizeInput($config_invoice_from_email); + $config_invoice_from_name = sanitizeInput($config_invoice_from_name); + $config_invoice_from_email = sanitizeInput($config_invoice_from_email); $sql_payments = mysqli_query($mysqli,"SELECT * FROM payments, accounts WHERE payment_account_id = account_id AND payment_invoice_id = $invoice_id ORDER BY payment_id DESC"); @@ -998,20 +988,20 @@ if (isset($_GET['email_invoice'])) { $balance = $invoice_amount - $amount_paid; if ($invoice_status == 'Paid') { - $subject = sanitizeInput("Invoice $invoice_prefix$invoice_number Receipt"); - $body = mysqli_real_escape_string($mysqli, "Hello $contact_name,

Please click on the link below to see your invoice marked paid.

Invoice Link


~
$company_name
Billing Department
$config_invoice_from_email
$company_phone"); + $subject = "Invoice $invoice_prefix$invoice_number Receipt"; + $body = "Hello $contact_name\,

Please click on the link below to see your invoice marked paid.

Invoice Link


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; } else { - $subject = sanitizeInput("Invoice $invoice_prefix$invoice_number"); - $body = mysqli_real_escape_string($mysqli, "Hello $contact_name,

Please view the details of the invoice below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . "
Balance Due: " . numfmt_format_currency($currency_format, $balance, $invoice_currency_code) . "
Due Date: $invoice_due


To view your invoice click here


~
$company_name
Billing Department
$config_invoice_from_email
$company_phone"); + $subject = "Invoice $invoice_prefix$invoice_number"; + $body = "Hello $contact_name\,

Please view the details of the invoice below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . "
Balance Due: " . numfmt_format_currency($currency_format, $balance, $invoice_currency_code) . "
Due Date: $invoice_due


To view your invoice click here


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; } // Queue Mail $data = [ [ - 'from' => $config_invoice_from_email_escaped, - 'from_name' => $config_invoice_from_name_escaped, - 'recipient' => $contact_email_escaped, - 'recipient_name' => $contact_name_escaped, + 'from' => $config_invoice_from_email, + 'from_name' => $config_invoice_from_name, + 'recipient' => $contact_email, + 'recipient_name' => $contact_name, 'subject' => $subject, 'body' => $body ] @@ -1031,7 +1021,7 @@ if (isset($_GET['email_invoice'])) { } // Logging - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Invoice', log_action = 'Email', log_description = 'Invoice $invoice_prefix_escaped$invoice_number queued to $contact_email_escaped Email ID: $email_id', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $invoice_id"); + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Invoice', log_action = 'Email', log_description = 'Invoice $invoice_prefix$invoice_number queued to $contact_email Email ID: $email_id', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $invoice_id"); // Send copies of the invoice to any additional billing contacts $sql_billing_contacts = mysqli_query( @@ -1061,7 +1051,7 @@ if (isset($_GET['email_invoice'])) { ]; // Logging - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Invoice', log_action = 'Email', log_description = 'Invoice $invoice_prefix_escaped$invoice_number queued to $billing_contact_email Email ID: $email_id', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $invoice_id"); + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Invoice', log_action = 'Email', log_description = 'Invoice $invoice_prefix$invoice_number queued to $billing_contact_email Email ID: $email_id', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $invoice_id"); } addToMailQueue($mysqli, $data); @@ -1152,32 +1142,32 @@ if (isset($_GET['force_recurring'])) { ); $row = mysqli_fetch_array($sql); - $invoice_prefix = $row['invoice_prefix']; + $invoice_prefix = sanitizeInput($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); - $invoice_scope = $row['invoice_scope']; - $invoice_date = $row['invoice_date']; - $invoice_due = $row['invoice_due']; + $invoice_scope = sanitizeInput($row['invoice_scope']); + $invoice_date = sanitizeInput($row['invoice_date']); + $invoice_due = sanitizeInput($row['invoice_due']); $invoice_amount = floatval($row['invoice_amount']); - $invoice_url_key = $row['invoice_url_key']; + $invoice_url_key = sanitizeInput($row['invoice_url_key']); $client_id = intval($row['client_id']); - $client_name = $row['client_name']; - $contact_name = $row['contact_name']; - $contact_email = $row['contact_email']; - $contact_phone = formatPhoneNumber($row['contact_phone']); - $contact_extension = $row['contact_extension']; - $contact_mobile = formatPhoneNumber($row['contact_mobile']); + $client_name = sanitizeInput($row['client_name']); + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); + $contact_phone = sanitizeInput(formatPhoneNumber($row['contact_phone'])); + $contact_extension = intval($row['contact_extension']); + $contact_mobile = sanitizeInput(formatPhoneNumber($row['contact_mobile'])); $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql); - $company_name = $row['company_name']; - $company_phone = formatPhoneNumber($row['company_phone']); - $company_email = $row['company_email']; - $company_website = $row['company_website']; + $company_name = sanitizeInput($row['company_name']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); + $company_email = sanitizeInput($row['company_email']); + $company_website = sanitizeInput($row['company_website']); // Email to client - $subject = mysqli_real_escape_string($mysqli, "Invoice $invoice_prefix$invoice_number"); - $body = mysqli_real_escape_string($mysqli, "Hello $contact_name,

Please view the details of the invoice below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: $$invoice_amount
Due Date: $invoice_due


To view your invoice click here


~
$company_name
$company_phone"); + $subject = "Invoice $invoice_prefix$invoice_number"; + $body = "Hello $contact_name\,

Please view the details of the invoice below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: $$invoice_amount
Due Date: $invoice_due


To view your invoice click here


--
$company_name - Billing
$company_phone"; $data = [ From 91eff8f9b629e62a68b039521623d5a69bdb1ff7 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 18:13:47 -0500 Subject: [PATCH 18/98] no need to SQL escape , in the emails, so removed the \, escaping in post invoice, ticket and ticket_email_parser --- cron_ticket_email_parser.php | 8 ++++---- post/invoice.php | 12 ++++++------ post/setting.php | 2 +- post/ticket.php | 14 +++++++------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cron_ticket_email_parser.php b/cron_ticket_email_parser.php index 9d9cd316..b168e405 100644 --- a/cron_ticket_email_parser.php +++ b/cron_ticket_email_parser.php @@ -164,7 +164,7 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date if ($config_ticket_client_general_notifications == 1) { $subject_email = "Ticket created - [$config_ticket_prefix$ticket_number] - $subject"; - $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "##- Please type your reply above this line -##

Hello $contact_name,

Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $data[] = [ 'from' => $config_ticket_from_email, @@ -185,7 +185,7 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date $client_name = sanitizeInput($client_row['client_name']); $email_subject = "ITFlow - New Ticket - $client_name: $subject"; - $email_body = "Hello\,

This is a notification that a new ticket has been raised in ITFlow.
Client: $client_name
Priority: Low (email parsed)
Link: https://$config_base_url/ticket.php?ticket_id=$id

--------------------------------

$subject
$details"; + $email_body = "Hello,

This is a notification that a new ticket has been raised in ITFlow.
Client: $client_name
Priority: Low (email parsed)
Link: https://$config_base_url/ticket.php?ticket_id=$id

--------------------------------

$subject
$details"; $data[] = [ 'from' => $config_ticket_from_email, @@ -240,7 +240,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Ticket', notification = 'Email parser: $from_email attempted to re-open ticket $config_ticket_prefix$ticket_number (ID $ticket_id) - check inbox manually to see email', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id"); $email_subject = "Action required: This ticket is already closed"; - $email_body = "Hi there\,

You\'ve tried to reply to a ticket that is closed - we won\'t see your response.

Please raise a new ticket by sending a fresh e-mail to our support address below.

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + $email_body = "Hi there,

You\'ve tried to reply to a ticket that is closed - we won\'t see your response.

Please raise a new ticket by sending a fresh e-mail to our support address below.

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $data = [ [ @@ -333,7 +333,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac $tech_name = sanitizeInput($tech_row['user_name']); $subject = "Ticket updated - [$config_ticket_prefix$ticket_number] - $subject"; - $body = "##- Please type your reply above this line -##

Hello $tech_name\,

A new reply has been added to the ticket \"$subject\".

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "##- Please type your reply above this line -##

Hello $tech_name,

A new reply has been added to the ticket \"$subject\".

Ticket: $config_ticket_prefix$ticket_number
Subject: $subject
Status: Open
https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $data = [ [ diff --git a/post/invoice.php b/post/invoice.php index 41321cb5..0ffedaf0 100644 --- a/post/invoice.php +++ b/post/invoice.php @@ -674,7 +674,7 @@ if (isset($_POST['add_payment'])) { if ($email_receipt == 1) { $subject = "Payment Received - Invoice $invoice_prefix$invoice_number"; - $body = "Hello $contact_name\,

We have received your payment in the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, $invoice_balance, $invoice_currency_code) . "

Thank you for your business!


--
$company_name - Billing Department
$config_invoice_from_email
$company_phone"; + $body = "Hello $contact_name,

We have received your payment in the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, $invoice_balance, $invoice_currency_code) . "

Thank you for your business!


--
$company_name - Billing Department
$config_invoice_from_email
$company_phone"; // Queue Mail $email = [ @@ -707,7 +707,7 @@ if (isset($_POST['add_payment'])) { $subject = "Partial Payment Recieved - Invoice $invoice_prefix$invoice_number"; - $body = "Hello $contact_name\,

We have recieved partial payment in the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " and it has been applied to invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, $invoice_balance, $invoice_currency_code) . "

Thank you for your business!


~
$company_name - Billing
$config_invoice_from_email
$company_phone"; + $body = "Hello $contact_name,

We have recieved partial payment in the amount of " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . " and it has been applied to invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $amount, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, $invoice_balance, $invoice_currency_code) . "

Thank you for your business!


~
$company_name - Billing
$config_invoice_from_email
$company_phone"; // Queue Mail $email = [ @@ -866,7 +866,7 @@ if (isset($_POST['add_bulk_payment'])) { $config_invoice_from_email = sanitizeInput($config_invoice_from_email); $subject = "Payment Received - Multiple Invoices"; - $body = "Hello $contact_name\,

Thank you for your payment of " . numfmt_format_currency($currency_format, $bulk_payment_amount_static, $currency_code) . " We\'ve applied your payment to the following invoices\, updating their balances accordingly:

$email_body_invoices


We appreciate your continued business!

Sincerely\,
$company_name - Billing
$config_invoice_from_email
$company_phone"; + $body = "Hello $contact_name,

Thank you for your payment of " . numfmt_format_currency($currency_format, $bulk_payment_amount_static, $currency_code) . " We\'ve applied your payment to the following invoices, updating their balances accordingly:

$email_body_invoices


We appreciate your continued business!

Sincerely,
$company_name - Billing
$config_invoice_from_email
$company_phone"; // Queue Mail mysqli_query($mysqli, "INSERT INTO email_queue SET email_recipient = '$contact_email', email_recipient_name = '$contact_name', email_from = '$config_invoice_from_email', email_from_name = '$config_invoice_from_name', email_subject = '$subject', email_content = '$body'"); @@ -989,10 +989,10 @@ if (isset($_GET['email_invoice'])) { if ($invoice_status == 'Paid') { $subject = "Invoice $invoice_prefix$invoice_number Receipt"; - $body = "Hello $contact_name\,

Please click on the link below to see your invoice marked paid.

Invoice Link


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; + $body = "Hello $contact_name,

Please click on the link below to see your invoice marked paid.

Invoice Link


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; } else { $subject = "Invoice $invoice_prefix$invoice_number"; - $body = "Hello $contact_name\,

Please view the details of the invoice below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . "
Balance Due: " . numfmt_format_currency($currency_format, $balance, $invoice_currency_code) . "
Due Date: $invoice_due


To view your invoice click here


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; + $body = "Hello $contact_name,

Please view the details of the invoice below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . "
Balance Due: " . numfmt_format_currency($currency_format, $balance, $invoice_currency_code) . "
Due Date: $invoice_due


To view your invoice click here


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; } // Queue Mail @@ -1167,7 +1167,7 @@ if (isset($_GET['force_recurring'])) { // Email to client $subject = "Invoice $invoice_prefix$invoice_number"; - $body = "Hello $contact_name\,

Please view the details of the invoice below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: $$invoice_amount
Due Date: $invoice_due


To view your invoice click here


--
$company_name - Billing
$company_phone"; + $body = "Hello $contact_name,

Please view the details of the invoice below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: $$invoice_amount
Due Date: $invoice_due


To view your invoice click here


--
$company_name - Billing
$company_phone"; $data = [ diff --git a/post/setting.php b/post/setting.php index ab1070bf..62ec9514 100644 --- a/post/setting.php +++ b/post/setting.php @@ -169,7 +169,7 @@ if (isset($_POST['test_email_smtp'])) { $email_to = sanitizeInput($_POST['email_to']); $subject = "Test email from ITFlow"; - $body = "This is a test email from ITFlow. If you are reading this, it worked!"; + $body = "This is a test email from ITFlow. If you are reading this, it worked!"; $data = [ [ diff --git a/post/ticket.php b/post/ticket.php index e7f0b059..f2df705b 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -95,7 +95,7 @@ if (isset($_POST['add_ticket'])) { if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { $subject = "Ticket created [$ticket_prefix$ticket_number] - $ticket_subject"; - $body = "##- Please type your reply above this line -##

Hello $contact_name\,

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "##- Please type your reply above this line -##

Hello $contact_name,

A ticket regarding \"$ticket_subject\" has been created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; // Email Ticket Contact // Queue Mail @@ -346,7 +346,7 @@ if (isset($_POST['assign_ticket'])) { // Allow for un-assigning tickets if ($assigned_to == 0) { - $ticket_reply = "Ticket unassigned\, pending re-assignment."; + $ticket_reply = "Ticket unassigned, pending re-assignment."; $agent_name = "No One"; $ticket_status = "Pending-Assignment"; } else { @@ -406,7 +406,7 @@ if (isset($_POST['assign_ticket'])) { $company_name = sanitizeInput($session_company_name); $subject = "$config_app_name ticket $ticket_prefix$ticket_number assigned to you"; - $body = "Hi $agent_name\,

A ticket has been assigned to you!

Ticket Number: $ticket_prefix$ticket_number
Subject: $ticket_subject

Thanks\,
$session_name
$company_name"; + $body = "Hi $agent_name,

A ticket has been assigned to you!

Ticket Number: $ticket_prefix$ticket_number
Subject: $ticket_subject

Thanks,
$session_name
$company_name"; // Email Ticket Agent // Queue Mail @@ -542,15 +542,15 @@ if (isset($_POST['add_ticket_reply'])) { if ($ticket_status == 'Closed') { $subject = "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"; - $body = "Hello $contact_name\,

Your ticket regarding $ticket_subject has been closed.

--------------------------------
$ticket_reply
--------------------------------

We hope the issue was resolved to your satisfaction. If you need further assistance\, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "Hello $contact_name,

Your ticket regarding $ticket_subject has been closed.

--------------------------------
$ticket_reply
--------------------------------

We hope the issue was resolved to your satisfaction. If you need further assistance, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; } elseif ($ticket_status == 'Auto Close') { $subject = "Ticket update - [$ticket_prefix$ticket_number] - $ticket_subject | (pending closure)"; - $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Your ticket regarding $ticket_subject has been updated and is pending closure.

--------------------------------
$ticket_reply
--------------------------------

If your issue is resolved\, you can ignore this email. If you need further assistance\, please respond!

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "##- Please type your reply above this line -##

Hello $contact_name,

Your ticket regarding $ticket_subject has been updated and is pending closure.

--------------------------------
$ticket_reply
--------------------------------

If your issue is resolved, you can ignore this email. If you need further assistance, please respond!

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; } else { $subject = "Ticket update - [$ticket_prefix$ticket_number] - $ticket_subject"; - $body = "##- Please type your reply above this line -##

Hello $contact_name\,

Your ticket regarding $ticket_subject has been updated.

--------------------------------
$ticket_reply
--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "##- Please type your reply above this line -##

Hello $contact_name,

Your ticket regarding $ticket_subject has been updated.

--------------------------------
$ticket_reply
--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; } @@ -777,7 +777,7 @@ if (isset($_GET['close_ticket'])) { $data = []; $subject = "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"; - $body = "Hello $contact_name\,

Your ticket regarding \"$ticket_subject\" has been closed.

We hope the issue was resolved to your satisfaction. If you need further assistance\, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "Hello $contact_name,

Your ticket regarding \"$ticket_subject\" has been closed.

We hope the issue was resolved to your satisfaction. If you need further assistance, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; // Email Ticket Contact // Queue Mail From 92ccd7de14eb00be764e2d79eca0146e7bbbb837 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 19:08:51 -0500 Subject: [PATCH 19/98] Update/Fix Mail Functions in POST/contact.php and event.php - sanitize POST vars instead the whole mail subject and body which prevents having a mixed of confusing redundant escaped and unescaped vars also fixed scheduling calendar events was not working to send an email out --- login.php | 4 +-- post/contact.php | 25 ++++++++++------- post/event.php | 70 +++++++++++++++++++++++++++--------------------- 3 files changed, 56 insertions(+), 43 deletions(-) diff --git a/login.php b/login.php index d64330c9..dd1e2c25 100644 --- a/login.php +++ b/login.php @@ -56,8 +56,8 @@ $config_smtp_port = intval($row['config_smtp_port']); $config_smtp_encryption = $row['config_smtp_encryption']; $config_smtp_username = $row['config_smtp_username']; $config_smtp_password = $row['config_smtp_password']; -$config_mail_from_email = $row['config_mail_from_email']; -$config_mail_from_name = $row['config_mail_from_name']; +$config_mail_from_email = sanitizeInput($row['config_mail_from_email']); +$config_mail_from_name = sanitizeInput($row['config_mail_from_name']); // Client Portal Enabled $config_client_portal_enable = intval($row['config_client_portal_enable']); diff --git a/post/contact.php b/post/contact.php index 2a730981..036096d8 100644 --- a/post/contact.php +++ b/post/contact.php @@ -68,7 +68,6 @@ if (isset($_POST['edit_contact'])) { require_once 'post/contact_model.php'; - $contact_id = intval($_POST['contact_id']); $send_email = intval($_POST['send_email']); @@ -98,12 +97,18 @@ if (isset($_POST['edit_contact'])) { // Send contact a welcome e-mail, if specified if ($send_email && !empty($auth_method) && !empty($config_smtp_host)) { - // Un-sanitizied used in body of email - $contact_name = $_POST['name']; - // Sanitize Config vars from get_settings.php - $config_ticket_from_email_escaped = sanitizeInput($config_ticket_from_email); - $config_ticket_from_name_escaped = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_mail_from_email = sanitizeInput($config_mail_from_email); + $config_mail_from_name = sanitizeInput($config_mail_from_name); + $config_base_url = sanitizeInput($config_base_url); + + // Get Company Phone Number + $sql = mysqli_query($mysqli,"SELECT company_name, company_phone FROM companies WHERE company_id = 1"); + $row = mysqli_fetch_array($sql); + $company_name = sanitizeInput($row['company_name']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); // Authentication info (azure, reset password, or tech-provided temporary password) @@ -112,11 +117,11 @@ if (isset($_POST['edit_contact'])) { } elseif (empty($_POST['contact_password'])) { $password_info = "Request a password reset at https://$config_base_url/portal/login_reset.php"; } else { - $password_info = $_POST['contact_password'] . " -- Please change on first login"; + $password_info = mysqli_real_escape_string($mysqli, $_POST['contact_password'] . " -- Please change on first login"); } - $subject = sanitizeInput("Your new $session_company_name support portal account"); - $body = mysqli_real_escape_string($mysqli, "Hello, $contact_name

$session_company_name has created a support portal account for you.

Username: $email
Password: $password_info

Login URL: https://$config_base_url/portal/

~
$session_company_name
Support Department
$config_ticket_from_email"); + $subject = "Your new $company_name portal account"; + $body = "Hello $name,

$company_name has created a support portal account for you.

Username: $email
Password: $password_info

Login URL: https://$config_base_url/portal/

--
$company_name - Support
$config_ticket_from_email
$company_phone"; // Queue Mail $data = [ @@ -124,7 +129,7 @@ if (isset($_POST['edit_contact'])) { 'from' => $config_mail_from_email, 'from_name' => $config_mail_from_name, 'recipient' => $email, - 'recipient_name' => $contact_name, + 'recipient_name' => $name, 'subject' => $subject, 'body' => $body, ] diff --git a/post/event.php b/post/event.php index cbfddd9e..2955a31c 100644 --- a/post/event.php +++ b/post/event.php @@ -39,27 +39,31 @@ if (isset($_POST['add_event'])) { //If email is checked if ($email_event == 1) { - $sql_client = mysqli_query($mysqli,"SELECT * FROM clients JOIN contacts ON primary_contact = contact_id WHERE client_id = $client"); + $sql_client = mysqli_query($mysqli,"SELECT * FROM clients JOIN contacts ON contact_client_id = client_id WHERE contact_primary = 1 AND client_id = $client"); $row = mysqli_fetch_array($sql_client); - $client_name = $row['client_name']; - $contact_name = $row['contact_name']; - $contact_email = $row['contact_email']; + $client_name = sanitizeInput($row['client_name']); + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); $sql_company = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql_company); - $company_name = $row['company_name']; - $company_country = $row['company_country']; - $company_address = $row['company_address']; - $company_city = $row['company_city']; - $company_state = $row['company_state']; - $company_zip = $row['company_zip']; - $company_phone = formatPhoneNumber($row['company_phone']); - $company_email = $row['company_email']; - $company_website = $row['company_website']; - $company_logo = $row['company_logo']; + $company_name = sanitizeInput($row['company_name']); + $company_country = sanitizeInput($row['company_country']); + $company_address = sanitizeInput($row['company_address']); + $company_city = sanitizeInput($row['company_city']); + $company_state = sanitizeInput($row['company_state']); + $company_zip = sanitizeInput($row['company_zip']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); + $company_email = sanitizeInput($row['company_email']); + $company_website = sanitizeInput($row['company_website']); + $company_logo = sanitizeInput($row['company_logo']); + + // Sanitize Config Vars from get_settings.php and Session Vars from check_login.php + $config_mail_from_name = sanitizeInput($config_mail_from_name); + $config_mail_from_email = sanitizeInput($config_mail_from_email); $subject = "New Calendar Event"; - $body = "Hello $contact_name,

A calendar event has been scheduled: $title at $start


~
$company_name
$company_phone"; + $body = "Hello $contact_name,

A calendar event has been scheduled:

Event Title: $title
Event Date: $start


--
$company_name
$company_phone"; $data = [ [ @@ -75,7 +79,7 @@ if (isset($_POST['add_event'])) { // Logging for email (success/fail) if ($mail === true) { - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Calendar Event', log_action = 'Email', log_description = '$session_name emailed event $title to $contact_name from client $client_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', client_id = $client, log_user_id = $session_user_id, log_entity_id = $event_id"); + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Calendar Event', log_action = 'Email', log_description = '$session_name emailed event $title to $contact_name from client $client_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client, log_user_id = $session_user_id, log_entity_id = $event_id"); } else { mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Mail', notification = 'Failed to send email to $contact_email'"); mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Mail', log_action = 'Error', log_description = 'Failed to send email to $contact_email regarding $subject. $mail', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); @@ -104,28 +108,32 @@ if (isset($_POST['edit_event'])) { //If email is checked if ($email_event == 1) { - $sql_client = mysqli_query($mysqli,"SELECT * FROM clients JOIN contacts ON primary_contact = contact_id WHERE client_id = $client"); + $sql_client = mysqli_query($mysqli,"SELECT * FROM clients JOIN contacts ON contact_client_id = client_id WHERE contact_primary = 1 AND client_id = $client"); $row = mysqli_fetch_array($sql_client); - $client_name = $row['client_name']; - $contact_name = $row['contact_name']; - $contact_email = $row['contact_email']; + $client_name = sanitizeInput($row['client_name']); + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); $sql_company = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql_company); - $company_name = $row['company_name']; - $company_country = $row['company_country']; - $company_address = $row['company_address']; - $company_city = $row['company_city']; - $company_state = $row['company_state']; - $company_zip = $row['company_zip']; - $company_phone = formatPhoneNumber($row['company_phone']); - $company_email = $row['company_email']; - $company_website = $row['company_website']; - $company_logo = $row['company_logo']; + $company_name = sanitizeInput($row['company_name']); + $company_country = sanitizeInput($row['company_country']); + $company_address = sanitizeInput($row['company_address']); + $company_city = sanitizeInput($row['company_city']); + $company_state = sanitizeInput($row['company_state']); + $company_zip = sanitizeInput($row['company_zip']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); + $company_email = sanitizeInput($row['company_email']); + $company_website = sanitizeInput($row['company_website']); + $company_logo = sanitizeInput($row['company_logo']); + + // Sanitize Config Vars from get_settings.php and Session Vars from check_login.php + $config_mail_from_name = sanitizeInput($config_mail_from_name); + $config_mail_from_email = sanitizeInput($config_mail_from_email); $subject = "Calendar Event Rescheduled"; - $body = "Hello $contact_name,

A calendar event has been rescheduled: $title at $start


~
$company_name
$company_phone"; + $body = "Hello $contact_name,

A calendar event has been rescheduled:

Event Title: $title
Event Date: $start


--
$company_name
$company_phone"; $data = [ [ From 9d60ccdf3ee53a07ca29d7ccb4ff9087249019cc Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 19:25:15 -0500 Subject: [PATCH 20/98] Updated UI on add/Edit Calendar events --- calendar_event_add_modal.php | 39 +++++++++++++++-------------- calendar_event_edit_modal.php | 47 +++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/calendar_event_add_modal.php b/calendar_event_add_modal.php index 9b7ad916..6b14e997 100644 --- a/calendar_event_add_modal.php +++ b/calendar_event_add_modal.php @@ -14,9 +14,6 @@ - @@ -61,24 +58,24 @@ - -
-
- -
-
- -
-
-
- - + +
+
+ +
+ +
+
+ +
+
+
+ +
+ +
- - - -
@@ -96,6 +93,10 @@
+
+ +
+
diff --git a/calendar_event_edit_modal.php b/calendar_event_edit_modal.php index 01b46cce..3eee42a7 100644 --- a/calendar_event_edit_modal.php +++ b/calendar_event_edit_modal.php @@ -17,9 +17,6 @@ - @@ -63,24 +60,25 @@
- -
-
- -
-
- -
-
- +
- - + +
+
+ +
+ +
+
+ +
+
+
+ +
+ +
- - - -
@@ -98,6 +96,17 @@
+
+ + +
+ + + +
+ + +
From 1479caa8e8ece2abb8224fb9cd22976e259c103e Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 19:26:00 -0500 Subject: [PATCH 21/98] Set Textarea rows from 4 to 5 --- calendar_event_edit_modal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calendar_event_edit_modal.php b/calendar_event_edit_modal.php index 3eee42a7..99eb0207 100644 --- a/calendar_event_edit_modal.php +++ b/calendar_event_edit_modal.php @@ -98,7 +98,7 @@
- +
From 63d4419ff58cc1bc7f09946a45d81f0797fb6d96 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 20:10:33 -0500 Subject: [PATCH 22/98] Update/Fix Mail Functions in POST/quote.php - sanitize POST vars instead the whole mail subject and body which prevents having a mixed of confusing redundant escaped and unescaped vars also --- post/invoice_model.php | 4 ++- post/profile.php | 19 ++++++++++++-- post/quote.php | 59 ++++++++++++++++++++---------------------- post/quote_model.php | 2 ++ 4 files changed, 50 insertions(+), 34 deletions(-) diff --git a/post/invoice_model.php b/post/invoice_model.php index b124a486..2319db50 100644 --- a/post/invoice_model.php +++ b/post/invoice_model.php @@ -3,4 +3,6 @@ $date = sanitizeInput($_POST['date']); $category = intval($_POST['category']); $scope = sanitizeInput($_POST['scope']); $invoice_discount = floatval($_POST['invoice_discount']); -$recurring_discount = floatval($_POST['recurring_discount']); \ No newline at end of file +$recurring_discount = floatval($_POST['recurring_discount']); + +$config_invoice_prefix = sanitizeInput($config_invoice_prefix); \ No newline at end of file diff --git a/post/profile.php b/post/profile.php index 38410fbf..93222dd1 100644 --- a/post/profile.php +++ b/post/profile.php @@ -23,6 +23,11 @@ if (isset($_POST['edit_your_user_details'])) { $user_old_email_sql = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT user_email FROM users WHERE user_id = $session_user_id")); $user_old_email = sanitizeInput($user_old_email_sql['user_email']); + // Sanitize Config Vars from get_settings.php and Session Vars from check_login.php + $config_mail_from_name = sanitizeInput($config_mail_from_name); + $config_mail_from_email = sanitizeInput($config_mail_from_email); + $config_app_name = sanitizeInput($config_app_name); + if (!empty($config_smtp_host) && ($user_old_email !== $email)) { $details = "Your email address was changed. New email: $email."; @@ -39,7 +44,7 @@ if (isset($_POST['edit_your_user_details'])) { 'subject' => $subject, 'body' => $body ] - ]; + ]; $mail = addToMailQueue($mysqli, $data); } @@ -102,12 +107,17 @@ if (isset($_POST['edit_your_user_password'])) { $name = sanitizeInput($user_sql['user_name']); $user_email = sanitizeInput($user_sql['user_email']); + // Sanitize Config Vars from get_settings.php and Session Vars from check_login.php + $config_mail_from_name = sanitizeInput($config_mail_from_name); + $config_mail_from_email = sanitizeInput($config_mail_from_email); + $config_app_name = sanitizeInput($config_app_name); + if (!empty($config_smtp_host)){ $details = "Your password was changed."; $subject = "$config_app_name account update confirmation for $name"; - $body = "Hi $name,

Your $config_app_name account has been updated, details below:

$details

If you did not perform this change, contact your $config_app_name administrator immediately.

Thanks,
ITFlow
$session_company_name"; + $body = "Hi $name,

Your $config_app_name account has been updated, details below:

$details

If you did not perform this change, contact your $config_app_name administrator immediately.

Thanks,
$config_app_name"; $data = [ [ @@ -210,6 +220,11 @@ if(isset($_POST['disable_2fa'])){ //Logging mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'User Settings', log_action = 'Modify', log_description = '$session_name disabled 2FA on their account', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); + // Sanitize Config Vars from get_settings.php and Session Vars from check_login.php + $config_mail_from_name = sanitizeInput($config_mail_from_name); + $config_mail_from_email = sanitizeInput($config_mail_from_email); + $config_app_name = sanitizeInput($config_app_name); + // Email notification if (!empty($config_smtp_host)) { $subject = "$config_app_name account update confirmation for $session_name"; diff --git a/post/quote.php b/post/quote.php index 89cc7459..158c2c83 100644 --- a/post/quote.php +++ b/post/quote.php @@ -8,7 +8,6 @@ if (isset($_POST['add_quote'])) { require_once 'post/quote_model.php'; - $client = intval($_POST['client']); //Get the last Quote Number and add 1 for the new Quote number @@ -356,51 +355,49 @@ if (isset($_GET['email_quote'])) { ); $row = mysqli_fetch_array($sql); - $quote_prefix = $row['quote_prefix']; + $quote_prefix = sanitizeInput($row['quote_prefix']); $quote_number = intval($row['quote_number']); - $quote_scope = $row['quote_scope']; - $quote_status = $row['quote_status']; - $quote_date = $row['quote_date']; - $quote_expire = $row['quote_expire']; + $quote_scope = sanitizeInput($row['quote_scope']); + $quote_status = sanitizeInput($row['quote_status']); + $quote_date = sanitizeInput($row['quote_date']); + $quote_expire = sanitizeInput($row['quote_expire']); $quote_amount = floatval($row['quote_amount']); - $quote_url_key = $row['quote_url_key']; - $quote_currency_code = $row['quote_currency_code']; + $quote_url_key = sanitizeInput($row['quote_url_key']); + $quote_currency_code = sanitizeInput($row['quote_currency_code']); $client_id = intval($row['client_id']); - $client_name = $row['client_name']; - $contact_name = $row['contact_name']; - $contact_email = $row['contact_email']; - $quote_prefix_escaped = sanitizeInput($row['quote_prefix']); - $contact_name_escaped = sanitizeInput($row['contact_name']); - $contact_email_escaped = sanitizeInput($row['contact_email']); + $client_name = sanitizeInput($row['client_name']); + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql); - $company_name = $row['company_name']; - $company_country = $row['company_country']; - $company_address = $row['company_address']; - $company_city = $row['company_city']; - $company_state = $row['company_state']; - $company_zip = $row['company_zip']; - $company_phone = formatPhoneNumber($row['company_phone']); - $company_email = $row['company_email']; - $company_website = $row['company_website']; - $company_logo = $row['company_logo']; + $company_name = sanitizeInput($row['company_name']); + $company_country = sanitizeInput($row['company_country']); + $company_address = sanitizeInput($row['company_address']); + $company_city = sanitizeInput($row['company_city']); + $company_state = sanitizeInput($row['company_state']); + $company_zip = sanitizeInput($row['company_zip']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); + $company_email = sanitizeInput($row['company_email']); + $company_website = sanitizeInput($row['company_website']); + $company_logo = sanitizeInput($row['company_logo']); // Sanitize Config vars from get_settings.php - $config_quote_from_name_escaped = sanitizeInput($config_quote_from_name); - $config_quote_from_email_escaped = sanitizeInput($config_quote_from_email); + $config_quote_from_name = sanitizeInput($config_quote_from_name); + $config_quote_from_email = sanitizeInput($config_quote_from_email); + $config_base_url = sanitizeInput($config_base_url); - $subject = sanitizeInput("Quote [$quote_scope]"); - $body = mysqli_escape_string($mysqli, "Hello $contact_name,

Thank you for your inquiry, we are pleased to provide you with the following estimate.


$quote_scope
Total Cost: " . numfmt_format_currency($currency_format, $quote_amount, $quote_currency_code) . "


View and accept your estimate online here


~
$company_name
Sales
$config_quote_from_email
$company_phone"); + $subject = "Quote [$quote_scope]"; + $body = "Hello $contact_name,

Thank you for your inquiry, we are pleased to provide you with the following estimate.


$quote_scope
Total Cost: " . numfmt_format_currency($currency_format, $quote_amount, $quote_currency_code) . "


View and accept your estimate online here


--
$company_name - Sales
$config_quote_from_email
$company_phone"; // Queue Mail $data = [ [ 'from' => $config_quote_from_email, 'from_name' => $config_quote_from_name, - 'recipient' => $contact_email_escaped, - 'recipient_name' => $contact_name_escaped, + 'recipient' => $contact_email, + 'recipient_name' => $contact_name, 'subject' => $subject, 'body' => $body, ] @@ -409,7 +406,7 @@ if (isset($_GET['email_quote'])) { // Logging mysqli_query($mysqli,"INSERT INTO history SET history_status = 'Sent', history_description = 'Emailed Quote!', history_quote_id = $quote_id"); - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Quote', log_action = 'Email', log_description = '$session_name emailed Quote $quote_prefix_escaped$quote_number to $contact_email_escaped Email ID: ', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $quote_id"); + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Quote', log_action = 'Email', log_description = '$session_name emailed Quote $quote_prefix$quote_number to $contact_email Email ID: ', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $quote_id"); $_SESSION['alert_message'] = "Quote has been sent"; diff --git a/post/quote_model.php b/post/quote_model.php index 061d685a..1243a155 100644 --- a/post/quote_model.php +++ b/post/quote_model.php @@ -4,3 +4,5 @@ $expire = sanitizeInput($_POST['expire']); $category = intval($_POST['category']); $scope = sanitizeInput($_POST['scope']); $quote_discount = floatval($_POST['quote_discount']); + +$config_quote_prefix = sanitizeInput($config_quote_prefix); From 0cdf49f69a4e3444219643e8ffabd879fc2fd77d Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 20:31:46 -0500 Subject: [PATCH 23/98] Update/Fix Mail Functions in POST/user.php and ajax.php - sanitize POST vars instead the whole mail subject and body which prevents having a mixed of confusing redundant escaped and unescaped vars --- ajax.php | 18 ++++++++++++++---- post/user.php | 18 +++++++++++++++--- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/ajax.php b/ajax.php index 7e7d18a4..78fb2ccb 100644 --- a/ajax.php +++ b/ajax.php @@ -303,14 +303,25 @@ if (isset($_GET['share_generate_link'])) { $url = "https://$config_base_url/guest_view_item.php?id=$share_id&key=$item_key"; } + $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $row = mysqli_fetch_array($sql); + $company_name = sanitizeInput($row['company_name']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); + + // Sanitize Config vars from get_settings.php + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $config_mail_from_name = sanitizeInput($config_mail_from_name); + $config_mail_from_email = sanitizeInput($config_mail_from_email); + // Send user e-mail, if specified if(!empty($config_smtp_host) && filter_var($item_email, FILTER_VALIDATE_EMAIL)){ - $subject = "Time sensitive - $session_company_name secure link enclosed"; + $subject = "Time sensitive - $company_name secure link enclosed"; if ($item_expires_friendly == "never") { - $subject = "$session_company_name secure link enclosed"; + $subject = "$company_name secure link enclosed"; } - $body = mysqli_real_escape_string($mysqli, "Hello,

$session_name from $session_company_name sent you a time sensitive secure link regarding '$item_name'.

The link will expire in $item_expires_friendly and may only be viewed $item_view_limit times, before the link is destroyed.

Click here to access your secure content

~
$session_company_name
Support Department
$config_ticket_from_email"); + $body = "Hello,

$session_name from $company_name sent you a time sensitive secure link regarding \"$item_name\".

The link will expire in $item_expires_friendly and may only be viewed $item_view_limit times, before the link is destroyed.

Click here to access your secure content

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $data = [ [ @@ -334,7 +345,6 @@ if (isset($_GET['share_generate_link'])) { echo json_encode($url); - // Logging mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Sharing', log_action = 'Create', log_description = '$session_name created shared link for $item_type - $item_name', log_client_id = $client_id, log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); diff --git a/post/user.php b/post/user.php index 9adc59df..60515059 100644 --- a/post/user.php +++ b/post/user.php @@ -8,7 +8,6 @@ if (isset($_POST['add_user'])) { require_once 'post/user_model.php'; - validateAdminRole(); validateCSRFToken($_POST['csrf_token']); @@ -47,11 +46,24 @@ if (isset($_POST['add_user'])) { // Create Settings mysqli_query($mysqli, "INSERT INTO user_settings SET user_id = $user_id, user_role = $role, user_config_force_mfa = $force_mfa"); + $sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1"); + $row = mysqli_fetch_array($sql); + $company_name = sanitizeInput($row['company_name']); + + // Sanitize Config vars from get_settings.php + $config_mail_from_name = sanitizeInput($config_mail_from_name); + $config_mail_from_email = sanitizeInput($config_mail_from_email); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $config_login_key_secret = mysqli_real_escape_string($mysqli, $config_login_key_secret); + $config_base_url = sanitizeInput($config_base_url); + // Send user e-mail, if specified if (isset($_POST['send_email']) && !empty($config_smtp_host) && filter_var($email, FILTER_VALIDATE_EMAIL)) { - $subject = "Your new $session_company_name ITFlow account"; - $body = "Hello, $name

An ITFlow account has been setup for you. Please change your password upon login.

Username: $email
Password: $_POST[password]
Login URL: https://$config_base_url/login.php?key=$config_login_key_secret

~
$session_company_name
Support Department
$config_ticket_from_email"; + $password = mysqli_real_escape_string($mysqli, $_POST['password']); + + $subject = "Your new $company_name ITFlow account"; + $body = "Hello $name,

An ITFlow account has been setup for you. Please change your password upon login.

Username: $email
Password: $password
Login URL: https://$config_base_url/login.php?key=$config_login_key_secret

--
$company_name - Support
$config_ticket_from_email"; $data = [ [ From 3c3e0f5f80a6c88f0a09e9c6e38444eb21d01cd2 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 20:49:37 -0500 Subject: [PATCH 24/98] Cleaned up guest_pay_invoice_stripe.php incorrect DB Handling for vars was HTML encoding instead of proper SQL escaping --- guest_pay_invoice_stripe.php | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index 8974b865..79306047 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -252,22 +252,22 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent // Invoice exists - get details $row = mysqli_fetch_array($invoice_sql); $invoice_id = intval($row['invoice_id']); - $invoice_prefix = nullable_htmlentities($row['invoice_prefix']); + $invoice_prefix = sanitizeInput(($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); $invoice_amount = floatval($row['invoice_amount']); - $invoice_currency_code = nullable_htmlentities($row['invoice_currency_code']); - $invoice_url_key = nullable_htmlentities($row['invoice_url_key']); + $invoice_currency_code = sanitizeInput($row['invoice_currency_code']); + $invoice_url_key = sanitizeInput($row['invoice_url_key']); $client_id = intval($row['client_id']); - $client_name = nullable_htmlentities($row['client_name']); - $contact_name = $row['contact_name']; - $contact_email = $row['contact_email']; + $client_name = sanitizeInput($row['client_name']); + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); $sql_company = mysqli_query($mysqli, "SELECT * FROM companies WHERE company_id = 1"); $row = mysqli_fetch_array($sql_company); - $company_name = mysqli_real_escape_string($mysqli, nullable_htmlentities($row['company_name'])); - $company_phone = nullable_htmlentities($row['company_phone']); - $company_locale = nullable_htmlentities($row['company_locale']); + $company_name = sanitizeInput($row['company_name']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); + $company_locale = sanitizeInput($row['company_locale']); $config_stripe_client_pays_fees = intval(getSettingValue($mysqli, 'config_stripe_client_pays_fees')); @@ -335,14 +335,13 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent $config_smtp_encryption = $row['config_smtp_encryption']; $config_smtp_username = $row['config_smtp_username']; $config_smtp_password = $row['config_smtp_password']; - $config_mail_from_email = $row['config_mail_from_email']; - $config_mail_from_name = $row['config_mail_from_name']; - $config_invoice_from_name = $row['config_invoice_from_name']; - $config_invoice_from_email = $row['config_invoice_from_email']; + $config_invoice_from_name = sanitizeInput($row['config_invoice_from_name']); + $config_invoice_from_email = sanitizeInput($row['config_invoice_from_email']); + $config_base_url = sanitizeInput($row['config_base_url']); if (!empty($config_smtp_host)) { $subject = "Payment Received - Invoice $invoice_prefix$invoice_number"; - $body = "Hello $contact_name,

We have received your payment in the amount of " . $pi_currency . $pi_amount_paid . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $pi_amount_paid, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, '0', $invoice_currency_code) . "

Thank you for your business!


~
$company_name
Billing Department
$config_invoice_from_email
$company_phone"; + $body = "Hello $contact_name,

We have received your payment in the amount of " . $pi_currency . $pi_amount_paid . " for invoice $invoice_prefix$invoice_number. Please keep this email as a receipt for your records.

Amount: " . numfmt_format_currency($currency_format, $pi_amount_paid, $invoice_currency_code) . "
Balance: " . numfmt_format_currency($currency_format, '0', $invoice_currency_code) . "

Thank you for your business!


~
$company_name - Billing
$config_invoice_from_email
$company_phone"; $data = [ [ From 00d4f7d66fb746dbac9a04ef1034ca2f44040cf6 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 20:54:56 -0500 Subject: [PATCH 25/98] moved config_stripe_client_pays_fees out of an unnessesary function and moved it to the setup stripe section --- guest_pay_invoice_stripe.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index 79306047..cc25f379 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -20,6 +20,7 @@ $config_stripe_enable = intval($stripe_vars['config_stripe_enable']); $config_stripe_publishable = nullable_htmlentities($stripe_vars['config_stripe_publishable']); $config_stripe_secret = nullable_htmlentities($stripe_vars['config_stripe_secret']); $config_stripe_account = intval($stripe_vars['config_stripe_account']); +$config_stripe_client_pays_fees = intval($stripe_vars['config_stripe_client_pays_fees']); // Check Stripe is configured if ($config_stripe_enable == 0 || $config_stripe_account == 0 || empty($config_stripe_publishable) || empty($config_stripe_secret)) { @@ -75,8 +76,6 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent $row = mysqli_fetch_array($sql); $company_locale = nullable_htmlentities($row['company_locale']); - $config_stripe_client_pays_fees = intval(getSettingValue($mysqli, 'config_stripe_client_pays_fees')); - // Add up all the payments for the invoice and get the total amount paid to the invoice $sql_amount_paid = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS amount_paid FROM payments WHERE payment_invoice_id = $invoice_id"); $row = mysqli_fetch_array($sql_amount_paid); From b1fd0fb4aa10337b460b319133965bd54a9fa68a Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 20:56:00 -0500 Subject: [PATCH 26/98] fixed --- guest_pay_invoice_stripe.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index cc25f379..a1694197 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -15,7 +15,7 @@ function log_to_console($message) DEFINE("WORDING_PAYMENT_FAILED", "

There was an error verifying your payment. Please contact us for more information.

"); // Setup Stripe -$stripe_vars = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_stripe_enable, config_stripe_publishable, config_stripe_secret, config_stripe_account FROM settings WHERE company_id = 1")); +$stripe_vars = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_stripe_enable, config_stripe_publishable, config_stripe_secret, config_stripe_account, config_stripe_client_pays_fees FROM settings WHERE company_id = 1")); $config_stripe_enable = intval($stripe_vars['config_stripe_enable']); $config_stripe_publishable = nullable_htmlentities($stripe_vars['config_stripe_publishable']); $config_stripe_secret = nullable_htmlentities($stripe_vars['config_stripe_secret']); From c801e58cc994d52316188ce637760c270f0bba78 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 20:58:53 -0500 Subject: [PATCH 27/98] Removed redundent get stripe client pays fee as the var is already aquired in beginning --- guest_pay_invoice_stripe.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index a1694197..85f579fd 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -268,9 +268,6 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); $company_locale = sanitizeInput($row['company_locale']); - $config_stripe_client_pays_fees = intval(getSettingValue($mysqli, 'config_stripe_client_pays_fees')); - - // Set Currency Formatting $currency_format = numfmt_create($company_locale, NumberFormatter::CURRENCY); From d390bee0bc60822a184ac2b314305ab7dcde07f8 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 21:16:28 -0500 Subject: [PATCH 28/98] Update/Fix Mail Functions in cron.php - sanitize POST vars instead the whole mail subject and body which prevents having a mixed of confusing redundant escaped and unescaped vars --- cron.php | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/cron.php b/cron.php index 2a032d66..b08c3688 100644 --- a/cron.php +++ b/cron.php @@ -14,7 +14,7 @@ $row = mysqli_fetch_array($sql_companies); // Company Details $company_name = sanitizeInput($row['company_name']); -$company_phone = formatPhoneNumber($row['company_phone']); +$company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); $company_email = sanitizeInput($row['company_email']); $company_website = sanitizeInput($row['company_website']); $company_city = sanitizeInput($row['company_city']); @@ -39,8 +39,8 @@ $config_smtp_username = $row['config_smtp_username']; $config_smtp_password = $row['config_smtp_password']; $config_smtp_port = intval($row['config_smtp_port']); $config_smtp_encryption = $row['config_smtp_encryption']; -$config_mail_from_email = $row['config_mail_from_email']; -$config_mail_from_name = $row['config_mail_from_name']; +$config_mail_from_email = sanitizeInput($row['config_mail_from_email']); +$config_mail_from_name = sanitizeInput($row['config_mail_from_name']); $config_recurring_auto_send_invoice = intval($row['config_recurring_auto_send_invoice']); // Tickets @@ -280,25 +280,22 @@ if (mysqli_num_rows($sql_scheduled_tickets) > 0) { $contact_name = sanitizeInput($row['contact_name']); $contact_email = sanitizeInput($row['contact_email']); - $client_name = sanitizeInput($row['client_name']); $contact_name = sanitizeInput($row['contact_name']); $contact_email = sanitizeInput($row['contact_email']); $ticket_prefix = sanitizeInput($row['ticket_prefix']); $ticket_number = intval($row['ticket_number']); $ticket_priority = sanitizeInput($row['ticket_priority']); - - // Not Sanitized Vars because they are already sanitized in subject and body wrapper - $ticket_subject = $row['ticket_subject']; - $ticket_details = $row['ticket_details']; // Output on settings_mail_queue.php is sanitized through HTML Purifier + $ticket_subject = mysqli_real_escape_string($mysqli, $row['ticket_subject']); + $ticket_details = mysqli_real_escape_string($mysqli, $row['ticket_details']); $data = []; // Notify client by email their ticket has been raised, if general notifications are turned on & there is a valid contact email if (!empty($config_smtp_host) && $config_ticket_client_general_notifications == 1 && filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { - $email_subject = mysqli_real_escape_string($mysqli, "Ticket created - [$ticket_prefix$ticket_number] - $ticket_subject (scheduled)"); - $email_body = mysqli_real_escape_string($mysqli, "##- Please type your reply above this line -##

Hello, $contact_name

A ticket regarding \"$ticket_subject\" has been automatically created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$id

~
$company_name
Support Department
$config_ticket_from_email
$company_phone"); + $email_subject = "Ticket created - [$ticket_prefix$ticket_number] - $ticket_subject (scheduled)"; + $email_body = "##- Please type your reply above this line -##

Hello $contact_name,

A ticket regarding \"$ticket_subject\" has been automatically created for you.

--------------------------------
$ticket_details--------------------------------

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: Open
Portal: https://$config_base_url/portal/ticket.php?id=$id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $email = [ 'from' => $config_ticket_from_email, @@ -316,8 +313,8 @@ if (mysqli_num_rows($sql_scheduled_tickets) > 0) { // Notify agent's via the DL address of the new ticket, if it's populated with a valid email if (filter_var($config_ticket_new_ticket_notification_email, FILTER_VALIDATE_EMAIL)) { - $email_subject = mysqli_real_escape_string($mysqli, "ITFlow - New Scheduled Ticket - $client_name: $ticket_subject"); - $email_body = mysqli_real_escape_string($mysqli, "Hello,

This is a notification that a new scheduled ticket has been raised in ITFlow.
Ticket: $ticket_prefix$ticket_number
Client: $client_name
Priority: $priority
Link: https://$config_base_url/ticket.php?ticket_id=$id

--------------------------------

$ticket_subject
$ticket_details"); + $email_subject = "ITFlow - New Scheduled Ticket - $client_name: $ticket_subject"; + $email_body = "Hello,

This is a notification that a new scheduled ticket has been raised in ITFlow.
Ticket: $ticket_prefix$ticket_number
Client: $client_name
Priority: $priority
Link: https://$config_base_url/ticket.php?ticket_id=$id

--------------------------------

$ticket_subject
$ticket_details"; $email = [ 'from' => $config_ticket_from_email, @@ -420,8 +417,8 @@ if ($config_ticket_autoclose == 1) { $ticket_reply_row = mysqli_fetch_array($sql_ticket_reply); $ticket_reply = $ticket_reply_row['ticket_reply']; - $subject = mysqli_real_escape_string($mysqli, "Ticket pending closure - [$ticket_prefix$ticket_number] - $ticket_subject"); - $body = mysqli_real_escape_string($mysqli, "##- Please type your reply above this line -##

Hello, $contact_name

This is an automatic friendly reminder that your ticket regarding $ticket_subject will be closed, unless you respond.

--------------------------------
$ticket_reply--------------------------------

If your issue is resolved, you can ignore this email - the ticket will automatically close. If you need further assistance, please respond to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

~
$company_name
Support Department
$config_ticket_from_email
$company_phone"); + $subject = "Ticket pending closure - [$ticket_prefix$ticket_number] - $ticket_subject"; + $body = "##- Please type your reply above this line -##

Hello, $contact_name

This is an automatic friendly reminder that your ticket regarding $ticket_subject will be closed, unless you respond.

--------------------------------
$ticket_reply--------------------------------

If your issue is resolved, you can ignore this email - the ticket will automatically close. If you need further assistance, please respond to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Status: $ticket_status
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $data = [ [ @@ -501,10 +498,10 @@ if ($config_send_invoice_reminders == 1) { mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Invoice Overdue', notification = 'Invoice $invoice_prefix$invoice_number for $client_name in the amount of $invoice_amount is overdue by $day days', notification_action = 'invoice.php?invoice_id=$invoice_id', notification_client_id = $client_id, notification_entity_id = $invoice_id"); - $subject = mysqli_real_escape_string($mysqli, "Overdue Invoice $invoice_prefix$invoice_number"); - $body = mysqli_real_escape_string($mysqli, "Hello $contact_name,

Our records indicate that we have not yet received payment for the invoice $invoice_prefix$invoice_number. We kindly request that you submit your payment as soon as possible. If you have any questions or concerns, please do not hesitate to contact us at $company_phone. + $subject = "Overdue Invoice $invoice_prefix$invoice_number"; + $body = "Hello $contact_name,

Our records indicate that we have not yet received payment for the invoice $invoice_prefix$invoice_number. We kindly request that you submit your payment as soon as possible. If you have any questions or concerns, please do not hesitate to contact us at $company_phone.

- Kindly review the invoice details mentioned below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . "
Due Date: $invoice_due


To view your invoice click here


~
$company_name
Billing Department
$config_invoice_from_email
$company_phone"); + Kindly review the invoice details mentioned below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . "
Due Date: $invoice_due


To view your invoice click here


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; $mail = addToMailQueue($mysqli, [ [ @@ -619,8 +616,8 @@ while ($row = mysqli_fetch_array($sql_recurring)) { $contact_name = sanitizeInput($row['contact_name']); $contact_email = sanitizeInput($row['contact_email']); - $subject = mysqli_real_escape_string($mysqli, "Invoice $invoice_prefix$invoice_number"); - $body = mysqli_real_escape_string($mysqli, "Hello $contact_name,

Kindly review the invoice details mentioned below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $recurring_currency_code) . "
Due Date: $invoice_due


To view your invoice click here


~
$company_name
Billing Department
$config_invoice_from_email
$company_phone"); + $subject = "Invoice $invoice_prefix$invoice_number"; + $body = "Hello $contact_name,

Kindly review the invoice details mentioned below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $recurring_currency_code) . "
Due Date: $invoice_due


To view your invoice click here


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; $mail = addToMailQueue($mysqli, [ [ @@ -966,8 +963,6 @@ if ($config_telemetry > 0 OR $config_telemetry = 2) { mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Cron', log_action = 'Telemetry', log_description = 'Cron sent telemetry results to ITFlow Developers'"); } - - /* * ############################################################################################################### * FINISH UP From 493c83e3f14dbb1c38f404856ea4d78ea2529acb Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 21:44:58 -0500 Subject: [PATCH 29/98] Added Days over due by to invoice reminders --- cron.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cron.php b/cron.php index b08c3688..cef7eba6 100644 --- a/cron.php +++ b/cron.php @@ -286,7 +286,7 @@ if (mysqli_num_rows($sql_scheduled_tickets) > 0) { $ticket_prefix = sanitizeInput($row['ticket_prefix']); $ticket_number = intval($row['ticket_number']); $ticket_priority = sanitizeInput($row['ticket_priority']); - $ticket_subject = mysqli_real_escape_string($mysqli, $row['ticket_subject']); + $ticket_subject = sanitizeInput($row['ticket_subject']); $ticket_details = mysqli_real_escape_string($mysqli, $row['ticket_details']); $data = []; @@ -501,7 +501,7 @@ if ($config_send_invoice_reminders == 1) { $subject = "Overdue Invoice $invoice_prefix$invoice_number"; $body = "Hello $contact_name,

Our records indicate that we have not yet received payment for the invoice $invoice_prefix$invoice_number. We kindly request that you submit your payment as soon as possible. If you have any questions or concerns, please do not hesitate to contact us at $company_phone.

- Kindly review the invoice details mentioned below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . "
Due Date: $invoice_due


To view your invoice click here


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; + Kindly review the invoice details mentioned below.

Invoice: $invoice_prefix$invoice_number
Issue Date: $invoice_date
Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . "
Due Date: $invoice_due
Over Due By: $day Days


To view your invoice click here


--
$company_name - Billing
$config_invoice_from_email
$company_phone"; $mail = addToMailQueue($mysqli, [ [ From 3b71e6132efac7e588e4b0f4b4df5a0c7448008f Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 22:08:41 -0500 Subject: [PATCH 30/98] Change Respond icon from check mark to a paper plane in ticket view --- ticket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ticket.php b/ticket.php index 431ed96e..52cdc865 100644 --- a/ticket.php +++ b/ticket.php @@ -376,7 +376,7 @@ if (isset($_GET['ticket_id'])) {
- +
From 623ed33a27c391a0fbdadfcaf5a10ccf080b2441 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 23:11:35 -0500 Subject: [PATCH 31/98] Update Portal UI elements and Mail Functions --- portal/document.php | 24 ------ portal/documents.php | 86 ++++++++-------------- portal/index.php | 30 +------- portal/invoices.php | 155 +++++++++++++++++---------------------- portal/portal_header.php | 30 ++++++-- portal/portal_post.php | 19 ++--- portal/profile.php | 2 +- portal/quotes.php | 138 ++++++++++++++-------------------- portal/tickets.php | 23 ------ 9 files changed, 191 insertions(+), 316 deletions(-) diff --git a/portal/document.php b/portal/document.php index 5c031538..d007e9de 100644 --- a/portal/document.php +++ b/portal/document.php @@ -8,7 +8,6 @@ header("Content-Security-Policy: default-src 'self' fonts.googleapis.com fonts.g require_once "inc_portal.php"; - if ($session_contact_primary == 0 && !$session_contact_is_technical_contact) { header("Location: portal_post.php?logout"); exit(); @@ -21,7 +20,6 @@ $purifier_config = HTMLPurifier_Config::createDefault(); $purifier_config->set('URI.AllowedSchemes', ['data' => true, 'src' => true, 'http' => true, 'https' => true]); $purifier = new HTMLPurifier($purifier_config); - // Check for a document ID if (!isset($_GET['id']) && !intval($_GET['id'])) { header("Location: documents.php"); @@ -39,27 +37,6 @@ $document_content = $purifier->purify($row['document_content']); ?> -
-
- - " alt="..." height="50" width="50" class="img-circle img-responsive"> - - - - - - -
- -
-

Welcome, !

-
-
- -
- -
-

@@ -72,4 +49,3 @@ $document_content = $purifier->purify($row['document_content']); -
-
- - " alt="..." height="50" width="50" class="img-circle img-responsive"> - - - - - - -
+
-
-

Welcome, !

-
-
+
-
+ + + + + + + + -
+ + ?> -
- -
NameCreated
- - - + + - - + - - - - - - - - - -
NameCreated + + +
- - -
- -
+ +
+
- -
-
- - " alt="..." height="50" width="50" class="img-circle img-responsive"> - - - - - - - - -
- -
-

Welcome, !

-
-
-
- - - + - + diff --git a/portal/invoices.php b/portal/invoices.php index ae319c95..028611d5 100644 --- a/portal/invoices.php +++ b/portal/invoices.php @@ -17,106 +17,85 @@ if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) { $invoices_sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $session_client_id AND invoice_status != 'Draft' ORDER BY invoice_date DESC"); ?> -
-
- - " alt="..." height="50" width="50" class="img-circle img-responsive"> - - - - - - -
+
-
-

Welcome, !

-
-
+
-
+ + + + + + + + + + + + -
+ + if (empty($invoice_scope)) { + $invoice_scope_display = "-"; + } else { + $invoice_scope_display = $invoice_scope; + } -
+ $now = time(); + if (($invoice_status == "Sent" || $invoice_status == "Partial" || $invoice_status == "Viewed") && strtotime($invoice_due) + 86400 < $now) { + $overdue_color = "text-danger font-weight-bold"; + } else { + $overdue_color = ""; + } + + if ($invoice_status == "Sent") { + $invoice_badge_color = "warning text-white"; + } elseif ($invoice_status == "Viewed") { + $invoice_badge_color = "info"; + } elseif ($invoice_status == "Partial") { + $invoice_badge_color = "primary"; + } elseif ($invoice_status == "Paid") { + $invoice_badge_color = "success"; + } elseif ($invoice_status == "Cancelled") { + $invoice_badge_color = "danger"; + } else{ + $invoice_badge_color = "secondary"; + } + ?> -
#ScopeAmountDateDueStatus
- - - - - - - + + + + + + + - - + - - - - - - - - - - - - - - -
#ScopeAmountDateDueStatus"> + + + +
"> - - - -
- -
+ +
+
+
- @@ -64,12 +64,12 @@ header("X-Frame-Options: DENY"); // Legacy @@ -81,3 +81,23 @@ header("X-Frame-Options: DENY"); // Legacy
+ +
+
+ + " alt="..." height="50" width="50" class="img-circle img-responsive"> + + + + + + + + +
+ +
+

Welcome, !

+
+
+
diff --git a/portal/portal_post.php b/portal/portal_post.php index e7169ed9..67e26e4d 100644 --- a/portal/portal_post.php +++ b/portal/portal_post.php @@ -9,23 +9,18 @@ require_once "inc_portal.php"; if (isset($_POST['add_ticket'])) { - // Get ticket prefix/number - $sql_settings = mysqli_query($mysqli, "SELECT * FROM settings WHERE company_id = 1"); - $row = mysqli_fetch_array($sql_settings); - $config_ticket_prefix = sanitizeInput($row['config_ticket_prefix']); - $config_ticket_next_number = intval($row['config_ticket_next_number']); - - // Get email settings - $config_ticket_from_name = $row['config_ticket_from_name']; - $config_ticket_from_email = $row['config_ticket_from_email']; - $config_ticket_new_ticket_notification_email = filter_var($row['config_ticket_new_ticket_notification_email'], FILTER_VALIDATE_EMAIL); - - $client_id = intval($session_client_id); $contact = intval($session_contact_id); $subject = sanitizeInput($_POST['subject']); $details = mysqli_real_escape_string($mysqli,($_POST['details'])); + // Get settings from get_settings.php + $config_ticket_prefix = sanitizeInput($config_ticket_prefix); + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $config_base_url = sanitizeInput($config_base_url); + $config_ticket_new_ticket_notification_email = filter_var($row['config_ticket_new_ticket_notification_email'], FILTER_VALIDATE_EMAIL); + // Ensure priority is low/med/high (as can be user defined) if ($_POST['priority'] !== "Low" && $_POST['priority'] !== "Medium" && $_POST['priority'] !== "High") { $priority = "Low"; diff --git a/portal/profile.php b/portal/profile.php index c3493d1c..e77afeaa 100644 --- a/portal/profile.php +++ b/portal/profile.php @@ -12,7 +12,7 @@ require_once 'inc_portal.php';

Profile

-

Name:

+

Name:

Email:

PIN:

Client:

diff --git a/portal/quotes.php b/portal/quotes.php index 948214df..dfb3ce52 100644 --- a/portal/quotes.php +++ b/portal/quotes.php @@ -8,7 +8,6 @@ header("Content-Security-Policy: default-src 'self' fonts.googleapis.com fonts.g require_once "inc_portal.php"; - if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) { header("Location: portal_post.php?logout"); exit(); @@ -17,98 +16,75 @@ if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) { $quotes_sql = mysqli_query($mysqli, "SELECT * FROM quotes WHERE quote_client_id = $session_client_id AND quote_status != 'Draft' ORDER BY quote_date DESC"); ?> -
-
- - " alt="..." height="50" width="50" class="img-circle img-responsive"> - - - - - - -
+
-
-

Welcome, !

-
-
+
-
+ + + + + + + + + + + -
+ + if (empty($quote_scope)) { + $quote_scope_display = "-"; + } else { + $quote_scope_display = $quote_scope; + } -
+ if ($quote_status == "Sent") { + $quote_badge_color = "warning text-white"; + } elseif ($quote_status == "Viewed") { + $quote_badge_color = "primary"; + } elseif ($quote_status == "Accepted") { + $quote_badge_color = "success"; + } elseif ($quote_status == "Declined") { + $quote_badge_color = "danger"; + } elseif ($quote_status == "Invoiced") { + $quote_badge_color = "info"; + } else { + $quote_badge_color = "secondary"; + } + + ?> -
#ScopeAmountDateStatus
- - - - - - + + + + + + - - + - - - - - - - - - - - - - -
#ScopeAmountDateStatus"> + + + +
"> - - - -
- -
+ +
+
-
-
- - " alt="..." height="50" width="50" class="img-circle img-responsive"> - - - - - - - - -
- -
-

Welcome, !

-
-
- -
- -
-
From bd8c93cb716f342a01b295a663a7b2c57d6ea3f2 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 20 Jan 2024 23:28:00 -0500 Subject: [PATCH 32/98] Update client portal login reset for the new mail function and made some minor UI / Code changes --- portal/login_reset.php | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/portal/login_reset.php b/portal/login_reset.php index 702c83dd..a6201ff9 100644 --- a/portal/login_reset.php +++ b/portal/login_reset.php @@ -38,9 +38,19 @@ if (!isset($_SESSION)) { $ip = sanitizeInput(getIP()); $user_agent = sanitizeInput($_SERVER['HTTP_USER_AGENT']); +// Get Company Info $company_sql = mysqli_query($mysqli, "SELECT company_name FROM companies WHERE company_id = 1"); $company_results = mysqli_fetch_array($company_sql); -$company_name = $company_results['company_name']; +$company_name = sanitizeInput($company_results['company_name']); +$company_phone = sanitizeInput(formatPhoneNumber($company_results['company_phone'])); +$company_name_display = $company_results['company_name']; + +// Get settings from get_settings.php and sanitize them +$config_ticket_from_name = sanitizeInput($config_ticket_from_name); +$config_ticket_from_email = sanitizeInput($config_ticket_from_email); +$config_mail_from_name = sanitizeInput($config_mail_from_name); +$config_mail_from_email = sanitizeInput($config_mail_from_email); +$config_base_url = sanitizeInput($config_base_url); DEFINE("WORDING_ERROR", "Something went wrong! Your link may have expired. Please request a new password reset e-mail."); @@ -68,8 +78,8 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") { // Send reset email - $subject = mysqli_real_escape_string($mysqli, "Password reset for $company_name ITFlow Portal"); - $body = mysqli_real_escape_string($mysqli, "Hello, $name

Someone (probably you) has requested a new password for your account on $company_name's ITFlow Client Portal.

Please click here to reset your password.

Alternatively, copy and paste this URL into your browser:
$url

If you didn't request this change, you can safely ignore this email.

~
$company_name
Support Department
$config_mail_from_email"); + $subject = "Password reset for $company_name Client Portal"; + $body = "Hello $name,

Someone (probably you) has requested a new password for your account on $company_name\'s Client Portal.

Please click here to reset your password.

Alternatively, copy and paste this URL into your browser:
$url

If you didn't request this change, you can safely ignore this email.

--
$company_name - Support
$config_ticket_from_email
$company_phone"; $data = [ [ @@ -124,8 +134,8 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") { mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Contact', log_action = 'Modify', log_description = 'Reset portal password for $email.', log_ip = '$ip', log_user_agent = '$user_agent', log_client_id = $client"); // Send confirmation email - $subject = mysqli_real_escape_string($mysqli, "Password reset confirmation for $company_name ITFlow Portal"); - $body = mysqli_real_escape_string($mysqli, "Hello, $name

Your password for your account on $company_name's ITFlow Client Portal was successfully reset. You should be all set!

If you didn't reset your password, please get in touch ASAP.

~
$company_name
Support Department
$config_mail_from_email"); + $subject = "Password reset confirmation for $company_name Client Portal"; + $body = "Hello $name,

Your password for your account on $company_name\'s Client Portal was successfully reset. You should be all set!

If you didn\'t reset your password, please get in touch ASAP.

~
$company_name - Support
$config_ticket_from_email
$company_phone"; $data = [ @@ -158,16 +168,16 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") { } - } ?> + - <?php echo $company_name; ?> | Password Reset + <?php echo nullable_htmlentities($company_name_display); ?> | Password Reset @@ -185,7 +195,7 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") { From 62fb73875b33a6be46eec251897e371452e4cf80 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 21 Jan 2024 15:27:15 -0500 Subject: [PATCH 40/98] Updated addToMailQueue Function to allow specifing an optional queue time to schedule outbound mail --- functions.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/functions.php b/functions.php index 9ae2a62d..39ac0347 100644 --- a/functions.php +++ b/functions.php @@ -937,7 +937,15 @@ function addToMailQueue($mysqli, $data) { $subject = strval($email['subject']); $body = strval($email['body']); - mysqli_query($mysqli, "INSERT INTO email_queue SET email_recipient = '$recipient', email_recipient_name = '$recipient_name', email_from = '$from', email_from_name = '$from_name', email_subject = '$subject', email_content = '$body'"); + // Check if 'email_queued_at' is set and not empty + if (isset($email['email_queued_at']) && !empty($email['email_queued_at'])) { + $queued_at = $email['email_queued_at']; + } else { + // Use the current date and time if 'email_queued_at' is not set or empty + $queued_at = date('Y-m-d H:i:s'); + } + + mysqli_query($mysqli, "INSERT INTO email_queue SET email_recipient = '$recipient', email_recipient_name = '$recipient_name', email_from = '$from', email_from_name = '$from_name', email_subject = '$subject', email_content = '$body', email_queued_at = '$queued_at'"); } return true; From ad1ec7d3384feb5e1a070993da86f8cf1e4f2b8a Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 21 Jan 2024 15:52:15 -0500 Subject: [PATCH 41/98] Allow to set an optional queue time in bulk mail, update cron_mail_queue.php to only send mail after its queued_at date and time --- client_bulk_mail.php | 9 +++++++++ cron_mail_queue.php | 2 +- functions.php | 4 ++-- post/bulk_mail.php | 4 +++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/client_bulk_mail.php b/client_bulk_mail.php index dfcb2f49..c7f43fb8 100644 --- a/client_bulk_mail.php +++ b/client_bulk_mail.php @@ -48,6 +48,15 @@ $sql = mysqli_query($mysqli, "SELECT * FROM contacts
+
+
+
+ +
+ +
+
+
diff --git a/cron_mail_queue.php b/cron_mail_queue.php index 5f9933cf..0827c092 100644 --- a/cron_mail_queue.php +++ b/cron_mail_queue.php @@ -61,7 +61,7 @@ file_put_contents($lock_file_path, "Locked"); // Get Mail Queue that has status of Queued and send it to the function sendSingleEmail() located in functions.php -$sql_queue = mysqli_query($mysqli, "SELECT * FROM email_queue WHERE email_status = 0"); +$sql_queue = mysqli_query($mysqli, "SELECT * FROM email_queue WHERE email_status = 0 AND email_queued_at <= NOW()"); if (mysqli_num_rows($sql_queue) > 0) { while ($row = mysqli_fetch_array($sql_queue)) { diff --git a/functions.php b/functions.php index 39ac0347..9fa0fb5a 100644 --- a/functions.php +++ b/functions.php @@ -938,8 +938,8 @@ function addToMailQueue($mysqli, $data) { $body = strval($email['body']); // Check if 'email_queued_at' is set and not empty - if (isset($email['email_queued_at']) && !empty($email['email_queued_at'])) { - $queued_at = $email['email_queued_at']; + if (isset($email['queued_at']) && !empty($email['queued_at'])) { + $queued_at = $email['queued_at']; } else { // Use the current date and time if 'email_queued_at' is not set or empty $queued_at = date('Y-m-d H:i:s'); diff --git a/post/bulk_mail.php b/post/bulk_mail.php index 3a2eb32d..e0986a5f 100644 --- a/post/bulk_mail.php +++ b/post/bulk_mail.php @@ -12,6 +12,7 @@ if (isset($_POST['send_bulk_mail_now'])) { $mail_from_name = sanitizeInput($_POST['mail_from_name']); $subject = sanitizeInput($_POST['subject']); $body = mysqli_escape_string($mysqli, $_POST['body']); + $queued_at = sanitizeInput($_POST['queued_at']); // Add Emails foreach($_POST['contact'] as $contact_id) { @@ -30,7 +31,8 @@ if (isset($_POST['send_bulk_mail_now'])) { 'recipient' => $contact_email, 'recipient_name' => $contact_name, 'subject' => $subject, - 'body' => $body + 'body' => $body, + 'queued_at' => $queued_at ]; } addToMailQueue($mysqli, $data); From 8d2a9bbf60e90ac09ba7f8fc15bc2b12bd330284 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Mon, 22 Jan 2024 12:17:06 -0500 Subject: [PATCH 42/98] Fix Broke Guest Pay Invoice via Stripe removed additional ) --- guest_pay_invoice_stripe.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index 85f579fd..1f215574 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -251,7 +251,7 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent // Invoice exists - get details $row = mysqli_fetch_array($invoice_sql); $invoice_id = intval($row['invoice_id']); - $invoice_prefix = sanitizeInput(($row['invoice_prefix']); + $invoice_prefix = sanitizeInput($row['invoice_prefix']); $invoice_number = intval($row['invoice_number']); $invoice_amount = floatval($row['invoice_amount']); $invoice_currency_code = sanitizeInput($row['invoice_currency_code']); From 9e8c3ed2fdccc9216d0ee3d7e0c005e7d429f98a Mon Sep 17 00:00:00 2001 From: johnnyq Date: Mon, 22 Jan 2024 12:27:47 -0500 Subject: [PATCH 43/98] Fix Redirect Link in Stripe Pay --- guest_pay_invoice_stripe.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index 1f215574..7793dd02 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -333,7 +333,8 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent $config_smtp_password = $row['config_smtp_password']; $config_invoice_from_name = sanitizeInput($row['config_invoice_from_name']); $config_invoice_from_email = sanitizeInput($row['config_invoice_from_email']); - $config_base_url = sanitizeInput($row['config_base_url']); + + $config_base_url = sanitizeInput($config_base_url); if (!empty($config_smtp_host)) { $subject = "Payment Received - Invoice $invoice_prefix$invoice_number"; From 4e0c7230f3ac17190614b5ff031aa2e93776c99f Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Mon, 22 Jan 2024 20:47:21 +0000 Subject: [PATCH 44/98] Update README.md Reword read me contribution section to emphasize proposing features on forum first --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 64e1487d..888d2d76 100644 --- a/README.md +++ b/README.md @@ -136,8 +136,7 @@ For help using ITFlow, feature requests, and general ideas / discussions please For bugs, please raise an [issue](https://github.com/itflow-org/itflow/issues). ### Contributing -If you are able to make a contribution that would make ITFlow better, please fork the repo and create a pull request. Please make sure you're following our [code standards](https://docs.itflow.org/code_standards). -For large changes / new features, please discuss the issue with other contributors first. +If you want to improve ITFlow, feel free to fork the repo and create a pull request, but make sure to discuss significant changes or new features with fellow contributors on the forum first. This helps ensure that your contributions are aligned with project goals, and saves time for everyone. All contributions should follow our [code standards](https://docs.itflow.org/code_standards). #### Contributors From ba0917e142aaefda86bc6b16b92c316748b8ce3e Mon Sep 17 00:00:00 2001 From: Marcus Hill Date: Mon, 22 Jan 2024 21:25:21 +0000 Subject: [PATCH 45/98] Logins JS Cleanup - Remove old JS - Standardize generate password JS style to match existing - Move JS functions to own files --- ajax.php | 4 +-- client_logins.php | 60 +++------------------------------- js/logins_generate_password.js | 14 ++++++++ js/logins_show_otp_via_id.js | 16 +++++++++ 4 files changed, 36 insertions(+), 58 deletions(-) create mode 100644 js/logins_generate_password.js create mode 100644 js/logins_show_otp_via_id.js diff --git a/ajax.php b/ajax.php index 78fb2ccb..ddf5639a 100644 --- a/ajax.php +++ b/ajax.php @@ -333,7 +333,7 @@ if (isset($_GET['share_generate_link'])) { 'body' => $body ] ]; - + $mail = addToMailQueue($mysqli, $data); if ($mail !== true) { @@ -499,5 +499,5 @@ if (isset($_GET['get_totp_token_via_id'])) { } if (isset($_GET['get_readable_pass'])) { - echo GenerateReadablePassword(4); + echo json_encode(GenerateReadablePassword(4)); } diff --git a/client_logins.php b/client_logins.php index 874f80f5..55f197e6 100644 --- a/client_logins.php +++ b/client_logins.php @@ -177,63 +177,11 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
- - document.getElementById("otp_" + id).innerText = token - - } - ); - } - - function showOTPViaLoginID(login_id) { - // Send a GET request to ajax.php as ajax.php?get_totp_token_via_id=true&login_id=ID - jQuery.get( - "ajax.php", { - get_totp_token_via_id: 'true', - login_id: login_id - }, - function(data) { - //If we get a response from post.php, parse it as JSON - const token = JSON.parse(data); - - document.getElementById("otp_" + login_id).innerText = token - - } - ); - } - - function generatePassword() { - document.getElementById("password").value = "" - } - - function generatePassword() { - var url = '/ajax.php?get_readable_pass=true'; - - // Make an AJAX request to the server - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - - xhr.onreadystatechange = function() { - if (xhr.readyState == 4 && xhr.status == 200) { - var password = xhr.responseText; - - document.getElementById("password").value = password; - } - }; - xhr.send(); - } - + + Date: Tue, 23 Jan 2024 16:44:30 -0500 Subject: [PATCH 46/98] UI Update for Asset Listing, combined columns to allow for a better display --- client_assets.php | 16 +++++++++++----- client_contact_details.php | 37 +++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/client_assets.php b/client_assets.php index 3572c8b1..a710ff78 100644 --- a/client_assets.php +++ b/client_assets.php @@ -149,13 +149,12 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); "> - - + - + @@ -305,14 +304,21 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); +
+ +
- - + diff --git a/client_contact_details.php b/client_contact_details.php index 863b94d8..6eeaffd6 100644 --- a/client_contact_details.php +++ b/client_contact_details.php @@ -84,33 +84,33 @@ if (isset($_GET['contact_id'])) {
-
+
-
+
- + -
+
-
+
-
Primary Contact
+
Primary Contact
-
Important
+
Important
-
Technical
+
Technical
-
Billing
+
Billing
-
+
@@ -149,12 +149,10 @@ if (isset($_GET['contact_id'])) {
NameDescriptionName / Description Type Make/ModelMake / Model Serial Number + +
+ +
+
- - + - @@ -216,12 +214,19 @@ if (isset($_GET['contact_id'])) { - - + - +
NameDescriptionName/Description Type Make/Model Serial NumberOperating System Install Date Status Action +
+ +
+ +
+ +
+
From 07c126db2b779578da0aae65e978237cadba5199 Mon Sep 17 00:00:00 2001 From: Brady Williams <39432793+braadaaay@users.noreply.github.com> Date: Wed, 24 Jan 2024 17:57:05 +1300 Subject: [PATCH 47/98] Fix Spelling from "wather" to "watcher" --- ticket_add_watcher_modal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ticket_add_watcher_modal.php b/ticket_add_watcher_modal.php index c0450042..f29c06f9 100644 --- a/ticket_add_watcher_modal.php +++ b/ticket_add_watcher_modal.php @@ -14,7 +14,7 @@ \ No newline at end of file + From 9ce280d80da1647efeceec363f51cdf03171aea0 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 24 Jan 2024 15:46:30 -0500 Subject: [PATCH 49/98] Fix Redirect to non-existent page after login when force MFA is enabled --- login.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/login.php b/login.php index dd1e2c25..1a38b930 100644 --- a/login.php +++ b/login.php @@ -113,7 +113,7 @@ if (isset($_POST['login'])) { $force_mfa = intval($row['user_config_force_mfa']); $remember_token = $row['user_config_remember_me_token']; if($force_mfa == 1 && $token == NULL) { - $config_start_page = "user_profile.php"; + $config_start_page = "user_security.php"; } $bypass_2fa = false; From 937397e9c0bceec9c5dc912afe7829b9c8e1b58c Mon Sep 17 00:00:00 2001 From: johnnyq Date: Thu, 25 Jan 2024 12:01:09 -0500 Subject: [PATCH 50/98] Allow .vsdx and .drawio diagram files to be uploaded via client files --- client_file_upload_modal.php | 2 +- post/file.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client_file_upload_modal.php b/client_file_upload_modal.php index 36e70113..2a174023 100644 --- a/client_file_upload_modal.php +++ b/client_file_upload_modal.php @@ -35,7 +35,7 @@
- +
Up to 20 files can be uploaded at once by holding down CTRL and selecting files diff --git a/post/file.php b/post/file.php index 0e3b62a2..1f702c19 100644 --- a/post/file.php +++ b/post/file.php @@ -22,7 +22,7 @@ if (isset($_POST['upload_files'])) { 'size' => $_FILES['file']['size'][$i] ]; - if ($file_reference_name = checkFileUpload($single_file, array('jpg', 'jpeg', 'gif', 'png', 'webp', 'pdf', 'txt', 'md', 'doc', 'docx', 'odt', 'csv', 'xls', 'xlsx', 'ods', 'pptx', 'odp', 'zip', 'tar', 'gz', 'xml', 'msg', 'json', 'wav', 'mp3', 'ogg', 'mov', 'mp4', 'av1', 'ovpn', 'cfg', 'ps1'))) { + if ($file_reference_name = checkFileUpload($single_file, array('jpg', 'jpeg', 'gif', 'png', 'webp', 'pdf', 'txt', 'md', 'doc', 'docx', 'odt', 'csv', 'xls', 'xlsx', 'ods', 'pptx', 'odp', 'zip', 'tar', 'gz', 'xml', 'msg', 'json', 'wav', 'mp3', 'ogg', 'mov', 'mp4', 'av1', 'ovpn', 'cfg', 'ps1', 'vsdx', 'drawio'))) { $file_tmp_path = $_FILES['file']['tmp_name'][$i]; From fd48d991d982ea4bb10d7fdcf8b6a8f884cffa8e Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 26 Jan 2024 17:12:57 -0500 Subject: [PATCH 51/98] Feature: Ticket Bulk Actions Assign Tech has been added, still work in progress, update ticket reply added tech notification add logging, do not allow to assign ticket on closed ticket and more refinements --- post/ticket.php | 22 ++ ticket_bulk_assign_modal.php | 46 ++++ tickets.php | 397 +++++++++++++++++++---------------- 3 files changed, 280 insertions(+), 185 deletions(-) create mode 100644 ticket_bulk_assign_modal.php diff --git a/post/ticket.php b/post/ticket.php index f2df705b..a1dd2151 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -466,6 +466,28 @@ if (isset($_GET['delete_ticket'])) { } +if (isset($_POST['bulk_assign_ticket'])) { + + // Role check + validateTechRole(); + + // POST variables + $assign_to = intval($_POST['assign_to']); + + // Assign Tech to Selected Tickets + if (!empty($_POST['ticket_ids'])) { + foreach($_POST['ticket_ids'] as $ticket_id) { + $ticket_id = intval($ticket_id); + mysqli_query($mysqli,"UPDATE tickets SET ticket_assigned_to = $assign_to WHERE ticket_id = $ticket_id"); + } + } + + $_SESSION['alert_message'] = "Bulk Assigned Tickets"; + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_POST['add_ticket_reply'])) { validateTechRole(); diff --git a/ticket_bulk_assign_modal.php b/ticket_bulk_assign_modal.php new file mode 100644 index 00000000..6393a351 --- /dev/null +++ b/ticket_bulk_assign_modal.php @@ -0,0 +1,46 @@ + diff --git a/tickets.php b/tickets.php index 24ee725a..1c34e155 100644 --- a/tickets.php +++ b/tickets.php @@ -102,11 +102,9 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']);
-
- -
+
@@ -123,19 +121,34 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']);
-
- -
@@ -235,196 +248,210 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']);

-
- - "> - - - - - -
Number - Subject - Client / Contact - Billable +
+ +
+ + "> + + + + + - - - - - - - - - - - Never

"; - } else { - $ticket_updated_at_display = "

Never

"; - } - } else { - $ticket_updated_at_display = "$ticket_updated_at_time_ago
$ticket_updated_at"; - } - $ticket_closed_at = nullable_htmlentities($row['ticket_closed_at']); - $client_id = intval($row['ticket_client_id']); - $client_name = nullable_htmlentities($row['client_name']); - $contact_id = intval($row['ticket_contact_id']); - $contact_name = nullable_htmlentities($row['contact_name']); - $contact_title = nullable_htmlentities($row['contact_title']); - $contact_email = nullable_htmlentities($row['contact_email']); - $contact_phone = formatPhoneNumber($row['contact_phone']); - $contact_extension = nullable_htmlentities($row['contact_extension']); - $contact_mobile = formatPhoneNumber($row['contact_mobile']); - if ($ticket_status == "Pending-Assignment") { - $ticket_status_color = "danger"; - } elseif ($ticket_status == "Assigned") { - $ticket_status_color = "primary"; - } elseif ($ticket_status == "In-Progress") { - $ticket_status_color = "success"; - } elseif ($ticket_status == "Closed") { - $ticket_status_color = "dark"; - } elseif ($ticket_status == "Auto Close") { - $ticket_status_color = "dark"; - } elseif ($ticket_status == "Client-Replied") { - $ticket_status_color = "warning"; - } else{ - $ticket_status_color = "secondary"; - } - - if ($ticket_priority == "High") { - $ticket_priority_color = "danger"; - } elseif ($ticket_priority == "Medium") { - $ticket_priority_color = "warning"; - } else{ - $ticket_priority_color = "info"; - } - $ticket_assigned_to = intval($row['ticket_assigned_to']); - if (empty($ticket_assigned_to)) { - if ($ticket_status == "Closed") { - $ticket_assigned_to_display = "

Not Assigned

"; - } else { - $ticket_assigned_to_display = "

Not Assigned

"; - } - } else { - $ticket_assigned_to_display = nullable_htmlentities($row['user_name']); - } - - if (empty($contact_name)) { - $contact_display = "-"; - } else { - $contact_display = "$contact_name
$contact_email"; - } - - $asset_id = intval($row['ticket_asset_id']); - $vendor_id = intval($row['ticket_vendor_id']); - - ?> - - "> - - - - $"; - } else { - echo "X"; - } - ?> - - - - - - - + + + + + + + + Never

"; + } else { + $ticket_updated_at_display = "

Never

"; + } + } else { + $ticket_updated_at_display = "$ticket_updated_at_time_ago
$ticket_updated_at"; + } + $ticket_closed_at = nullable_htmlentities($row['ticket_closed_at']); + $client_id = intval($row['ticket_client_id']); + $client_name = nullable_htmlentities($row['client_name']); + $contact_id = intval($row['ticket_contact_id']); + $contact_name = nullable_htmlentities($row['contact_name']); + $contact_title = nullable_htmlentities($row['contact_title']); + $contact_email = nullable_htmlentities($row['contact_email']); + $contact_phone = formatPhoneNumber($row['contact_phone']); + $contact_extension = nullable_htmlentities($row['contact_extension']); + $contact_mobile = formatPhoneNumber($row['contact_mobile']); + if ($ticket_status == "Pending-Assignment") { + $ticket_status_color = "danger"; + } elseif ($ticket_status == "Assigned") { + $ticket_status_color = "primary"; + } elseif ($ticket_status == "In-Progress") { + $ticket_status_color = "success"; + } elseif ($ticket_status == "Closed") { + $ticket_status_color = "dark"; + } elseif ($ticket_status == "Auto Close") { + $ticket_status_color = "dark"; + } elseif ($ticket_status == "Client-Replied") { + $ticket_status_color = "warning"; + } else{ + $ticket_status_color = "secondary"; + } - require "ticket_assign_modal.php"; + if ($ticket_priority == "High") { + $ticket_priority_color = "danger"; + } elseif ($ticket_priority == "Medium") { + $ticket_priority_color = "warning"; + } else{ + $ticket_priority_color = "info"; + } + $ticket_assigned_to = intval($row['ticket_assigned_to']); + if (empty($ticket_assigned_to)) { + if ($ticket_status == "Closed") { + $ticket_assigned_to_display = "

Not Assigned

"; + } else { + $ticket_assigned_to_display = "

Not Assigned

"; + } + } else { + $ticket_assigned_to_display = nullable_htmlentities($row['user_name']); + } - require "ticket_edit_priority_modal.php"; + if (empty($contact_name)) { + $contact_display = "-"; + } else { + $contact_display = "$contact_name
$contact_email"; + } + + $asset_id = intval($row['ticket_asset_id']); + $vendor_id = intval($row['ticket_vendor_id']); + + ?> + + "> + + + + + + + + + + + + + + + - ?> - - -
+
+ +
+
Number + Subject + Client / Contact Priority - Status - Assigned - Last Response - Created -
- - - - - - - - -
-
- + ?> + Billable + - -
- -
Priority + Status + Assigned + Last Response + Created +
+
+ +
+
+ + + + + + + + +
+
+ + $"; + } else { + echo "X"; + } + ?> + +
+ +
-
+ +
+
+ + + + From 6dbbb232ed339170b38bc69ad9df76818d986862 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 26 Jan 2024 20:21:55 -0500 Subject: [PATCH 52/98] Update Bulk Ticket assign action: Updated button, not notifies newly assigned tech via email and in app notification and now logs properly --- post/ticket.php | 83 +++++++++++++++++++++++++++++++++++++++++++++++-- tickets.php | 41 +++++++++++------------- 2 files changed, 100 insertions(+), 24 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index a1dd2151..7c11fa06 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -478,8 +478,87 @@ if (isset($_POST['bulk_assign_ticket'])) { if (!empty($_POST['ticket_ids'])) { foreach($_POST['ticket_ids'] as $ticket_id) { $ticket_id = intval($ticket_id); - mysqli_query($mysqli,"UPDATE tickets SET ticket_assigned_to = $assign_to WHERE ticket_id = $ticket_id"); - } + + $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id"); + $row = mysqli_fetch_array($sql); + + $ticket_prefix = sanitizeInput($row['ticket_prefix']); + $ticket_number = intval($row['ticket_number']); + $ticket_status = sanitizeInput($row['ticket_status']); + $ticket_subject = sanitizeInput($row['ticket_subject']); + $client_id = intval($row['ticket_client_id']); + + if($ticket_status == 'Pending-Assignment' && $assign_to > 0){ + $ticket_status = 'Assigned'; + } + + // Allow for un-assigning tickets + if ($assign_to == 0) { + $ticket_reply = "Ticket unassigned, pending re-assignment."; + $agent_name = "No One"; + $ticket_status = "Pending-Assignment"; + } else { + // Get & verify assigned agent details + $agent_details_sql = mysqli_query($mysqli, "SELECT user_name, user_email FROM users LEFT JOIN user_settings ON users.user_id = user_settings.user_id WHERE users.user_id = $assign_to AND user_settings.user_role > 1"); + $agent_details = mysqli_fetch_array($agent_details_sql); + + $agent_name = sanitizeInput($agent_details['user_name']); + $agent_email = sanitizeInput($agent_details['user_email']); + $ticket_reply = "Ticket re-assigned to $agent_name."; + + if (!$agent_name) { + $_SESSION['alert_type'] = "error"; + $_SESSION['alert_message'] = "Invalid agent!"; + header("Location: " . $_SERVER["HTTP_REFERER"]); + exit(); + } + } + + // Update ticket & insert reply + mysqli_query($mysqli,"UPDATE tickets SET ticket_assigned_to = $assign_to, ticket_status = '$ticket_status' WHERE ticket_id = $ticket_id"); + + mysqli_query($mysqli,"INSERT INTO ticket_replies SET ticket_reply = '$ticket_reply', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + + // Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Edit', log_description = '$session_name reassigned ticket $ticket_prefix$ticket_number - $ticket_subject to $agent_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); + + + // Notification + if ($session_user_id != $assign_to && $assign_to != 0) { + + // App Notification + mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Ticket', notification = 'Ticket $ticket_prefix$ticket_number - Subject: $ticket_subject has been assigned to you by $session_name', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id, notification_user_id = $assign_to"); + + // Agent Email Notification + if (!empty($config_smtp_host)) { + + // Sanitize Config vars from get_settings.php + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $company_name = sanitizeInput($session_company_name); + + $subject = "$config_app_name ticket $ticket_prefix$ticket_number assigned to you"; + $body = "Hi $agent_name,

A ticket has been assigned to you!

Ticket Number: $ticket_prefix$ticket_number
Subject: $ticket_subject

Thanks,
$session_name
$company_name"; + + // Email Ticket Agent + // Queue Mail + $data = [ + [ + 'from' => $config_ticket_from_email, + 'from_name' => $config_ticket_from_name, + 'recipient' => $agent_email, + 'recipient_name' => $agent_name, + 'subject' => $subject, + 'body' => $body, + ] + ]; + addToMailQueue($mysqli, $data); + } + + } + + } // End For Each Ticket ID Loop + } $_SESSION['alert_message'] = "Bulk Assigned Tickets"; diff --git a/tickets.php b/tickets.php index 1c34e155..162ae904 100644 --- a/tickets.php +++ b/tickets.php @@ -121,32 +121,31 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']);
-
+
- - - Unassigned Tickets | - - - -
+ + Unassigned Tickets | + + + +
@@ -252,9 +251,7 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']);
- "> + ">
From 47d2ad993e387f47ab812796b0a6ee33de1ddf1e Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 26 Jan 2024 21:44:03 -0500 Subject: [PATCH 53/98] Don't show checkboxes next to closed tickets --- tickets.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tickets.php b/tickets.php index 162ae904..e07abdfb 100644 --- a/tickets.php +++ b/tickets.php @@ -253,7 +253,7 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); "> - "> - + + + + + + + + + + + + +
+
@@ -374,10 +374,12 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); ?>
+ +
+
From d7a58c01f9e63a07ebf6432a5bbecb06533412ae Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 26 Jan 2024 22:30:55 -0500 Subject: [PATCH 54/98] Update bulk assign tech to only notify by one email with all tickets assigned instead of multiple same with notification, updated some wording as well and include a ticket count in the logging email and notification --- post/ticket.php | 72 ++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index 7c11fa06..57ce51e6 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -473,6 +473,9 @@ if (isset($_POST['bulk_assign_ticket'])) { // POST variables $assign_to = intval($_POST['assign_to']); + + // Get a Ticket Count + $ticket_count = count($_POST['ticket_ids']); // Assign Tech to Selected Tickets if (!empty($_POST['ticket_ids'])) { @@ -523,45 +526,46 @@ if (isset($_POST['bulk_assign_ticket'])) { mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Edit', log_description = '$session_name reassigned ticket $ticket_prefix$ticket_number - $ticket_subject to $agent_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); - // Notification - if ($session_user_id != $assign_to && $assign_to != 0) { - - // App Notification - mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Ticket', notification = 'Ticket $ticket_prefix$ticket_number - Subject: $ticket_subject has been assigned to you by $session_name', notification_action = 'ticket.php?ticket_id=$ticket_id', notification_client_id = $client_id, notification_user_id = $assign_to"); - - // Agent Email Notification - if (!empty($config_smtp_host)) { - - // Sanitize Config vars from get_settings.php - $config_ticket_from_name = sanitizeInput($config_ticket_from_name); - $config_ticket_from_email = sanitizeInput($config_ticket_from_email); - $company_name = sanitizeInput($session_company_name); - - $subject = "$config_app_name ticket $ticket_prefix$ticket_number assigned to you"; - $body = "Hi $agent_name,

A ticket has been assigned to you!

Ticket Number: $ticket_prefix$ticket_number
Subject: $ticket_subject

Thanks,
$session_name
$company_name"; - - // Email Ticket Agent - // Queue Mail - $data = [ - [ - 'from' => $config_ticket_from_email, - 'from_name' => $config_ticket_from_name, - 'recipient' => $agent_email, - 'recipient_name' => $agent_name, - 'subject' => $subject, - 'body' => $body, - ] - ]; - addToMailQueue($mysqli, $data); - } - - } + $tickets_assigned_body .= "$ticket_prefix$ticket_number - $ticket_subject
"; } // End For Each Ticket ID Loop + // Notification + if ($session_user_id != $assign_to && $assign_to != 0) { + + // App Notification + mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Ticket', notification = '$ticket_count Tickets have been assigned to you by $session_name', notification_action = 'tickets.php?status=Open&assigned=$assign_to', notification_client_id = $client_id, notification_user_id = $assign_to"); + + // Agent Email Notification + if (!empty($config_smtp_host)) { + + // Sanitize Config vars from get_settings.php + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $company_name = sanitizeInput($session_company_name); + + $subject = "$config_app_name $ticket_count tickets have been assigned to you"; + $body = "Hi $agent_name,

$ticket_count tickets have been assigned to you!

$tickets_assigned_body
Thanks,
$session_name
$company_name"; + + // Email Ticket Agent + // Queue Mail + $data = [ + [ + 'from' => $config_ticket_from_email, + 'from_name' => $config_ticket_from_name, + 'recipient' => $agent_email, + 'recipient_name' => $agent_name, + 'subject' => $subject, + 'body' => $body, + ] + ]; + addToMailQueue($mysqli, $data); + } + + } } - $_SESSION['alert_message'] = "Bulk Assigned Tickets"; + $_SESSION['alert_message'] = "You assigned $ticket_count Tickets to $agent_name"; header("Location: " . $_SERVER["HTTP_REFERER"]); From a197151286fdab98dd65f3607b2ad34af988e039 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 26 Jan 2024 22:35:40 -0500 Subject: [PATCH 55/98] Update email wording on tech notify of assigned tickets --- post/ticket.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index 57ce51e6..db226148 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -525,7 +525,6 @@ if (isset($_POST['bulk_assign_ticket'])) { // Logging mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Edit', log_description = '$session_name reassigned ticket $ticket_prefix$ticket_number - $ticket_subject to $agent_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); - $tickets_assigned_body .= "$ticket_prefix$ticket_number - $ticket_subject
"; } // End For Each Ticket ID Loop @@ -545,7 +544,7 @@ if (isset($_POST['bulk_assign_ticket'])) { $company_name = sanitizeInput($session_company_name); $subject = "$config_app_name $ticket_count tickets have been assigned to you"; - $body = "Hi $agent_name,

$ticket_count tickets have been assigned to you!

$tickets_assigned_body
Thanks,
$session_name
$company_name"; + $body = "Hi $agent_name,

$session_name assigned $ticket_count tickets to you!

$tickets_assigned_body
Thanks,
$session_name
$company_name"; // Email Ticket Agent // Queue Mail From dec2f484ab2de3c7a4db75e84aba93f7fe60e327 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 26 Jan 2024 22:57:41 -0500 Subject: [PATCH 56/98] added - between App Name and Task for ticket assignment email --- post/ticket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index db226148..a2491e3b 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -405,7 +405,7 @@ if (isset($_POST['assign_ticket'])) { $config_ticket_from_email = sanitizeInput($config_ticket_from_email); $company_name = sanitizeInput($session_company_name); - $subject = "$config_app_name ticket $ticket_prefix$ticket_number assigned to you"; + $subject = "$config_app_name - ticket $ticket_prefix$ticket_number assigned to you"; $body = "Hi $agent_name,

A ticket has been assigned to you!

Ticket Number: $ticket_prefix$ticket_number
Subject: $ticket_subject

Thanks,
$session_name
$company_name"; // Email Ticket Agent @@ -543,7 +543,7 @@ if (isset($_POST['bulk_assign_ticket'])) { $config_ticket_from_email = sanitizeInput($config_ticket_from_email); $company_name = sanitizeInput($session_company_name); - $subject = "$config_app_name $ticket_count tickets have been assigned to you"; + $subject = "$config_app_name - $ticket_count tickets have been assigned to you"; $body = "Hi $agent_name,

$session_name assigned $ticket_count tickets to you!

$tickets_assigned_body
Thanks,
$session_name
$company_name"; // Email Ticket Agent From f2719a612e9010bd2fe165c2061bf58b84e0fa88 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 26 Jan 2024 23:59:24 -0500 Subject: [PATCH 57/98] Feature: Bulk Action - Assign Location for contacts --- client_contact_bulk_assign_location_modal.php | 43 +++ client_contacts.php | 347 ++++++++++-------- post/contact.php | 39 ++ tickets.php | 2 +- 4 files changed, 269 insertions(+), 162 deletions(-) create mode 100644 client_contact_bulk_assign_location_modal.php diff --git a/client_contact_bulk_assign_location_modal.php b/client_contact_bulk_assign_location_modal.php new file mode 100644 index 00000000..7b522026 --- /dev/null +++ b/client_contact_bulk_assign_location_modal.php @@ -0,0 +1,43 @@ + \ No newline at end of file diff --git a/client_contacts.php b/client_contacts.php index 6dce4fd4..f712cf39 100644 --- a/client_contacts.php +++ b/client_contacts.php @@ -61,187 +61,211 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
Archived Archived +

-
- - "> - - - - - - - - - - $contact_title"; - } - $contact_department = nullable_htmlentities($row['contact_department']); - if (empty($contact_department)) { - $contact_department_display = ""; - } else { - $contact_department_display = $contact_department; - } - $contact_extension = nullable_htmlentities($row['contact_extension']); - if (empty($contact_extension)) { - $contact_extension_display = ""; - } else { - $contact_extension_display = "x$contact_extension"; - } - $contact_phone = formatPhoneNumber($row['contact_phone']); - if (empty($contact_phone)) { - $contact_phone_display = ""; - } else { - $contact_phone_display = ""; - } - - $contact_mobile = formatPhoneNumber($row['contact_mobile']); - if (empty($contact_mobile)) { - $contact_mobile_display = ""; - } else { - $contact_mobile_display = ""; - } - $contact_email = nullable_htmlentities($row['contact_email']); - if (empty($contact_email)) { - $contact_email_display = ""; - } else { - $contact_email_display = ""; - } - $contact_info_display = "$contact_phone_display $contact_mobile_display $contact_email_display"; - if (empty($contact_info_display)) { - $contact_info_display = "-"; - } - $contact_pin = nullable_htmlentities($row['contact_pin']); - $contact_photo = nullable_htmlentities($row['contact_photo']); - $contact_initials = initials($contact_name); - $contact_notes = nullable_htmlentities($row['contact_notes']); - $contact_primary = intval($row['contact_primary']); - $contact_important = intval($row['contact_important']); - $contact_billing = intval($row['contact_billing']); - $contact_technical = intval($row['contact_technical']); - $contact_created_at = nullable_htmlentities($row['contact_created_at']); - if ($contact_primary == 1) { - $contact_primary_display = "Primary Contact"; - } else { - $contact_primary_display = false; - } - $contact_location_id = intval($row['contact_location_id']); - $location_name = nullable_htmlentities($row['location_name']); - if (empty($location_name)) { - $location_name_display = "-"; - } else { - $location_name_display = $location_name; - } - $auth_method = nullable_htmlentities($row['contact_auth_method']); - - // Related Assets Query - $sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets WHERE asset_contact_id = $contact_id ORDER BY asset_id DESC"); - $asset_count = mysqli_num_rows($sql_related_assets); - - // Related Logins Query - $sql_related_logins = mysqli_query($mysqli, "SELECT * FROM logins WHERE login_contact_id = $contact_id ORDER BY login_id DESC"); - $login_count = mysqli_num_rows($sql_related_logins); - - // Related Software Query - $sql_related_software = mysqli_query($mysqli, "SELECT * FROM software, software_contacts WHERE software.software_id = software_contacts.software_id AND software_contacts.contact_id = $contact_id ORDER BY software.software_id DESC"); - $software_count = mysqli_num_rows($sql_related_software); - - // Related Tickets Query - $sql_related_tickets = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_contact_id = $contact_id ORDER BY ticket_id DESC"); - $ticket_count = mysqli_num_rows($sql_related_tickets); - - ?> + + + +
+
NameDepartmentContactLocationAction
+ "> - - - - - - + + + + + - + + $contact_title"; + } + $contact_department = nullable_htmlentities($row['contact_department']); + if (empty($contact_department)) { + $contact_department_display = ""; + } else { + $contact_department_display = $contact_department; + } + $contact_extension = nullable_htmlentities($row['contact_extension']); + if (empty($contact_extension)) { + $contact_extension_display = ""; + } else { + $contact_extension_display = "x$contact_extension"; + } + $contact_phone = formatPhoneNumber($row['contact_phone']); + if (empty($contact_phone)) { + $contact_phone_display = ""; + } else { + $contact_phone_display = ""; + } + $contact_mobile = formatPhoneNumber($row['contact_mobile']); + if (empty($contact_mobile)) { + $contact_mobile_display = ""; + } else { + $contact_mobile_display = ""; + } + $contact_email = nullable_htmlentities($row['contact_email']); + if (empty($contact_email)) { + $contact_email_display = ""; + } else { + $contact_email_display = ""; + } + $contact_info_display = "$contact_phone_display $contact_mobile_display $contact_email_display"; + if (empty($contact_info_display)) { + $contact_info_display = "-"; + } + $contact_pin = nullable_htmlentities($row['contact_pin']); + $contact_photo = nullable_htmlentities($row['contact_photo']); + $contact_initials = initials($contact_name); + $contact_notes = nullable_htmlentities($row['contact_notes']); + $contact_primary = intval($row['contact_primary']); + $contact_important = intval($row['contact_important']); + $contact_billing = intval($row['contact_billing']); + $contact_technical = intval($row['contact_technical']); + $contact_created_at = nullable_htmlentities($row['contact_created_at']); + if ($contact_primary == 1) { + $contact_primary_display = "Primary Contact"; + } else { + $contact_primary_display = false; + } + $contact_location_id = intval($row['contact_location_id']); + $location_name = nullable_htmlentities($row['location_name']); + if (empty($location_name)) { + $location_name_display = "-"; + } else { + $location_name_display = $location_name; + } + $auth_method = nullable_htmlentities($row['contact_auth_method']); - } + // Related Assets Query + $sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets WHERE asset_contact_id = $contact_id ORDER BY asset_id DESC"); + $asset_count = mysqli_num_rows($sql_related_assets); - ?> + // Related Logins Query + $sql_related_logins = mysqli_query($mysqli, "SELECT * FROM logins WHERE login_contact_id = $contact_id ORDER BY login_id DESC"); + $login_count = mysqli_num_rows($sql_related_logins); - -
"> - - - - "> - - - - - - - - -
- - -
-
-
-
-
- +
+
NameDepartmentContactLocationAction
-
+ // Related Software Query + $sql_related_software = mysqli_query($mysqli, "SELECT * FROM software, software_contacts WHERE software.software_id = software_contacts.software_id AND software_contacts.contact_id = $contact_id ORDER BY software.software_id DESC"); + $software_count = mysqli_num_rows($sql_related_software); + + // Related Tickets Query + $sql_related_tickets = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_contact_id = $contact_id ORDER BY ticket_id DESC"); + $ticket_count = mysqli_num_rows($sql_related_tickets); + + ?> +
+
+ +
+
"> + + + + "> + + + + + + + + +
+ + +
+
+
+
+
+ +
+
+ + @@ -287,6 +311,8 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); }); + + $contact_count contacts to location $location_name"; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_GET['anonymize_contact'])) { validateAdminRole(); diff --git a/tickets.php b/tickets.php index e07abdfb..5096fbab 100644 --- a/tickets.php +++ b/tickets.php @@ -248,7 +248,7 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']);
- +
"> From ee3087725da47c51d0e3e5bb826acd7deb042027 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 01:03:18 -0500 Subject: [PATCH 58/98] Rename inconsistent multi Actions to Bulk Actions --- js/bulk_actions.js | 40 ++++++++++++++++++++++++++++++++++++++++ js/multi_actions.js | 35 ----------------------------------- 2 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 js/bulk_actions.js delete mode 100644 js/multi_actions.js diff --git a/js/bulk_actions.js b/js/bulk_actions.js new file mode 100644 index 00000000..f83ced35 --- /dev/null +++ b/js/bulk_actions.js @@ -0,0 +1,40 @@ +// Allow selecting and editing multiple records at once + +var form = document.getElementById("bulkActions"); // Get the form element by its id +var checkboxes = form.querySelectorAll('input[type="checkbox"].bulk-select'); // Select only checkboxes with class "bulk-select" +var selectedCount = document.getElementById("selectedCount"); +var selectAllCheckbox = document.getElementById("selectAllCheckbox"); // The "select all" checkbox + +// Event listener for each checkbox +for (var i = 0; i < checkboxes.length; i++) { + checkboxes[i].addEventListener("click", updateSelectedCount); +} + +// Function to update the count of selected checkboxes +function updateSelectedCount() { + var count = 0; + for (var i = 0; i < checkboxes.length; i++) { + if (checkboxes[i].checked) { + count++; + } + } + selectedCount.textContent = count; // Display the count + + // Show or hide the multi-action button + document.getElementById("bulkActionButton").hidden = count === 0; +} + +// Function to check/uncheck all checkboxes +function checkAll(source) { + for (var i = 0; i < checkboxes.length; i++) { + checkboxes[i].checked = source.checked; + } + updateSelectedCount(); // Update the count after changing checkbox states +} + +// Event listener for the "select all" checkbox +if (selectAllCheckbox) { + selectAllCheckbox.addEventListener("click", function() { + checkAll(this); + }); +} diff --git a/js/multi_actions.js b/js/multi_actions.js deleted file mode 100644 index db45e613..00000000 --- a/js/multi_actions.js +++ /dev/null @@ -1,35 +0,0 @@ -// Allow selecting and editing multiple records at once - -var form = document.getElementById("multi_actions"); // Get the form element by its id -var checkboxes = form.querySelectorAll('input[type="checkbox"]'); -var selectedCount = document.getElementById("selectedCount"); - - -for (var i = 0; i < checkboxes.length; i++) { - checkboxes[i].addEventListener("click", updateSelectedCount); -} - -function updateSelectedCount() { - var count = 0; - for (var i = 0; i < checkboxes.length; i++) { - if (checkboxes[i].checked) { - if (checkboxes[i] !== document.getElementById("selectAllCheckbox") && checkboxes[i].checked) { - count++; - } - } - } - selectedCount.textContent = count; - if (count > 0) { - document.getElementById("multiActionButton").hidden = false; - } - - if (count === 0) { - document.getElementById("multiActionButton").hidden = true; - } -} - -function checkAll(source) { - for (var i = 0; i < checkboxes.length; i++) { - checkboxes[i].checked = source.checked; - } -} From 1deba6eac5e986ac5309af4208e5f9f6b2cb37d8 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 01:41:25 -0500 Subject: [PATCH 59/98] Added Bulk Assign Location to Assets --- client_asset_bulk_assign_location_modal.php | 43 ++ client_assets.php | 452 +++++++++++--------- client_contacts.php | 8 +- post/asset.php | 39 ++ scheduled_tickets.php | 14 +- tickets.php | 8 +- 6 files changed, 335 insertions(+), 229 deletions(-) create mode 100644 client_asset_bulk_assign_location_modal.php diff --git a/client_asset_bulk_assign_location_modal.php b/client_asset_bulk_assign_location_modal.php new file mode 100644 index 00000000..a5ad9f8c --- /dev/null +++ b/client_asset_bulk_assign_location_modal.php @@ -0,0 +1,43 @@ + \ No newline at end of file diff --git a/client_assets.php b/client_assets.php index a710ff78..31b3a2c9 100644 --- a/client_assets.php +++ b/client_assets.php @@ -139,252 +139,276 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); Archived +
-
-
- "> - - - - - - - - - - - - - - - - - - - - - - - "; - } - $asset_nat_ip = nullable_htmlentities($row['asset_nat_ip']); - $asset_mac = nullable_htmlentities($row['asset_mac']); - $asset_uri = nullable_htmlentities($row['asset_uri']); - $asset_uri_2 = nullable_htmlentities($row['asset_uri_2']); - $asset_status = nullable_htmlentities($row['asset_status']); - $asset_purchase_date = nullable_htmlentities($row['asset_purchase_date']); - $asset_warranty_expire = nullable_htmlentities($row['asset_warranty_expire']); - $asset_install_date = nullable_htmlentities($row['asset_install_date']); - if (empty($asset_install_date)) { - $asset_install_date_display = "-"; - } else { - $asset_install_date_display = $asset_install_date; - } - $asset_notes = nullable_htmlentities($row['asset_notes']); - $asset_created_at = nullable_htmlentities($row['asset_created_at']); - $asset_vendor_id = intval($row['asset_vendor_id']); - $asset_location_id = intval($row['asset_location_id']); - $asset_contact_id = intval($row['asset_contact_id']); - $asset_network_id = intval($row['asset_network_id']); - - $device_icon = getAssetIcon($asset_type); - - $contact_name = nullable_htmlentities($row['contact_name']); - if (empty($contact_name)) { - $contact_name = "-"; - } - $contact_archived_at = nullable_htmlentities($row['contact_archived_at']); - if (empty($contact_archived_at)) { - $contact_archived_display = ""; - } else { - $contact_archived_display = "Archived - "; - } - - $location_name = nullable_htmlentities($row['location_name']); - if (empty($location_name)) { - $location_name = "-"; - } - $location_archived_at = nullable_htmlentities($row['location_archived_at']); - if (empty($location_archived_at)) { - $location_archived_display = ""; - } else { - $location_archived_display = "Archived - "; - } - - $login_id = intval($row['login_id']); - $login_username = nullable_htmlentities(decryptLoginEntry($row['login_username'])); - $login_password = nullable_htmlentities(decryptLoginEntry($row['login_password'])); - - ?> + +
+
Name / DescriptionTypeMake / ModelSerial NumberOperating SystemIPInstall DateAssigned ToLocationStatusAction
+ "> - + + + + + + + + + + + + + + + + + + + + + + " tabindex="-1"> - + + + + -
- -
- - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + - ?> - - -
- - - - - - 0) { - ?> - + +
+ +
+
Name / DescriptionTypeMake / ModelSerial NumberOperating SystemIPInstall DateAssigned ToLocationStatusAction
+
+ +
+
+ + + + + + 0) { + ?> + + + + +
+ +
+
- -
- +
-
-
- + +
+
+ + +
+ + Archived -
- +
"> @@ -311,7 +311,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); }); - + $asset_count assets to location $location_name"; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_POST["import_client_assets_csv"])) { validateTechRole(); diff --git a/scheduled_tickets.php b/scheduled_tickets.php index 4e1753cc..fd552f8f 100644 --- a/scheduled_tickets.php +++ b/scheduled_tickets.php @@ -50,9 +50,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
- diff --git a/post/asset.php b/post/asset.php index a46d275e..73f3173a 100644 --- a/post/asset.php +++ b/post/asset.php @@ -260,6 +260,45 @@ if (isset($_POST['bulk_assign_asset_location'])) { } +if (isset($_POST['bulk_assign_asset_contact'])) { + + validateTechRole(); + + $contact_id = intval($_POST['contact_id']); + + // Get Contact name and client id for logging and Notification + $sql = mysqli_query($mysqli,"SELECT contact_name, contact_client_id FROM contacts WHERE contact_id = $contact_id"); + $row = mysqli_fetch_array($sql); + $contact_name = sanitizeInput($row['contact_name']); + $client_id = intval($row['contact_client_id']); + + // Get Selected Contacts Count + $asset_count = count($_POST['asset_ids']); + + // Assign Contact to Selected Assets + if (!empty($_POST['asset_ids'])) { + foreach($_POST['asset_ids'] as $asset_id) { + $asset_id = intval($asset_id); + + // Get Asset Details for Logging + $sql = mysqli_query($mysqli,"SELECT asset_name FROM assets WHERE asset_id = $asset_id"); + $row = mysqli_fetch_array($sql); + $asset_name = sanitizeInput($row['asset_name']); + + mysqli_query($mysqli,"UPDATE assets SET asset_contact_id = $contact_id WHERE asset_id = $asset_id"); + + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Asset', log_action = 'Modify', log_description = '$session_name assigned $asset_name to contact $contact_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $asset_id"); + + } // End Assign Contact Loop + + $_SESSION['alert_message'] = "You assigned $asset_count assets to contact $contact_name"; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_POST["import_client_assets_csv"])) { validateTechRole(); From 3c28c2b89b31442d8e98d5fcb182a6db75b42056 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 02:16:41 -0500 Subject: [PATCH 61/98] Prevent Password Manager from asking to save password for every asset edit / add / bulk submit --- client_asset_add_modal.php | 2 +- client_asset_copy_modal.php | 2 +- client_asset_edit_modal.php | 2 +- client_assets.php | 3 ++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client_asset_add_modal.php b/client_asset_add_modal.php index d546991b..a0248c96 100644 --- a/client_asset_add_modal.php +++ b/client_asset_add_modal.php @@ -345,7 +345,7 @@
- +
diff --git a/client_asset_copy_modal.php b/client_asset_copy_modal.php index 10ea9946..2ed181fc 100644 --- a/client_asset_copy_modal.php +++ b/client_asset_copy_modal.php @@ -341,7 +341,7 @@
- + diff --git a/client_asset_edit_modal.php b/client_asset_edit_modal.php index 8f3c73a9..86c0ef30 100644 --- a/client_asset_edit_modal.php +++ b/client_asset_edit_modal.php @@ -369,7 +369,7 @@
- + diff --git a/client_assets.php b/client_assets.php index 5e79483a..6eac3ef7 100644 --- a/client_assets.php +++ b/client_assets.php @@ -162,7 +162,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
- "> + "> - + From 8562906fa654e7049d9ecbaea223ad8621de90c6 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 03:04:43 -0500 Subject: [PATCH 64/98] Prevent Copy to Clipboard button from submitting in assets since we wrapped listings in a form to allow for bulk actions this caused buttons like this to act as submits unless we add type='button' --- client_assets.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_assets.php b/client_assets.php index 45855636..2b894880 100644 --- a/client_assets.php +++ b/client_assets.php @@ -223,7 +223,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); if (empty($asset_ip)) { $asset_ip_display = "-"; } else { - $asset_ip_display = "$asset_ip"; + $asset_ip_display = "$asset_ip"; } $asset_nat_ip = nullable_htmlentities($row['asset_nat_ip']); $asset_mac = nullable_htmlentities($row['asset_mac']); From 9184fa3ab35b74346439e869f64db099db7992c1 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 03:10:54 -0500 Subject: [PATCH 65/98] Fix Copy IP to clipboard in Assets missing clipboardjs class --- client_assets.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_assets.php b/client_assets.php index 2b894880..a482214e 100644 --- a/client_assets.php +++ b/client_assets.php @@ -223,7 +223,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); if (empty($asset_ip)) { $asset_ip_display = "-"; } else { - $asset_ip_display = "$asset_ip"; + $asset_ip_display = "$asset_ip"; } $asset_nat_ip = nullable_htmlentities($row['asset_nat_ip']); $asset_mac = nullable_htmlentities($row['asset_mac']); From d3153a29cbefe9b8896947233f97b273c1510228 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 03:32:30 -0500 Subject: [PATCH 66/98] Asset Assignment Do not show all archived users from the date the asset is created instead if an asset has an archive user show that user and all new users --- client_asset_edit_modal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_asset_edit_modal.php b/client_asset_edit_modal.php index 86c0ef30..fb99ed29 100644 --- a/client_asset_edit_modal.php +++ b/client_asset_edit_modal.php @@ -251,7 +251,7 @@ '$asset_created_at' OR contact_archived_at IS NULL) AND contact_client_id = $client_id ORDER BY contact_archived_at ASC, contact_name ASC"); + $sql_contacts = mysqli_query($mysqli, "SELECT * FROM contacts WHERE contact_id = $asset_contact_id OR (contact_archived_at IS NULL) AND contact_client_id = $client_id ORDER BY contact_archived_at ASC, contact_name ASC"); while ($row = mysqli_fetch_array($sql_contacts)) { $contact_id_select = intval($row['contact_id']); $contact_name_select = nullable_htmlentities($row['contact_name']); From 0b7b7e298afec8ff1fddb10dca3a624e413dceca Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 03:35:22 -0500 Subject: [PATCH 67/98] Remove unessesary () --- client_asset_edit_modal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_asset_edit_modal.php b/client_asset_edit_modal.php index fb99ed29..f544693f 100644 --- a/client_asset_edit_modal.php +++ b/client_asset_edit_modal.php @@ -251,7 +251,7 @@ Date: Sat, 27 Jan 2024 03:44:32 -0500 Subject: [PATCH 68/98] Add Red X next to Assigned to for Archived Users still palying with this design maybe just make the user text red with a pop over that says archived when hovered --- client_assets.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_assets.php b/client_assets.php index a482214e..d57b8540 100644 --- a/client_assets.php +++ b/client_assets.php @@ -255,7 +255,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); if (empty($contact_archived_at)) { $contact_archived_display = ""; } else { - $contact_archived_display = "Archived - "; + $contact_archived_display = " Archived - "; } $location_name = nullable_htmlentities($row['location_name']); From d8de41d9377198eb418068cc757e6bf7224b0ad2 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 11:59:05 -0500 Subject: [PATCH 69/98] Do Not show archived items when copying asset --- client_asset_copy_modal.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client_asset_copy_modal.php b/client_asset_copy_modal.php index 2ed181fc..bf676a8f 100644 --- a/client_asset_copy_modal.php +++ b/client_asset_copy_modal.php @@ -132,7 +132,7 @@ '$asset_created_at' OR network_archived_at IS NULL) AND network_client_id = $client_id ORDER BY network_name ASC"); + $sql_networks = mysqli_query($mysqli, "SELECT * FROM networks WHERE network_archived_at IS NULL AND network_client_id = $client_id ORDER BY network_name ASC"); while ($row = mysqli_fetch_array($sql_networks)) { $network_id_select = intval($row['network_id']); $network_name_select = nullable_htmlentities($row['network_name']); @@ -215,7 +215,7 @@ - Vendor - '$asset_created_at' OR vendor_archived_at IS NULL) AND vendor_client_id = $client_id AND vendor_template = 0 ORDER BY vendor_name ASC"); + $sql_vendors = mysqli_query($mysqli, "SELECT * FROM vendors WHERE vendor_archived_at IS NULL AND vendor_client_id = $client_id AND vendor_template = 0 ORDER BY vendor_name ASC"); while ($row = mysqli_fetch_array($sql_vendors)) { $vendor_id_select = intval($row['vendor_id']); $vendor_name_select = nullable_htmlentities($row['vendor_name']); From 8b85ae377a6b2a0b960f85a2a1e7c37ffcd3443c Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 13:23:44 -0500 Subject: [PATCH 70/98] Updated the way Archived Items are displayed in asset list view and when editing, this will be standard going forward, added Bulk Set Asset Status, further work on improving the archived logic, assets is pretty much gold standard here now --- client_asset_bulk_edit_status_modal.php | 36 ++++++++++++++++++++++ client_asset_details.php | 19 +++++++----- client_asset_edit_modal.php | 40 ++++++++++++------------- client_assets.php | 21 ++++++++----- post/asset.php | 34 +++++++++++++++++++++ 5 files changed, 114 insertions(+), 36 deletions(-) create mode 100644 client_asset_bulk_edit_status_modal.php diff --git a/client_asset_bulk_edit_status_modal.php b/client_asset_bulk_edit_status_modal.php new file mode 100644 index 00000000..910d953c --- /dev/null +++ b/client_asset_bulk_edit_status_modal.php @@ -0,0 +1,36 @@ + \ No newline at end of file diff --git a/client_asset_details.php b/client_asset_details.php index 78e635aa..f95fd002 100644 --- a/client_asset_details.php +++ b/client_asset_details.php @@ -46,17 +46,20 @@ if (isset($_GET['asset_id'])) { $contact_phone = nullable_htmlentities($row['contact_phone']); $contact_mobile = nullable_htmlentities($row['contact_mobile']); $contact_archived_at = nullable_htmlentities($row['contact_archived_at']); - if (empty($contact_archived_at)) { - $contact_archived_display = ""; + if ($contact_archived_at) { + $contact_name_display = "$contact_name"; } else { - $contact_archived_display = "Archived - "; + $contact_name_display = $contact_name; } $location_name = nullable_htmlentities($row['location_name']); + if (empty($location_name)) { + $location_name = "-"; + } $location_archived_at = nullable_htmlentities($row['location_archived_at']); - if (empty($location_archived_at)) { - $location_archived_display = ""; + if ($location_archived_at) { + $location_name_display = "$location_name"; } else { - $location_archived_display = "Archived - "; + $location_name_display = $location_name; } $login_id = intval($row['login_id']); @@ -181,10 +184,10 @@ if (isset($_GET['asset_id'])) {
-
+
-
+
diff --git a/client_asset_edit_modal.php b/client_asset_edit_modal.php index f544693f..45a07833 100644 --- a/client_asset_edit_modal.php +++ b/client_asset_edit_modal.php @@ -134,20 +134,20 @@ '$asset_created_at' OR network_archived_at IS NULL) AND network_client_id = $client_id ORDER BY network_archived_at ASC, network_name ASC"); + $sql_networks = mysqli_query($mysqli, "SELECT * FROM networks WHERE network_id = $asset_network_id OR network_archived_at IS NULL AND network_client_id = $client_id ORDER BY network_name ASC"); while ($row = mysqli_fetch_array($sql_networks)) { $network_id_select = intval($row['network_id']); $network_name_select = nullable_htmlentities($row['network_name']); $network_select = nullable_htmlentities($row['network']); $network_archived_at = nullable_htmlentities($row['network_archived_at']); - if (empty($network_archived_at)) { - $network_archived_display = ""; + if ($network_archived_at) { + $network_name_select_display = "($network_name_select - $network_select) - ARCHIVED"; } else { - $network_archived_display = "Archived - "; + $network_name_select_display = "$network_name_select - $network_select"; } ?> - + @@ -223,18 +223,18 @@ '$asset_created_at' OR location_archived_at IS NULL) AND location_client_id = $client_id ORDER BY location_archived_at ASC, location_name ASC"); + $sql_locations = mysqli_query($mysqli, "SELECT * FROM locations WHERE location_id = $asset_location_id OR location_archived_at IS NULL AND location_client_id = $client_id ORDER BY location_name ASC"); while ($row = mysqli_fetch_array($sql_locations)) { $location_id_select = intval($row['location_id']); $location_name_select = nullable_htmlentities($row['location_name']); $location_archived_at = nullable_htmlentities($row['location_archived_at']); - if (empty($location_archived_at)) { - $location_archived_display = ""; + if ($location_archived_at) { + $location_name_select_display = "($location_name_select) - ARCHIVED"; } else { - $location_archived_display = "Archived - "; + $location_name_select_display = $location_name_select; } ?> - + @@ -251,19 +251,19 @@ @@ -299,18 +299,18 @@ '$asset_created_at' OR vendor_archived_at IS NULL) AND vendor_client_id = $client_id ORDER BY vendor_archived_at ASC, vendor_name ASC"); + $sql_vendors = mysqli_query($mysqli, "SELECT * FROM vendors WHERE vendor_id = $asset_vendor_id OR vendor_archived_at IS NULL AND vendor_client_id = $client_id ORDER BY vendor_name ASC"); while ($row = mysqli_fetch_array($sql_vendors)) { $vendor_id_select = intval($row['vendor_id']); $vendor_name_select = nullable_htmlentities($row['vendor_name']); $vendor_archived_at = nullable_htmlentities($row['vendor_archived_at']); - if (empty($vendor_archived_at)) { - $vendor_archived_display = ""; + if ($vendor_archived_at) { + $vendor_name_select_display = "($vendor_name_select) - ARCHIVED"; } else { - $vendor_archived_display = "Archived - "; + $vendor_name_select_display = $vendor_name_select; } ?> - + diff --git a/client_assets.php b/client_assets.php index d57b8540..06de5897 100644 --- a/client_assets.php +++ b/client_assets.php @@ -151,6 +151,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); Assign Location + + + Set Status +
@@ -252,10 +256,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $contact_name = "-"; } $contact_archived_at = nullable_htmlentities($row['contact_archived_at']); - if (empty($contact_archived_at)) { - $contact_archived_display = ""; + if ($contact_archived_at) { + $contact_name_display = "
$contact_name
"; } else { - $contact_archived_display = " Archived - "; + $contact_name_display = $contact_name; } $location_name = nullable_htmlentities($row['location_name']); @@ -263,10 +267,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $location_name = "-"; } $location_archived_at = nullable_htmlentities($row['location_archived_at']); - if (empty($location_archived_at)) { - $location_archived_display = ""; + if ($location_archived_at) { + $location_name_display = "
$location_name
"; } else { - $location_archived_display = "Archived - "; + $location_name_display = $location_name; } $login_id = intval($row['login_id']); @@ -355,9 +359,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
- + - + - + + + + + + + diff --git a/js/ticket_time_tracking.js b/js/ticket_time_tracking.js index f60a7016..081319e3 100644 --- a/js/ticket_time_tracking.js +++ b/js/ticket_time_tracking.js @@ -103,7 +103,6 @@ document.getElementById("startStopTimer").innerText = "Start"; } - function handleInputFocus() { if (!isPaused) { pauseTimer(); @@ -126,7 +125,6 @@ } } - function updateRunningTicketsCount() { let runningTickets = parseInt(document.getElementById('runningTicketsCount').innerText, 10); @@ -136,31 +134,27 @@ runningTickets = Math.max(0, runningTickets - 1); } - document.getElementById('runningTicketsCount').innerText = runningTickets.toString(); + document.getElementById('runningTicketsCount').innerText = runningTickets.toString(); } // Function to check status and pause timer function checkStatusAndPauseTimer() { var status = document.querySelector('select[name="status"]').value; - if (status.includes("Pending")) { + if (status.includes("Pending") || status.includes("Close")) { pauseTimer(); } } - - document.getElementById("hours").addEventListener('change', updateTimeFromInput); document.getElementById("minutes").addEventListener('change', updateTimeFromInput); document.getElementById("seconds").addEventListener('change', updateTimeFromInput); - document.getElementById("hours").addEventListener('focus', handleInputFocus); document.getElementById("minutes").addEventListener('focus', handleInputFocus); document.getElementById("seconds").addEventListener('focus', handleInputFocus); document.querySelector('select[name="status"]').addEventListener('change', checkStatusAndPauseTimer); - document.getElementById("startStopTimer").addEventListener('click', function() { if (timerInterval === null) { startTimer(); diff --git a/settings_online_payment.php b/settings_online_payment.php index 33425dfb..76201245 100644 --- a/settings_online_payment.php +++ b/settings_online_payment.php @@ -24,7 +24,7 @@ require_once "inc_all_settings.php";
">
- +
@@ -34,7 +34,7 @@ require_once "inc_all_settings.php";
- +
From 007d07d41720f10eece38fd5b12d1b972a51e656 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 28 Jan 2024 15:57:27 -0500 Subject: [PATCH 81/98] Added unbilled ticket wording per Pull Req #866 --- client_tickets.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_tickets.php b/client_tickets.php index a7fb7b10..47e9719d 100644 --- a/client_tickets.php +++ b/client_tickets.php @@ -63,7 +63,7 @@ $total_tickets_closed = intval($row['total_tickets_closed']);
-

Tickets +

Tickets Open | Closed From e82ba786a588b7aed191395c30762eb4f7df1a49 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Mon, 29 Jan 2024 21:17:12 -0500 Subject: [PATCH 82/98] Added One more code piece from Pull #866 to fix Gateway Fees shown and to fix balance on guest view invoice --- guest_view_invoice.php | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/guest_view_invoice.php b/guest_view_invoice.php index 18f5c6ba..84a27a38 100644 --- a/guest_view_invoice.php +++ b/guest_view_invoice.php @@ -111,16 +111,25 @@ $sql_amount_paid = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS amount_p $row = mysqli_fetch_array($sql_amount_paid); $amount_paid = floatval($row['amount_paid']); -// Check config to see if client pays fees is enabled -if ($config_stripe_client_pays_fees == 1) { - // Calculate the amount to charge the client - $balance_to_pay = ($balance + $config_stripe_flat_fee) / (1 - $coinfig_stripe_percentage_fee); - $stripe_fee = $balance_to_pay - $balance; +if ($invoice_amount - $amount_paid < 0) { //already paid invoices + $gateway_fee = -1 * ($invoice_amount - $amount_paid); + $amount_paid = $invoice_amount; // Set amount paid to invoice amount if gateway fee is enabled. + $balance = $invoice_amount - $amount_paid; } else { $gateway_fee = 0; $balance = $invoice_amount - $amount_paid; } +// Check config to see if client pays fees is enabled +if ($config_stripe_client_pays_fees == 1) { + // Calculate the amount to charge the client + $balance_to_pay = ($balance + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); + $gateway_fee = $balance_to_pay - $balance; +} else { + $gateway_fee = 0; +} + + //check to see if overdue $invoice_color = $invoice_badge_color; // Default if ($invoice_status !== "Paid" && $invoice_status !== "Draft" && $invoice_status !== "Cancelled") { @@ -301,7 +310,7 @@ $sql_invoice_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE it 0) { ?>

From ff1616de9455cf9ebc0db2814679ab09a67801fd Mon Sep 17 00:00:00 2001 From: johnnyq Date: Mon, 29 Jan 2024 21:56:13 -0500 Subject: [PATCH 83/98] Updated Guest Invoice logic so if they payed gateway fee is not shown --- guest_view_invoice.php | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/guest_view_invoice.php b/guest_view_invoice.php index 84a27a38..d790e20b 100644 --- a/guest_view_invoice.php +++ b/guest_view_invoice.php @@ -111,25 +111,28 @@ $sql_amount_paid = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS amount_p $row = mysqli_fetch_array($sql_amount_paid); $amount_paid = floatval($row['amount_paid']); -if ($invoice_amount - $amount_paid < 0) { //already paid invoices - $gateway_fee = -1 * ($invoice_amount - $amount_paid); - $amount_paid = $invoice_amount; // Set amount paid to invoice amount if gateway fee is enabled. - $balance = $invoice_amount - $amount_paid; -} else { - $gateway_fee = 0; - $balance = $invoice_amount - $amount_paid; -} +// Calculate the balance owed +$balance = $invoice_amount - $amount_paid; -// Check config to see if client pays fees is enabled -if ($config_stripe_client_pays_fees == 1) { - // Calculate the amount to charge the client - $balance_to_pay = ($balance + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); - $gateway_fee = $balance_to_pay - $balance; +// Check for overpayment or exact payment (amount paid is equal to or exceeds invoice amount) +if ($balance <= 0) { + // Invoice is fully paid (either exact payment or overpayment) + $gateway_fee = 0; // Zero out the gateway fee + $amount_paid = $invoice_amount; // Adjust amount paid to equal invoice amount + $balance = 0; // Balance is zero since invoice is fully paid } else { - $gateway_fee = 0; + // If invoice is not fully paid + // Check if client is responsible for paying Stripe fees + if ($config_stripe_client_pays_fees == 1) { + // Calculate the total amount to charge the client, including Stripe fees + $balance_to_pay = ($balance + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); + $gateway_fee = $balance_to_pay - $balance; // Calculate gateway fee based on Stripe fees + } else { + // If client is not responsible for Stripe fees, gateway fee remains zero + $gateway_fee = 0; + } } - //check to see if overdue $invoice_color = $invoice_badge_color; // Default if ($invoice_status !== "Paid" && $invoice_status !== "Draft" && $invoice_status !== "Cancelled") { From db8ae13135fa6c3d54ad5284586ce8f6a27b01e3 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Tue, 30 Jan 2024 14:11:29 -0500 Subject: [PATCH 84/98] Feature: Add Bulk Move Folder Action to Client Documents and Files --- client_document_bulk_move_modal.php | 41 ++++++ client_documents.php | 202 ++++++++++++++++------------ client_file_bulk_move_modal.php | 41 ++++++ client_files.php | 193 ++++++++++++++------------ post/document.php | 38 ++++++ post/file.php | 38 ++++++ 6 files changed, 380 insertions(+), 173 deletions(-) create mode 100644 client_document_bulk_move_modal.php create mode 100644 client_file_bulk_move_modal.php diff --git a/client_document_bulk_move_modal.php b/client_document_bulk_move_modal.php new file mode 100644 index 00000000..9b5ddadf --- /dev/null +++ b/client_document_bulk_move_modal.php @@ -0,0 +1,41 @@ + diff --git a/client_documents.php b/client_documents.php index 67b3749c..c826c5d6 100644 --- a/client_documents.php +++ b/client_documents.php @@ -165,104 +165,128 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
- +
+
+
+ +
-
-
@@ -314,6 +314,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
+
From fe33cfa4e924f00b80be12ad7924c7d145b56259 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 02:48:31 -0500 Subject: [PATCH 62/98] UI: Fix the client top head city state postal below the address from being offset by using a font awesome dummy icon --- inc_client_top_head.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc_client_top_head.php b/inc_client_top_head.php index 8b8ea699..19ab16eb 100644 --- a/inc_client_top_head.php +++ b/inc_client_top_head.php @@ -44,7 +44,7 @@ Date: Sat, 27 Jan 2024 02:55:06 -0500 Subject: [PATCH 63/98] UI: Set IP Column to Text no wrap to prevent the Copy IP Button from wrapping --- client_assets.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_assets.php b/client_assets.php index 6eac3ef7..45855636 100644 --- a/client_assets.php +++ b/client_assets.php @@ -352,7 +352,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
+ diff --git a/post/asset.php b/post/asset.php index 73f3173a..7a5d4b38 100644 --- a/post/asset.php +++ b/post/asset.php @@ -299,6 +299,40 @@ if (isset($_POST['bulk_assign_asset_contact'])) { } +if (isset($_POST['bulk_edit_asset_status'])) { + + validateTechRole(); + + $status = sanitizeInput($_POST['status']); + + // Get Selected Contacts Count + $asset_count = count($_POST['asset_ids']); + + // Assign Contact to Selected Assets + if (!empty($_POST['asset_ids'])) { + foreach($_POST['asset_ids'] as $asset_id) { + $asset_id = intval($asset_id); + + // Get Asset Details for Logging + $sql = mysqli_query($mysqli,"SELECT asset_name, asset_client_id FROM assets WHERE asset_id = $asset_id"); + $row = mysqli_fetch_array($sql); + $asset_name = sanitizeInput($row['asset_name']); + $client_id = intval($row['asset_client_id']); + + mysqli_query($mysqli,"UPDATE assets SET asset_status = '$status' WHERE asset_id = $asset_id"); + + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Asset', log_action = 'Modify', log_description = '$session_name set status $status on $asset_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $asset_id"); + + } // End Assign Contact Loop + + $_SESSION['alert_message'] = "You set the status $status on $asset_count assets."; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_POST["import_client_assets_csv"])) { validateTechRole(); From 50b00c5712a34eaa91f24f7219d20c88d55bc5ab Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 13:45:11 -0500 Subject: [PATCH 71/98] Feature: Bulk Edit Contact Phone Number useful where the share an Office Number but have seperate extensions --- client_contact_bulk_edit_phone_modal.php | 31 +++++++++++++++++++ client_contacts.php | 6 +++- post/contact.php | 38 ++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 client_contact_bulk_edit_phone_modal.php diff --git a/client_contact_bulk_edit_phone_modal.php b/client_contact_bulk_edit_phone_modal.php new file mode 100644 index 00000000..a872c7dd --- /dev/null +++ b/client_contact_bulk_edit_phone_modal.php @@ -0,0 +1,31 @@ + \ No newline at end of file diff --git a/client_contacts.php b/client_contacts.php index 13460f53..a6a856be 100644 --- a/client_contacts.php +++ b/client_contacts.php @@ -75,6 +75,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); Assign Location + + + Set Phone Number + @@ -85,7 +89,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
"> @@ -265,6 +268,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
+
diff --git a/post/contact.php b/post/contact.php index ca336826..3c1d8640 100644 --- a/post/contact.php +++ b/post/contact.php @@ -177,12 +177,12 @@ if (isset($_POST['bulk_assign_contact_location'])) { validateTechRole(); $location_id = intval($_POST['location']); - $client_id = intval($_POST['client_id']); // Get Location name for logging and Notification - $sql = mysqli_query($mysqli,"SELECT location_name FROM locations WHERE location_id = $location_id"); + $sql = mysqli_query($mysqli,"SELECT location_name, location_client_id FROM locations WHERE location_id = $location_id"); $row = mysqli_fetch_array($sql); $location_name = sanitizeInput($row['location_name']); + $client_id = intval($row['location_client_id']); // Get Selected Contacts Count $contact_count = count($_POST['contact_ids']); @@ -211,6 +211,40 @@ if (isset($_POST['bulk_assign_contact_location'])) { } +if (isset($_POST['bulk_edit_contact_phone'])) { + + validateTechRole(); + + $phone = preg_replace("/[^0-9]/", '', $_POST['phone']); + + // Get Selected Contacts Count + $contact_count = count($_POST['contact_ids']); + + // Assign Location to Selected Contacts + if (!empty($_POST['contact_ids'])) { + foreach($_POST['contact_ids'] as $contact_id) { + $contact_id = intval($contact_id); + + // Get Contact Details for Logging + $sql = mysqli_query($mysqli,"SELECT contact_name, contact_client_id FROM contacts WHERE contact_id = $contact_id"); + $row = mysqli_fetch_array($sql); + $contact_name = sanitizeInput($row['contact_name']); + $client_id = intval($row['contact_client_id']); + + mysqli_query($mysqli,"UPDATE contacts SET contact_phone = '$phone' WHERE contact_id = $contact_id"); + + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Contact', log_action = 'Modify', log_description = '$session_name set Phone Number to $phone for $contact_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $contact_id"); + + } // End Assign Location Loop + + $_SESSION['alert_message'] = "You set Phone Number " . formatPhoneNumber($phone) . " on $contact_count contacts"; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_GET['anonymize_contact'])) { validateAdminRole(); From c711db937df827da9caa387b35b8f20c0560c275 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 14:01:10 -0500 Subject: [PATCH 72/98] Updated Edit Location logic in contacts added Pop Over Title for archived Items in assets and contacts --- client_asset_details.php | 4 ++-- client_assets.php | 4 ++-- client_contact_edit_modal.php | 10 ++++++++-- client_contacts.php | 6 +++++- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/client_asset_details.php b/client_asset_details.php index f95fd002..07718006 100644 --- a/client_asset_details.php +++ b/client_asset_details.php @@ -47,7 +47,7 @@ if (isset($_GET['asset_id'])) { $contact_mobile = nullable_htmlentities($row['contact_mobile']); $contact_archived_at = nullable_htmlentities($row['contact_archived_at']); if ($contact_archived_at) { - $contact_name_display = "$contact_name"; + $contact_name_display = "$contact_name"; } else { $contact_name_display = $contact_name; } @@ -57,7 +57,7 @@ if (isset($_GET['asset_id'])) { } $location_archived_at = nullable_htmlentities($row['location_archived_at']); if ($location_archived_at) { - $location_name_display = "$location_name"; + $location_name_display = "$location_name"; } else { $location_name_display = $location_name; } diff --git a/client_assets.php b/client_assets.php index 06de5897..81356f28 100644 --- a/client_assets.php +++ b/client_assets.php @@ -257,7 +257,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); } $contact_archived_at = nullable_htmlentities($row['contact_archived_at']); if ($contact_archived_at) { - $contact_name_display = "
$contact_name
"; + $contact_name_display = "
$contact_name
"; } else { $contact_name_display = $contact_name; } @@ -268,7 +268,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); } $location_archived_at = nullable_htmlentities($row['location_archived_at']); if ($location_archived_at) { - $location_name_display = "
$location_name
"; + $location_name_display = "
$location_name
"; } else { $location_name_display = $location_name; } diff --git a/client_contact_edit_modal.php b/client_contact_edit_modal.php index 5bd6beee..74090ec8 100644 --- a/client_contact_edit_modal.php +++ b/client_contact_edit_modal.php @@ -122,14 +122,20 @@ '$contact_created_at' OR location_archived_at IS NULL) AND location_client_id = $client_id ORDER BY location_name ASC"); + $sql_locations = mysqli_query($mysqli, "SELECT * FROM locations WHERE location_id = $contact_location_id OR location_archived_at IS NULL AND location_client_id = $client_id ORDER BY location_name ASC"); while ($row = mysqli_fetch_array($sql_locations)) { $location_id_select = intval($row['location_id']); $location_name_select = nullable_htmlentities($row['location_name']); + $location_archived_at = nullable_htmlentities($row['location_archived_at']); + if ($location_archived_at) { + $location_name_select_display = "($location_name_select) - ARCHIVED"; + } else { + $location_name_select_display = $location_name_select; + } ?> + } ?> value=""> diff --git a/client_contacts.php b/client_contacts.php index a6a856be..f4d7e4a5 100644 --- a/client_contacts.php +++ b/client_contacts.php @@ -169,7 +169,11 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $contact_location_id = intval($row['contact_location_id']); $location_name = nullable_htmlentities($row['location_name']); if (empty($location_name)) { - $location_name_display = "-"; + $location_name = "-"; + } + $location_archived_at = nullable_htmlentities($row['location_archived_at']); + if ($location_archived_at) { + $location_name_display = "
$location_name
"; } else { $location_name_display = $location_name; } From 777637277b08fb1a5470296b6c690ec92b695bb6 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 27 Jan 2024 14:15:18 -0500 Subject: [PATCH 73/98] Fix Issue where if you edited first record that shared the same form input name like location then it would blank out the first record if edited this is fixed by adding bulk_ in front of the form Input names under the bulk modals not sure why this happens but this is the fix --- client_asset_bulk_assign_contact_modal.php | 2 +- client_asset_bulk_assign_location_modal.php | 2 +- client_asset_bulk_edit_status_modal.php | 2 +- client_contact_bulk_assign_location_modal.php | 2 +- client_contact_bulk_edit_phone_modal.php | 2 +- post/asset.php | 6 +++--- post/contact.php | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/client_asset_bulk_assign_contact_modal.php b/client_asset_bulk_assign_contact_modal.php index fd5dd915..c95978cd 100644 --- a/client_asset_bulk_assign_contact_modal.php +++ b/client_asset_bulk_assign_contact_modal.php @@ -16,7 +16,7 @@
- - - diff --git a/client_contact_bulk_assign_location_modal.php b/client_contact_bulk_assign_location_modal.php index 7b522026..404a545a 100644 --- a/client_contact_bulk_assign_location_modal.php +++ b/client_contact_bulk_assign_location_modal.php @@ -16,7 +16,7 @@
- - + diff --git a/post/asset.php b/post/asset.php index 7a5d4b38..68ac83e2 100644 --- a/post/asset.php +++ b/post/asset.php @@ -225,7 +225,7 @@ if (isset($_POST['bulk_assign_asset_location'])) { validateTechRole(); - $location_id = intval($_POST['location_id']); + $location_id = intval($_POST['bulk_location_id']); // Get Location name and client id for logging and Notification $sql = mysqli_query($mysqli,"SELECT location_name, location_client_id FROM locations WHERE location_id = $location_id"); @@ -264,7 +264,7 @@ if (isset($_POST['bulk_assign_asset_contact'])) { validateTechRole(); - $contact_id = intval($_POST['contact_id']); + $contact_id = intval($_POST['bulk_contact_id']); // Get Contact name and client id for logging and Notification $sql = mysqli_query($mysqli,"SELECT contact_name, contact_client_id FROM contacts WHERE contact_id = $contact_id"); @@ -303,7 +303,7 @@ if (isset($_POST['bulk_edit_asset_status'])) { validateTechRole(); - $status = sanitizeInput($_POST['status']); + $status = sanitizeInput($_POST['bulk_status']); // Get Selected Contacts Count $asset_count = count($_POST['asset_ids']); diff --git a/post/contact.php b/post/contact.php index 3c1d8640..7880e7a9 100644 --- a/post/contact.php +++ b/post/contact.php @@ -176,7 +176,7 @@ if (isset($_POST['bulk_assign_contact_location'])) { validateTechRole(); - $location_id = intval($_POST['location']); + $location_id = intval($_POST['bulk_location_id']); // Get Location name for logging and Notification $sql = mysqli_query($mysqli,"SELECT location_name, location_client_id FROM locations WHERE location_id = $location_id"); @@ -215,7 +215,7 @@ if (isset($_POST['bulk_edit_contact_phone'])) { validateTechRole(); - $phone = preg_replace("/[^0-9]/", '', $_POST['phone']); + $phone = preg_replace("/[^0-9]/", '', $_POST['bulk_phone']); // Get Selected Contacts Count $contact_count = count($_POST['contact_ids']); From b986f04a0c7401d38e917e9e27eb7b63a7f3cb85 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 28 Jan 2024 00:00:28 -0500 Subject: [PATCH 74/98] Add More Configurable variabled for Stripe including such as Flat Rate and Percent Fees, expense vendor and expense category update guest stripe pay to take advantage of these vars and updated settings --- database_updates.php | 18 +++++++-- database_version.php | 2 +- db.sql | 8 +++- get_settings.php | 8 +++- guest_pay_invoice_stripe.php | 14 +++---- post/setting.php | 23 +++-------- settings_online_payment.php | 74 ++++++++++++++++++++++++++++++++++-- 7 files changed, 112 insertions(+), 35 deletions(-) diff --git a/database_updates.php b/database_updates.php index cabf8b15..7d6107ca 100644 --- a/database_updates.php +++ b/database_updates.php @@ -1559,14 +1559,26 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.0.2'"); } + if (CURRENT_DATABASE_VERSION == '1.0.2') { + //Insert queries here required to update to DB version 1.0.3 + mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_stripe_expense_vendor` INT(11) NOT NULL DEFAULT 0 AFTER `config_stripe_account`"); + mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_stripe_expense_category` INT(11) NOT NULL DEFAULT 0 AFTER `config_stripe_expense_vendor`"); + mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_stripe_percentage_fee` DECIMAL(4,4) NOT NULL DEFAULT 0.029 AFTER `config_stripe_expense_category`"); + mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_stripe_flat_fee` DECIMAL(15,2) NOT NULL DEFAULT 0.30 AFTER `config_stripe_percentage_fee`"); + mysqli_query($mysqli, "ALTER TABLE `settings` CHANGE `config_stripe_account` `config_stripe_account` INT(11) NOT NULL DEFAULT 0"); + + //Then, update the database to the next sequential version + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.0.3'"); + } + // Be sure to change database_version.php to reflect the version you are updating to here // Please add this same comment block to the bottom of this file, and update the version number. // Uncomment Below Lines, to add additional database updates // - // if (CURRENT_DATABASE_VERSION == '1.0.2') { - // // Insert queries here required to update to DB version 1.0.3 + // if (CURRENT_DATABASE_VERSION == '1.0.3') { + // // Insert queries here required to update to DB version 1.0.4 // // Then, update the database to the next sequential version - // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.0.3'"); + // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.0.4'"); // } } else { diff --git a/database_version.php b/database_version.php index c3d5aa31..6ede6e49 100644 --- a/database_version.php +++ b/database_version.php @@ -5,5 +5,5 @@ * It is used in conjunction with database_updates.php */ -DEFINE("LATEST_DATABASE_VERSION", "1.0.2"); +DEFINE("LATEST_DATABASE_VERSION", "1.0.3"); diff --git a/db.sql b/db.sql index 15d7a5f5..81e80bb1 100644 --- a/db.sql +++ b/db.sql @@ -1270,7 +1270,11 @@ CREATE TABLE `settings` ( `config_stripe_enable` tinyint(1) NOT NULL DEFAULT 0, `config_stripe_publishable` varchar(255) DEFAULT NULL, `config_stripe_secret` varchar(255) DEFAULT NULL, - `config_stripe_account` tinyint(1) NOT NULL DEFAULT 0, + `config_stripe_account` int(11) NOT NULL DEFAULT 0, + `config_stripe_expense_vendor` int(11) NOT NULL DEFAULT 0, + `config_stripe_expense_category` int(11) NOT NULL DEFAULT 0, + `config_stripe_percentage_fee` decimal(4,4) NOT NULL DEFAULT 0.0290, + `config_stripe_flat_fee` decimal(15,2) NOT NULL DEFAULT 0.30, `config_stripe_client_pays_fees` tinyint(1) NOT NULL DEFAULT 0, `config_azure_client_id` varchar(200) DEFAULT NULL, `config_azure_client_secret` varchar(200) DEFAULT NULL, @@ -1756,4 +1760,4 @@ CREATE TABLE `vendors` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2024-01-15 13:07:46 +-- Dump completed on 2024-01-27 23:58:10 diff --git a/get_settings.php b/get_settings.php index 2a8cdeaa..51e098f1 100644 --- a/get_settings.php +++ b/get_settings.php @@ -79,11 +79,15 @@ $config_enable_alert_domain_expire = intval($row['config_enable_alert_domain_exp $config_send_invoice_reminders = intval($row['config_send_invoice_reminders']); $config_invoice_overdue_reminders = intval($row['config_invoice_overdue_reminders']); -// Online Payment +// Online Stripe Payment $config_stripe_enable = intval($row['config_stripe_enable']); $config_stripe_publishable = $row['config_stripe_publishable']; $config_stripe_secret = $row['config_stripe_secret']; -$config_stripe_account = $row['config_stripe_account']; +$config_stripe_account = intval($row['config_stripe_account']); +$config_stripe_expense_vendor = intval($row['config_stripe_expense_vendor']); +$config_stripe_expense_category = intval($row['config_stripe_expense_category']); +$config_stripe_percentage_fee = floatval($row['config_stripe_percentage_fee']); +$config_stripe_flat_fee = floatval($row['config_stripe_flat_fee']); $config_stripe_client_pays_fees = intval($row['config_stripe_client_pays_fees']); // Modules diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index 7793dd02..1bac7e49 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -15,11 +15,15 @@ function log_to_console($message) DEFINE("WORDING_PAYMENT_FAILED", "

There was an error verifying your payment. Please contact us for more information.

"); // Setup Stripe -$stripe_vars = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_stripe_enable, config_stripe_publishable, config_stripe_secret, config_stripe_account, config_stripe_client_pays_fees FROM settings WHERE company_id = 1")); +$stripe_vars = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_stripe_enable, config_stripe_publishable, config_stripe_secret, config_stripe_account, config_stripe_expense_vendor, config_stripe_expense_category, config_stripe_percentage_fee, config_stripe_flat_fee, config_stripe_client_pays_fees FROM settings WHERE company_id = 1")); $config_stripe_enable = intval($stripe_vars['config_stripe_enable']); $config_stripe_publishable = nullable_htmlentities($stripe_vars['config_stripe_publishable']); $config_stripe_secret = nullable_htmlentities($stripe_vars['config_stripe_secret']); $config_stripe_account = intval($stripe_vars['config_stripe_account']); +$config_stripe_expense_vendor = intval($row['config_stripe_expense_vendor']); +$config_stripe_expense_category = intval($row['config_stripe_expense_category']); +$config_stripe_percentage_fee = floatval($row['config_stripe_percentage_fee']); +$config_stripe_flat_fee = floatval($row['config_stripe_flat_fee']); $config_stripe_client_pays_fees = intval($stripe_vars['config_stripe_client_pays_fees']); // Check Stripe is configured @@ -85,10 +89,8 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent // Check config to see if client pays fees is enabled if ($config_stripe_client_pays_fees == 1) { $balance_before_fees = $balance_to_pay; - $percentage_fee = 0.029; - $flat_fee = 0.30; // Calculate the amount to charge the client - $balance_to_pay = ($balance_to_pay + $flat_fee) / (1 - $percentage_fee); + $balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); // Calculate the fee amount $gateway_fee = round($balance_to_pay - $balance_before_fees, 2); @@ -279,10 +281,8 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent // Check config to see if client pays fees is enabled if ($config_stripe_client_pays_fees == 1) { - $percentage_fee = 0.029; - $flat_fee = 0.30; // Calculate the amount to charge the client - $balance_to_pay = ($balance_to_pay + $flat_fee) / (1 - $percentage_fee); + $balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); } // Round balance to pay to 2 decimal places diff --git a/post/setting.php b/post/setting.php index 62ec9514..631b8af2 100644 --- a/post/setting.php +++ b/post/setting.php @@ -373,8 +373,13 @@ if (isset($_POST['edit_online_payment_settings'])) { $config_stripe_publishable = sanitizeInput($_POST['config_stripe_publishable']); $config_stripe_secret = sanitizeInput($_POST['config_stripe_secret']); $config_stripe_account = intval($_POST['config_stripe_account']); + $config_stripe_expense_vendor = intval($_POST['config_stripe_expense_vendor']); + $config_stripe_expense_category = intval($_POST['config_stripe_expense_category']); + $config_stripe_percentage_fee = floatval($_POST['config_stripe_percentage_fee']); + $config_stripe_flat_fee = floatval($_POST['config_stripe_flat_fee']); + $config_stripe_client_pays_fees = intval($_POST['config_stripe_client_pays_fees']); - mysqli_query($mysqli,"UPDATE settings SET config_stripe_enable = $config_stripe_enable, config_stripe_publishable = '$config_stripe_publishable', config_stripe_secret = '$config_stripe_secret', config_stripe_account = $config_stripe_account WHERE company_id = 1"); + mysqli_query($mysqli,"UPDATE settings SET config_stripe_enable = $config_stripe_enable, config_stripe_publishable = '$config_stripe_publishable', config_stripe_secret = '$config_stripe_secret', config_stripe_account = $config_stripe_account, config_stripe_expense_vendor = $config_stripe_expense_vendor, config_stripe_expense_category = $config_stripe_expense_category, config_stripe_percentage_fee = $config_stripe_percentage_fee, config_stripe_flat_fee = $config_stripe_flat_fee, config_stripe_client_pays_fees = $config_stripe_client_pays_fees WHERE company_id = 1"); //Logging mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Settings', log_action = 'Modify', log_description = '$session_name modified online payment settings', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); @@ -889,19 +894,3 @@ if (isset($_GET['update_db'])) { header("Location: " . $_SERVER["HTTP_REFERER"]); } - -if (isset($_POST['config_stripe_client_pays_fees'])) { - - validateAdminRole(); - - $config_stripe_client_pays_fees = intval($_POST['config_stripe_client_pays_fees']); - - mysqli_query($mysqli,"UPDATE settings SET config_stripe_client_pays_fees = $config_stripe_client_pays_fees WHERE company_id = 1"); - - //Logging - mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Settings', log_action = 'Modify', log_description = '$session_name modified stripe client pays fees', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); - - $_SESSION['alert_message'] = "Stripe client pays fees updated"; - - header("Location: " . $_SERVER["HTTP_REFERER"]); -} diff --git a/settings_online_payment.php b/settings_online_payment.php index 2c301713..fe674b39 100644 --- a/settings_online_payment.php +++ b/settings_online_payment.php @@ -21,7 +21,8 @@ require_once "inc_all_settings.php"; - +
"> +
@@ -44,7 +45,7 @@ require_once "inc_all_settings.php";
- +
@@ -65,15 +66,82 @@ require_once "inc_all_settings.php";
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+
value="1" id="clientPaysFeesSwitch"> +
+
+ +
+
+ +
+ +
+
- +
+ +
+
+ +
+ +
+
+ +

From 3d3bb6a43612b4e331566f0954666cbd51f52a20 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 28 Jan 2024 01:49:49 -0500 Subject: [PATCH 75/98] Feature: Stripe Payment now logs an expense to the selected account --- guest_pay_invoice_stripe.php | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index 1bac7e49..1fc6c300 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -20,10 +20,10 @@ $config_stripe_enable = intval($stripe_vars['config_stripe_enable']); $config_stripe_publishable = nullable_htmlentities($stripe_vars['config_stripe_publishable']); $config_stripe_secret = nullable_htmlentities($stripe_vars['config_stripe_secret']); $config_stripe_account = intval($stripe_vars['config_stripe_account']); -$config_stripe_expense_vendor = intval($row['config_stripe_expense_vendor']); -$config_stripe_expense_category = intval($row['config_stripe_expense_category']); -$config_stripe_percentage_fee = floatval($row['config_stripe_percentage_fee']); -$config_stripe_flat_fee = floatval($row['config_stripe_flat_fee']); +$config_stripe_expense_vendor = intval($stripe_vars['config_stripe_expense_vendor']); +$config_stripe_expense_category = intval($stripe_vars['config_stripe_expense_category']); +$config_stripe_percentage_fee = floatval($stripe_vars['config_stripe_percentage_fee']); +$config_stripe_flat_fee = floatval($stripe_vars['config_stripe_flat_fee']); $config_stripe_client_pays_fees = intval($stripe_vars['config_stripe_client_pays_fees']); // Check Stripe is configured @@ -86,16 +86,14 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent $amount_paid = floatval($row['amount_paid']); $balance_to_pay = $invoice_amount - $amount_paid; - // Check config to see if client pays fees is enabled if ($config_stripe_client_pays_fees == 1) { - $balance_before_fees = $balance_to_pay; - // Calculate the amount to charge the client - $balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); - // Calculate the fee amount - $gateway_fee = round($balance_to_pay - $balance_before_fees, 2); + $balance_before_fees = $balance_to_pay; + // Calculate the amount to charge the client + $balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); + // Calculate the fee amount + $gateway_fee = round($balance_to_pay - $balance_before_fees, 2); + } - } - //Round balance to pay to 2 decimal places $balance_to_pay = round($balance_to_pay, 2); @@ -279,10 +277,19 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent $amount_paid_previously = $row['amount_paid']; $balance_to_pay = $invoice_amount - $amount_paid_previously; - // Check config to see if client pays fees is enabled + // Check config to see if client pays fees is enabled or if should expense it if ($config_stripe_client_pays_fees == 1) { // Calculate the amount to charge the client $balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); + } else { + $balance_before_fees = $balance_to_pay; + // Calculate the amount to charge the client + $balance_to_not_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); + // Calculate the fee amount + $gateway_expense_fee = round($balance_to_not_pay - $balance_before_fees, 2); + + // Add Expense + mysqli_query($mysqli,"INSERT INTO expenses SET expense_date = '$pi_date', expense_amount = $gateway_expense_fee, expense_currency_code = '$invoice_currency_code', expense_account_id = $config_stripe_account, expense_vendor_id = $config_stripe_expense_vendor, expense_client_id = $client_id, expense_category_id = $config_stripe_expense_category, expense_description = 'Stripe Transaction for Invoice $invoice_prefix$invoice_number In the Amount of $balance_to_pay', expense_reference = 'Stripe - $pi_id'"); } // Round balance to pay to 2 decimal places @@ -366,7 +373,6 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent // Redirect user to invoice header('Location: //' . $config_base_url . '/guest_view_invoice.php?invoice_id=' . $pi_invoice_id . '&url_key=' . $invoice_url_key); - } else { echo "

Oops, something went wrong! Please raise a ticket if you believe this is an error.

"; } From 56c138fb12870d0044e3ca64ca7ab79446801900 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 28 Jan 2024 02:08:11 -0500 Subject: [PATCH 76/98] cleanup --- guest_pay_invoice_stripe.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index 1fc6c300..c89d0b3a 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -2,15 +2,13 @@ require_once 'guest_header.php'; -function log_to_console($message) -{ +function log_to_console($message) { $message = date("H:i:s") . " - $message - ".PHP_EOL; print($message); flush(); ob_flush(); } - // Define wording DEFINE("WORDING_PAYMENT_FAILED", "

There was an error verifying your payment. Please contact us for more information.

"); @@ -379,4 +377,3 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent require_once 'guest_footer.php'; - From 063d042378c36eb0073f5cfa7b05cf209e5e62f4 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 28 Jan 2024 14:45:43 -0500 Subject: [PATCH 77/98] Update guest_ajax.php with the new stripe vars --- guest_ajax.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/guest_ajax.php b/guest_ajax.php index 44402413..b80560d5 100644 --- a/guest_ajax.php +++ b/guest_ajax.php @@ -54,6 +54,8 @@ if (isset($_GET['stripe_create_pi'])) { $config_sql = mysqli_query($mysqli, "SELECT * FROM settings WHERE company_id = 1"); $config_row = mysqli_fetch_array($config_sql); $config_stripe_client_pays_fees = intval($config_row['config_stripe_client_pays_fees']); + $config_stripe_percentage_fee = floatval($config_row['config_stripe_percentage_fee']); + $config_stripe_flat_fee = floatval($config_row['config_stripe_flat_fee']); // Add up all the payments for the invoice and get the total amount paid to the invoice $sql_amount_paid = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS amount_paid FROM payments WHERE payment_invoice_id = $invoice_id"); @@ -63,11 +65,8 @@ if (isset($_GET['stripe_create_pi'])) { // Check config to see if client pays fees is enabled if ($config_stripe_client_pays_fees == 1) { - // Get fees from config - $percentage_fee = 0.029; // Default Stripe fee - $flat_fee = 0.30; // Default Stripe fee // Calculate the amount to charge the client - $balance_to_pay = ($balance_to_pay + $flat_fee) / (1 - $percentage_fee); + $balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); } $balance_to_pay = round($balance_to_pay, 2); From 9bd924dc672a6ddbe07a02fb15c7c1116ec52641 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 28 Jan 2024 14:54:28 -0500 Subject: [PATCH 78/98] Only create a Stripe Expense if client pays fee is off, a stripe expense vendor and expense category is selected in settings --- guest_pay_invoice_stripe.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index c89d0b3a..244e088d 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -279,7 +279,10 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent if ($config_stripe_client_pays_fees == 1) { // Calculate the amount to charge the client $balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); - } else { + } + + // Check to see if Expense Fields are configured and client pays fee is off then create expense + if ($config_stripe_client_pays_fees == 0 && $config_stripe_expense_vendor > 0 && $config_stripe_expense_category > 0) { $balance_before_fees = $balance_to_pay; // Calculate the amount to charge the client $balance_to_not_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); From 5afacf78cf14b8e1d01f9e26b13096dc6960f09a Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 28 Jan 2024 15:23:58 -0500 Subject: [PATCH 79/98] Convert strip Percentage Decimal from decimal vlaue to percentage value on view form and then reconvert from Percent back to Decimal value on POST --- post/setting.php | 2 +- settings_online_payment.php | 119 +++++++++++++++++++----------------- 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/post/setting.php b/post/setting.php index 631b8af2..220a132f 100644 --- a/post/setting.php +++ b/post/setting.php @@ -375,7 +375,7 @@ if (isset($_POST['edit_online_payment_settings'])) { $config_stripe_account = intval($_POST['config_stripe_account']); $config_stripe_expense_vendor = intval($_POST['config_stripe_expense_vendor']); $config_stripe_expense_category = intval($_POST['config_stripe_expense_category']); - $config_stripe_percentage_fee = floatval($_POST['config_stripe_percentage_fee']); + $config_stripe_percentage_fee = floatval($_POST['config_stripe_percentage_fee']) / 100; $config_stripe_flat_fee = floatval($_POST['config_stripe_flat_fee']); $config_stripe_client_pays_fees = intval($_POST['config_stripe_client_pays_fees']); diff --git a/settings_online_payment.php b/settings_online_payment.php index fe674b39..33425dfb 100644 --- a/settings_online_payment.php +++ b/settings_online_payment.php @@ -23,7 +23,6 @@ require_once "inc_all_settings.php";
"> -
@@ -67,67 +66,13 @@ require_once "inc_all_settings.php";
-
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
- value="1" id="clientPaysFeesSwitch"> - -
-
-
- +
@@ -137,10 +82,70 @@ require_once "inc_all_settings.php";
- +
+
+ +
+ value="1" id="clientPaysFeesSwitch"> + +
+
+ +
"> + +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+
From f8dc67fbf92fd86c772291865d0c24d687d9cbbf Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 28 Jan 2024 15:55:05 -0500 Subject: [PATCH 80/98] Added Gateway Fee to the Guest View Invoice and minor fix for ticket counter per Pull Request #866 also added stripe flat and percent config vars to guest view invoice. Note We do not need to merge Pull #866 as all changes nessessary have been implented manually --- guest_view_invoice.php | 31 ++++++++++++++++++++++--------- js/ticket_time_tracking.js | 10 ++-------- settings_online_payment.php | 4 ++-- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/guest_view_invoice.php b/guest_view_invoice.php index f1ee664b..18f5c6ba 100644 --- a/guest_view_invoice.php +++ b/guest_view_invoice.php @@ -80,6 +80,8 @@ if (!empty($company_logo)) { $company_locale = nullable_htmlentities($row['company_locale']); $config_invoice_footer = nullable_htmlentities($row['config_invoice_footer']); $config_stripe_enable = intval($row['config_stripe_enable']); +$config_stripe_percentage_fee = floatval($row['config_stripe_percentage_fee']); +$config_stripe_flat_fee = floatval($row['config_stripe_flat_fee']); $config_stripe_client_pays_fees = intval($row['config_stripe_client_pays_fees']); //Set Currency Format @@ -109,16 +111,15 @@ $sql_amount_paid = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS amount_p $row = mysqli_fetch_array($sql_amount_paid); $amount_paid = floatval($row['amount_paid']); -$balance = $invoice_amount - $amount_paid; - // Check config to see if client pays fees is enabled if ($config_stripe_client_pays_fees == 1) { - $percentage_fee = 0.029; - $flat_fee = 0.30; - // Calculate the amount to charge the client - $balance_to_pay = ($balance + $flat_fee) / (1 - $percentage_fee); - $stripe_fee = $balance_to_pay - $balance; - } + // Calculate the amount to charge the client + $balance_to_pay = ($balance + $config_stripe_flat_fee) / (1 - $coinfig_stripe_percentage_fee); + $stripe_fee = $balance_to_pay - $balance; +} else { + $gateway_fee = 0; + $balance = $invoice_amount - $amount_paid; +} //check to see if overdue $invoice_color = $invoice_badge_color; // Default @@ -297,7 +298,19 @@ $sql_invoice_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE it
Paid
Gateway Fee
Balance
- "> - - - - - - - - - +
- Name - - Created - - Last Update - - Action -
+ "> + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - -
+
+ +
+
+ Name + + Created + + Last Update + + Action +
+
+ +
+
+ +
+
+ +
+
+ +
- -
-
- -
-
- -
-
-
+ +
+
+
+ + @@ -270,6 +294,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); + + + diff --git a/client_files.php b/client_files.php index 196a11e6..86231d60 100644 --- a/client_files.php +++ b/client_files.php @@ -157,9 +157,21 @@ $num_of_files = mysqli_num_rows($sql);
-
+
"> "> + + +
@@ -213,96 +225,109 @@ $num_of_files = mysqli_num_rows($sql); -
- - - "> - - - - - - - - - - + +
+
NameUploadedAction
+ + "> - - - + + + + + + + - require "client_file_move_modal.php"; + + + + + + + - + require "client_file_move_modal.php"; -
" target="_blank" class="text-secondary"> - +
+
NameUploadedAction
+
+ +
+
" target="_blank" class="text-secondary"> + +
-
- + } + ?> + + + + + + @@ -314,6 +339,8 @@ $num_of_files = mysqli_num_rows($sql); + + $document_count documents to the folder $folder_name"; + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_POST['link_file_to_document'])) { validateTechRole(); diff --git a/post/file.php b/post/file.php index 1f702c19..46d24668 100644 --- a/post/file.php +++ b/post/file.php @@ -143,3 +143,41 @@ if (isset($_POST['delete_file'])) { header("Location: " . $_SERVER["HTTP_REFERER"]); } + +if (isset($_POST['bulk_move_files'])) { + + validateTechRole(); + + $folder_id = intval($_POST['bulk_folder_id']); + + // Get folder name for logging and Notification + $sql = mysqli_query($mysqli,"SELECT folder_name, folder_client_id FROM folders WHERE folder_id = $folder_id"); + $row = mysqli_fetch_array($sql); + $folder_name = sanitizeInput($row['folder_name']); + $client_id = intval($row['folder_client_id']); + + // Get Selected file Count + $file_count = count($_POST['file_ids']); + + // Move Documents to Folder Loop + if (!empty($_POST['file_ids'])) { + foreach($_POST['file_ids'] as $file_id) { + $file_id = intval($file_id); + // Get file name for logging + $sql = mysqli_query($mysqli,"SELECT file_name FROM files WHERE file_id = $file_id"); + $row = mysqli_fetch_array($sql); + $file_name = sanitizeInput($row['file_name']); + + // file move query + mysqli_query($mysqli,"UPDATE files SET file_folder_id = $folder_id WHERE file_id = $file_id"); + + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'File', log_action = 'Move', log_description = '$session_name moved file $file_name to folder $folder_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $file_id"); + } + } + + $_SESSION['alert_message'] = "You moved $file_count files to the folder $folder_name"; + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} From c6f1a25692576bc094261e016b46aa88d148fb67 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Tue, 30 Jan 2024 14:54:00 -0500 Subject: [PATCH 85/98] Feature: Added Bulk Set Priority on Tickets --- post/ticket.php | 43 +++++++++++++++++++++++++++++ ticket_bulk_edit_priority_modal.php | 36 ++++++++++++++++++++++++ tickets.php | 5 ++++ 3 files changed, 84 insertions(+) create mode 100644 ticket_bulk_edit_priority_modal.php diff --git a/post/ticket.php b/post/ticket.php index a2491e3b..4623a4fc 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -570,6 +570,49 @@ if (isset($_POST['bulk_assign_ticket'])) { } +if (isset($_POST['bulk_edit_ticket_priority'])) { + + // Role check + validateTechRole(); + + // POST variables + $priority = sanitizeInput($_POST['bulk_priority']); + + // Get a Ticket Count + $ticket_count = count($_POST['ticket_ids']); + + // Assign Tech to Selected Tickets + if (!empty($_POST['ticket_ids'])) { + foreach($_POST['ticket_ids'] as $ticket_id) { + $ticket_id = intval($ticket_id); + + $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id"); + $row = mysqli_fetch_array($sql); + + $ticket_prefix = sanitizeInput($row['ticket_prefix']); + $ticket_number = intval($row['ticket_number']); + $ticket_status = sanitizeInput($row['ticket_status']); + $ticket_subject = sanitizeInput($row['ticket_subject']); + $current_ticket_priority = sanitizeInput($row['ticket_priority']); + $client_id = intval($row['ticket_client_id']); + + // Update ticket & insert reply + mysqli_query($mysqli,"UPDATE tickets SET ticket_priority = '$priority' WHERE ticket_id = $ticket_id"); + + mysqli_query($mysqli,"INSERT INTO ticket_replies SET ticket_reply = '$session_name updated the priority from $current_ticket_priority to $priority', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + + // Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Edit', log_description = '$session_name updated the priority on ticket $ticket_prefix$ticket_number - $ticket_subject from $current_ticket_priority to $priority', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); + + } // End For Each Ticket ID Loop + } + + $_SESSION['alert_message'] = "You updated the priority for $ticket_count Tickets to $priority"; + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_POST['add_ticket_reply'])) { validateTechRole(); diff --git a/ticket_bulk_edit_priority_modal.php b/ticket_bulk_edit_priority_modal.php new file mode 100644 index 00000000..3b3582a9 --- /dev/null +++ b/ticket_bulk_edit_priority_modal.php @@ -0,0 +1,36 @@ + diff --git a/tickets.php b/tickets.php index 5c14086d..dad20984 100644 --- a/tickets.php +++ b/tickets.php @@ -143,6 +143,10 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); Assign Tech + + + Update Priority + @@ -442,6 +446,7 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); + From 731b60b07a4ca3d77f32de9a4283ed16a9117433 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Tue, 30 Jan 2024 16:04:29 -0500 Subject: [PATCH 86/98] Feature: Added Bulk Ticket Closure --- post/ticket.php | 108 ++++++++++++++++++++++++++++++++++++ ticket_bulk_close_modal.php | 23 ++++++++ tickets.php | 5 ++ 3 files changed, 136 insertions(+) create mode 100644 ticket_bulk_close_modal.php diff --git a/post/ticket.php b/post/ticket.php index 4623a4fc..f4cbc635 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -613,6 +613,114 @@ if (isset($_POST['bulk_edit_ticket_priority'])) { } +if (isset($_POST['bulk_close_tickets'])) { + + // Role check + validateTechRole(); + + // POST variables + $details = mysqli_escape_string($mysqli, $_POST['bulk_details']); + + // Get a Ticket Count + $ticket_count = count($_POST['ticket_ids']); + + // Assign Tech to Selected Tickets + if (!empty($_POST['ticket_ids'])) { + foreach($_POST['ticket_ids'] as $ticket_id) { + $ticket_id = intval($ticket_id); + + $sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id"); + $row = mysqli_fetch_array($sql); + + $ticket_prefix = sanitizeInput($row['ticket_prefix']); + $ticket_number = intval($row['ticket_number']); + $ticket_status = sanitizeInput($row['ticket_status']); + $ticket_subject = sanitizeInput($row['ticket_subject']); + $current_ticket_priority = sanitizeInput($row['ticket_priority']); + $client_id = intval($row['ticket_client_id']); + + // Update ticket & insert reply + mysqli_query($mysqli,"UPDATE tickets SET ticket_status = 'Closed' WHERE ticket_id = $ticket_id"); + + mysqli_query($mysqli,"INSERT INTO ticket_replies SET ticket_reply = '$details', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + + // Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Close', log_description = '$session_name closed $ticket_prefix$ticket_number - $ticket_subject in a bulk action', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); + + // Client notification email + if (!empty($config_smtp_host) && $config_ticket_client_general_notifications == 1) { + + // Get Contact details + $ticket_sql = mysqli_query($mysqli,"SELECT contact_name, contact_email FROM tickets + LEFT JOIN contacts ON ticket_contact_id = contact_id + WHERE ticket_id = $ticket_id + "); + $row = mysqli_fetch_array($ticket_sql); + + $contact_name = sanitizeInput($row['contact_name']); + $contact_email = sanitizeInput($row['contact_email']); + + // Sanitize Config vars from get_settings.php + $config_ticket_from_name = sanitizeInput($config_ticket_from_name); + $config_ticket_from_email = sanitizeInput($config_ticket_from_email); + $config_base_url = sanitizeInput($config_base_url); + + // Get Company Info + $sql = mysqli_query($mysqli,"SELECT company_name, company_phone FROM companies WHERE company_id = 1"); + $row = mysqli_fetch_array($sql); + $company_name = sanitizeInput($row['company_name']); + $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); + + // Check email valid + if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { + + $data = []; + + $subject = "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"; + $body = "Hello $contact_name,

Your ticket regarding \"$ticket_subject\" has been closed.

$details

We hope the issue was resolved to your satisfaction. If you need further assistance, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + + // Email Ticket Contact + // Queue Mail + + $data[] = [ + 'from' => $config_ticket_from_email, + 'from_name' => $config_ticket_from_name, + 'recipient' => $contact_email, + 'recipient_name' => $contact_name, + 'subject' => $subject, + 'body' => $body + ]; + + // Also Email all the watchers + $sql_watchers = mysqli_query($mysqli, "SELECT watcher_email FROM ticket_watchers WHERE watcher_ticket_id = $ticket_id"); + $body .= "

----------------------------------------
DO NOT REPLY - YOU ARE RECEIVING THIS EMAIL BECAUSE YOU ARE A WATCHER"; + while ($row = mysqli_fetch_array($sql_watchers)) { + $watcher_email = sanitizeInput($row['watcher_email']); + + // Queue Mail + $data[] = [ + 'from' => $config_ticket_from_email, + 'from_name' => $config_ticket_from_name, + 'recipient' => $watcher_email, + 'recipient_name' => $watcher_email, + 'subject' => $subject, + 'body' => $body + ]; + } + addToMailQueue($mysqli, $data); + } + + } + // End Mail IF + } // End Loop + } // End Array Empty Check + + $_SESSION['alert_message'] = "You closed $ticket_count Tickets"; + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_POST['add_ticket_reply'])) { validateTechRole(); diff --git a/ticket_bulk_close_modal.php b/ticket_bulk_close_modal.php new file mode 100644 index 00000000..13555988 --- /dev/null +++ b/ticket_bulk_close_modal.php @@ -0,0 +1,23 @@ + diff --git a/tickets.php b/tickets.php index dad20984..1ba9c2c9 100644 --- a/tickets.php +++ b/tickets.php @@ -147,6 +147,10 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); Update Priority + + + Close + @@ -447,6 +451,7 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); + From 80fdad81e943dca981132705bb67a8ec06fefa1f Mon Sep 17 00:00:00 2001 From: johnnyq Date: Tue, 30 Jan 2024 16:25:27 -0500 Subject: [PATCH 87/98] Fix Not being able to Enable Stripe Pay on Updated or new Installs --- settings_online_payment.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/settings_online_payment.php b/settings_online_payment.php index 76201245..3345d69f 100644 --- a/settings_online_payment.php +++ b/settings_online_payment.php @@ -49,7 +49,7 @@ require_once "inc_all_settings.php";
- - + Date: Tue, 30 Jan 2024 16:40:19 -0500 Subject: [PATCH 88/98] Fix issue with adding slashes to close email config_from_name vars --- post/ticket.php | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index f4cbc635..b7ec8c75 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -661,9 +661,9 @@ if (isset($_POST['bulk_close_tickets'])) { $contact_email = sanitizeInput($row['contact_email']); // Sanitize Config vars from get_settings.php - $config_ticket_from_name = sanitizeInput($config_ticket_from_name); - $config_ticket_from_email = sanitizeInput($config_ticket_from_email); - $config_base_url = sanitizeInput($config_base_url); + $from_name = sanitizeInput($config_ticket_from_name); + $from_email = sanitizeInput($config_ticket_from_email); + $base_url = sanitizeInput($config_base_url); // Get Company Info $sql = mysqli_query($mysqli,"SELECT company_name, company_phone FROM companies WHERE company_id = 1"); @@ -677,14 +677,14 @@ if (isset($_POST['bulk_close_tickets'])) { $data = []; $subject = "Ticket closed - [$ticket_prefix$ticket_number] - $ticket_subject | (do not reply)"; - $body = "Hello $contact_name,

Your ticket regarding \"$ticket_subject\" has been closed.

$details

We hope the issue was resolved to your satisfaction. If you need further assistance, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; + $body = "Hello $contact_name,

Your ticket regarding \"$ticket_subject\" has been closed.

$details

We hope the issue was resolved to your satisfaction. If you need further assistance, please raise a new ticket using the below details. Please do not reply to this email.

Ticket: $ticket_prefix$ticket_number
Subject: $ticket_subject
Portal: https://$base_url/portal/ticket.php?id=$ticket_id

--
$company_name - Support
$config_ticket_from_email
$company_phone"; // Email Ticket Contact // Queue Mail $data[] = [ - 'from' => $config_ticket_from_email, - 'from_name' => $config_ticket_from_name, + 'from' => $from_email, + 'from_name' => $from_name, 'recipient' => $contact_email, 'recipient_name' => $contact_name, 'subject' => $subject, @@ -699,8 +699,8 @@ if (isset($_POST['bulk_close_tickets'])) { // Queue Mail $data[] = [ - 'from' => $config_ticket_from_email, - 'from_name' => $config_ticket_from_name, + 'from' => $from_email, + 'from_name' => $from_name, 'recipient' => $watcher_email, 'recipient_name' => $watcher_email, 'subject' => $subject, @@ -710,8 +710,7 @@ if (isset($_POST['bulk_close_tickets'])) { addToMailQueue($mysqli, $data); } - } - // End Mail IF + } // End Mail IF } // End Loop } // End Array Empty Check From da98f847748bf2e02f7cedf07c1f1f6a6c3dda0e Mon Sep 17 00:00:00 2001 From: johnnyq Date: Tue, 30 Jan 2024 16:55:04 -0500 Subject: [PATCH 89/98] Move the MailQueue Action out of the get email loop on close Bulk Tickets this prevent unessessary mysql connections --- post/ticket.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index b7ec8c75..57986b27 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -707,9 +707,8 @@ if (isset($_POST['bulk_close_tickets'])) { 'body' => $body ]; } - addToMailQueue($mysqli, $data); } - + addToMailQueue($mysqli, $data); } // End Mail IF } // End Loop } // End Array Empty Check From 00197cef965ba8d2dac028c89cb01f6546511ce5 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 31 Jan 2024 13:53:25 -0500 Subject: [PATCH 90/98] feat: Bulk Set Contact Department / Group --- client_contact_bulk_edit_department_modal.php | 31 +++++++++++++++++ client_contacts.php | 5 +++ post/contact.php | 34 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 client_contact_bulk_edit_department_modal.php diff --git a/client_contact_bulk_edit_department_modal.php b/client_contact_bulk_edit_department_modal.php new file mode 100644 index 00000000..ae6192cb --- /dev/null +++ b/client_contact_bulk_edit_department_modal.php @@ -0,0 +1,31 @@ + \ No newline at end of file diff --git a/client_contacts.php b/client_contacts.php index f4d7e4a5..e58e237e 100644 --- a/client_contacts.php +++ b/client_contacts.php @@ -79,6 +79,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); Set Phone Number + + + Set Department + @@ -273,6 +277,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); + diff --git a/post/contact.php b/post/contact.php index 7880e7a9..18f12550 100644 --- a/post/contact.php +++ b/post/contact.php @@ -245,6 +245,40 @@ if (isset($_POST['bulk_edit_contact_phone'])) { } +if (isset($_POST['bulk_edit_contact_department'])) { + + validateTechRole(); + + $department = sanitizeInput($_POST['bulk_department']); + + // Get Selected Contacts Count + $contact_count = count($_POST['contact_ids']); + + // Assign Location to Selected Contacts + if (!empty($_POST['contact_ids'])) { + foreach($_POST['contact_ids'] as $contact_id) { + $contact_id = intval($contact_id); + + // Get Contact Details for Logging + $sql = mysqli_query($mysqli,"SELECT contact_name, contact_client_id FROM contacts WHERE contact_id = $contact_id"); + $row = mysqli_fetch_array($sql); + $contact_name = sanitizeInput($row['contact_name']); + $client_id = intval($row['contact_client_id']); + + mysqli_query($mysqli,"UPDATE contacts SET contact_department = '$department' WHERE contact_id = $contact_id"); + + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Contact', log_action = 'Modify', log_description = '$session_name set Department to $department for $contact_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $contact_id"); + + } // End Assign Location Loop + + $_SESSION['alert_message'] = "You set the Department to $department for $contact_count contacts"; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_GET['anonymize_contact'])) { validateAdminRole(); From dad2a7d376fc3830ff1cd8115a438466f8258c33 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 31 Jan 2024 13:56:00 -0500 Subject: [PATCH 91/98] Update Contact Department wording to also include group changed icon from building to users which is more suitable --- client_contact_add_modal.php | 6 +++--- client_contact_edit_modal.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client_contact_add_modal.php b/client_contact_add_modal.php index 58d1892f..b5942535 100644 --- a/client_contact_add_modal.php +++ b/client_contact_add_modal.php @@ -64,12 +64,12 @@
- +
- +
- +
diff --git a/client_contact_edit_modal.php b/client_contact_edit_modal.php index 74090ec8..bea22ae9 100644 --- a/client_contact_edit_modal.php +++ b/client_contact_edit_modal.php @@ -66,12 +66,12 @@
- +
- +
- +
From 5818c7fe18494319f9d72e55ef2514a53c2a4075 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 31 Jan 2024 14:23:47 -0500 Subject: [PATCH 92/98] feat. Added Contact Roles to Bulk Actions --- client_contact_bulk_edit_role_modal.php | 49 +++++++++++++++++++++++++ client_contacts.php | 5 +++ post/contact.php | 36 ++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 client_contact_bulk_edit_role_modal.php diff --git a/client_contact_bulk_edit_role_modal.php b/client_contact_bulk_edit_role_modal.php new file mode 100644 index 00000000..f5b59899 --- /dev/null +++ b/client_contact_bulk_edit_role_modal.php @@ -0,0 +1,49 @@ + \ No newline at end of file diff --git a/client_contacts.php b/client_contacts.php index e58e237e..1900748c 100644 --- a/client_contacts.php +++ b/client_contacts.php @@ -83,6 +83,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); Set Department + + + Set Roles + @@ -278,6 +282,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); + diff --git a/post/contact.php b/post/contact.php index 18f12550..7d4df316 100644 --- a/post/contact.php +++ b/post/contact.php @@ -279,6 +279,42 @@ if (isset($_POST['bulk_edit_contact_department'])) { } +if (isset($_POST['bulk_edit_contact_role'])) { + + validateTechRole(); + + $contact_important = intval($_POST['bulk_contact_important']); + $contact_billing = intval($_POST['bulk_contact_billing']); + $contact_technical = intval($_POST['bulk_contact_technical']); + + // Get Selected Contacts Count + $contact_count = count($_POST['contact_ids']); + + // Assign Location to Selected Contacts + if (!empty($_POST['contact_ids'])) { + foreach($_POST['contact_ids'] as $contact_id) { + $contact_id = intval($contact_id); + + // Get Contact Details for Logging + $sql = mysqli_query($mysqli,"SELECT contact_name, contact_client_id FROM contacts WHERE contact_id = $contact_id"); + $row = mysqli_fetch_array($sql); + $contact_name = sanitizeInput($row['contact_name']); + $client_id = intval($row['contact_client_id']); + + mysqli_query($mysqli,"UPDATE contacts SET contact_important = $contact_important, contact_billing = $contact_billing, contact_technical = $contact_technical WHERE contact_id = $contact_id"); + + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Contact', log_action = 'Modify', log_description = '$session_name updated $contact_name role', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $contact_id"); + + } // End Assign Location Loop + + $_SESSION['alert_message'] = "You updated roles for $contact_count contacts"; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); + +} + if (isset($_GET['anonymize_contact'])) { validateAdminRole(); From 7975505823eddf3aade67de0df84c745433cfa01 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 31 Jan 2024 14:49:25 -0500 Subject: [PATCH 93/98] feat. Updated Bulk Close Ticket to allow for a Private Note instead of public --- post/ticket.php | 10 ++++++++-- ticket_bulk_close_modal.php | 10 ++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/post/ticket.php b/post/ticket.php index 57986b27..2749badc 100644 --- a/post/ticket.php +++ b/post/ticket.php @@ -620,6 +620,12 @@ if (isset($_POST['bulk_close_tickets'])) { // POST variables $details = mysqli_escape_string($mysqli, $_POST['bulk_details']); + $private_note = intval($_POST['bulk_private_note']); + if($private_note == 1){ + $ticket_reply_type = 'Internal'; + } else { + $ticket_reply_type = 'Public'; + } // Get a Ticket Count $ticket_count = count($_POST['ticket_ids']); @@ -642,13 +648,13 @@ if (isset($_POST['bulk_close_tickets'])) { // Update ticket & insert reply mysqli_query($mysqli,"UPDATE tickets SET ticket_status = 'Closed' WHERE ticket_id = $ticket_id"); - mysqli_query($mysqli,"INSERT INTO ticket_replies SET ticket_reply = '$details', ticket_reply_type = 'Internal', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); + mysqli_query($mysqli,"INSERT INTO ticket_replies SET ticket_reply = '$details', ticket_reply_type = '$ticket_reply_type', ticket_reply_time_worked = '00:01:00', ticket_reply_by = $session_user_id, ticket_reply_ticket_id = $ticket_id"); // Logging mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Close', log_description = '$session_name closed $ticket_prefix$ticket_number - $ticket_subject in a bulk action', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $ticket_id"); // Client notification email - if (!empty($config_smtp_host) && $config_ticket_client_general_notifications == 1) { + if (!empty($config_smtp_host) && $config_ticket_client_general_notifications == 1 && $private_note == 0) { // Get Contact details $ticket_sql = mysqli_query($mysqli,"SELECT contact_name, contact_email FROM tickets diff --git a/ticket_bulk_close_modal.php b/ticket_bulk_close_modal.php index 13555988..51fa9c3b 100644 --- a/ticket_bulk_close_modal.php +++ b/ticket_bulk_close_modal.php @@ -9,10 +9,20 @@ @@ -452,6 +456,7 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); + From 96ff92d07087cd7d08a19a7e552cbd71c27ff0f9 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 31 Jan 2024 17:09:35 -0500 Subject: [PATCH 95/98] Feature: Bulk Edit Category, Client and Account for expenses --- expense_bulk_edit_account_modal.php | 58 +++++++ expense_bulk_edit_category_modal.php | 42 +++++ expense_bulk_edit_client_modal.php | 43 +++++ expenses.php | 237 +++++++++++++++------------ post/expense.php | 107 ++++++++++++ 5 files changed, 386 insertions(+), 101 deletions(-) create mode 100644 expense_bulk_edit_account_modal.php create mode 100644 expense_bulk_edit_category_modal.php create mode 100644 expense_bulk_edit_client_modal.php diff --git a/expense_bulk_edit_account_modal.php b/expense_bulk_edit_account_modal.php new file mode 100644 index 00000000..43c930b7 --- /dev/null +++ b/expense_bulk_edit_account_modal.php @@ -0,0 +1,58 @@ + diff --git a/expense_bulk_edit_category_modal.php b/expense_bulk_edit_category_modal.php new file mode 100644 index 00000000..e0e79da7 --- /dev/null +++ b/expense_bulk_edit_category_modal.php @@ -0,0 +1,42 @@ + diff --git a/expense_bulk_edit_client_modal.php b/expense_bulk_edit_client_modal.php new file mode 100644 index 00000000..2d069289 --- /dev/null +++ b/expense_bulk_edit_client_modal.php @@ -0,0 +1,43 @@ + diff --git a/expenses.php b/expenses.php index 8d76408f..ce2126e8 100644 --- a/expenses.php +++ b/expenses.php @@ -48,7 +48,25 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
+
@@ -91,117 +109,134 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
- - "> - - - - - - - - - - - - - +
+
DateVendorCategoryDescriptionAmountAccountClientAction
+ "> + + + + + + + + + + + + + + "; + } + + ?> + + + + + + + + + + + + + + "; } ?> - - - - - - - - - - - - - - -
+
+ +
+
DateVendorCategoryDescriptionAmountAccountClientAction
+
+ +
+
+ +
- -
-
+ + + + + + + + + $category_name to $expense_count expenses"; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); +} + +if (isset($_POST['bulk_edit_expense_account'])) { + + $account_id = intval($_POST['bulk_account_id']); + + // Get Account name for logging and Notification + $sql = mysqli_query($mysqli,"SELECT account_name FROM accounts WHERE account_id = $account_id"); + $row = mysqli_fetch_array($sql); + $account_name = sanitizeInput($row['account_name']); + + // Get Selected Contacts Count + $expense_count = count($_POST['expense_ids']); + + // Assign category to Selected Expenses + if (!empty($_POST['expense_ids'])) { + foreach($_POST['expense_ids'] as $expense_id) { + $expense_id = intval($expense_id); + + // Get Expense Details for Logging + $sql = mysqli_query($mysqli,"SELECT expense_description, expense_client_id FROM expenses WHERE expense_id = $expense_id"); + $row = mysqli_fetch_array($sql); + $expense_description = sanitizeInput($row['expense_description']); + $client_id = intval($row['expense_client_id']); + + mysqli_query($mysqli,"UPDATE expenses SET expense_account_id = $account_id WHERE expense_id = $expense_id"); + + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Expense', log_action = 'Edit', log_description = '$session_name assigned $expense_description to account $account_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $expense_id"); + + } // End Assign Location Loop + + $_SESSION['alert_message'] = "You assigned account $account_name to $expense_count expenses"; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); +} + +if (isset($_POST['bulk_edit_expense_client'])) { + + $client_id = intval($_POST['bulk_client_id']); + + // Get Client name for logging and Notification + $sql = mysqli_query($mysqli,"SELECT client_name FROM clients WHERE client_id = $client_id"); + $row = mysqli_fetch_array($sql); + $client_name = sanitizeInput($row['client_name']); + + // Get Selected Contacts Count + $expense_count = count($_POST['expense_ids']); + + // Assign category to Selected Expenses + if (!empty($_POST['expense_ids'])) { + foreach($_POST['expense_ids'] as $expense_id) { + $expense_id = intval($expense_id); + + // Get Expense Details for Logging + $sql = mysqli_query($mysqli,"SELECT expense_description FROM expenses WHERE expense_id = $expense_id"); + $row = mysqli_fetch_array($sql); + $expense_description = sanitizeInput($row['expense_description']); + + mysqli_query($mysqli,"UPDATE expenses SET expense_client_id = $client_id WHERE expense_id = $expense_id"); + + //Logging + mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Expense', log_action = 'Edit', log_description = '$session_name assigned $expense_description to client $client_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $expense_id"); + + } // End Assign Location Loop + + $_SESSION['alert_message'] = "You assigned Client $client_name to $expense_count expenses"; + } + + header("Location: " . $_SERVER["HTTP_REFERER"]); +} + if (isset($_POST['export_expenses_csv'])) { $date_from = sanitizeInput($_POST['date_from']); $date_to = sanitizeInput($_POST['date_to']); From 1bbb4426f666d72c03fc3e25985e98eb1fcb9372 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 31 Jan 2024 21:33:37 -0500 Subject: [PATCH 96/98] Fix Expense being off for Payment Gateway Fee --- guest_pay_invoice_stripe.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index 244e088d..9c86c903 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -283,11 +283,8 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent // Check to see if Expense Fields are configured and client pays fee is off then create expense if ($config_stripe_client_pays_fees == 0 && $config_stripe_expense_vendor > 0 && $config_stripe_expense_category > 0) { - $balance_before_fees = $balance_to_pay; - // Calculate the amount to charge the client - $balance_to_not_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); - // Calculate the fee amount - $gateway_expense_fee = round($balance_to_not_pay - $balance_before_fees, 2); + // Calculate gateway expense fee + $gateway_expense_fee = round($balance_to_pay * $config_stripe_percentage_fee + $config_stripe_flat_fee, 2); // Add Expense mysqli_query($mysqli,"INSERT INTO expenses SET expense_date = '$pi_date', expense_amount = $gateway_expense_fee, expense_currency_code = '$invoice_currency_code', expense_account_id = $config_stripe_account, expense_vendor_id = $config_stripe_expense_vendor, expense_client_id = $client_id, expense_category_id = $config_stripe_expense_category, expense_description = 'Stripe Transaction for Invoice $invoice_prefix$invoice_number In the Amount of $balance_to_pay', expense_reference = 'Stripe - $pi_id'"); From 28e7a6b1955d8a800cdb96ef38642a2e6dd3f9ff Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 31 Jan 2024 22:11:27 -0500 Subject: [PATCH 97/98] Removed Gateway Fee from the baance of Guest View Invoice and displayed it on the Pay Online button, as the client can pay other ways if they decide to not pay online if Client Pays Fees is enabled --- guest_pay_invoice_stripe.php | 15 ++++++++------- guest_view_invoice.php | 32 +++----------------------------- 2 files changed, 11 insertions(+), 36 deletions(-) diff --git a/guest_pay_invoice_stripe.php b/guest_pay_invoice_stripe.php index 9c86c903..15ded8f5 100644 --- a/guest_pay_invoice_stripe.php +++ b/guest_pay_invoice_stripe.php @@ -86,10 +86,9 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent if ($config_stripe_client_pays_fees == 1) { $balance_before_fees = $balance_to_pay; - // Calculate the amount to charge the client - $balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); - // Calculate the fee amount - $gateway_fee = round($balance_to_pay - $balance_before_fees, 2); + // Calculate the Gateway fee + $gateway_fee = round($balance_to_pay * $config_stripe_percentage_fee + $config_stripe_flat_fee, 2); + $balance_to_pay = $balance_to_pay + $gateway_fee; } //Round balance to pay to 2 decimal places @@ -277,17 +276,19 @@ if (isset($_GET['invoice_id'], $_GET['url_key']) && !isset($_GET['payment_intent // Check config to see if client pays fees is enabled or if should expense it if ($config_stripe_client_pays_fees == 1) { + // Calculate gateway expense fee + $gateway_fee = round($balance_to_pay * $config_stripe_percentage_fee + $config_stripe_flat_fee, 2); // Calculate the amount to charge the client - $balance_to_pay = ($balance_to_pay + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); + $balance_to_pay = $balance_to_pay + $gateway_fee; } // Check to see if Expense Fields are configured and client pays fee is off then create expense if ($config_stripe_client_pays_fees == 0 && $config_stripe_expense_vendor > 0 && $config_stripe_expense_category > 0) { // Calculate gateway expense fee - $gateway_expense_fee = round($balance_to_pay * $config_stripe_percentage_fee + $config_stripe_flat_fee, 2); + $gateway_fee = round($balance_to_pay * $config_stripe_percentage_fee + $config_stripe_flat_fee, 2); // Add Expense - mysqli_query($mysqli,"INSERT INTO expenses SET expense_date = '$pi_date', expense_amount = $gateway_expense_fee, expense_currency_code = '$invoice_currency_code', expense_account_id = $config_stripe_account, expense_vendor_id = $config_stripe_expense_vendor, expense_client_id = $client_id, expense_category_id = $config_stripe_expense_category, expense_description = 'Stripe Transaction for Invoice $invoice_prefix$invoice_number In the Amount of $balance_to_pay', expense_reference = 'Stripe - $pi_id'"); + mysqli_query($mysqli,"INSERT INTO expenses SET expense_date = '$pi_date', expense_amount = $gateway_fee, expense_currency_code = '$invoice_currency_code', expense_account_id = $config_stripe_account, expense_vendor_id = $config_stripe_expense_vendor, expense_client_id = $client_id, expense_category_id = $config_stripe_expense_category, expense_description = 'Stripe Transaction for Invoice $invoice_prefix$invoice_number In the Amount of $balance_to_pay', expense_reference = 'Stripe - $pi_id'"); } // Round balance to pay to 2 decimal places diff --git a/guest_view_invoice.php b/guest_view_invoice.php index d790e20b..59406616 100644 --- a/guest_view_invoice.php +++ b/guest_view_invoice.php @@ -114,24 +114,8 @@ $amount_paid = floatval($row['amount_paid']); // Calculate the balance owed $balance = $invoice_amount - $amount_paid; -// Check for overpayment or exact payment (amount paid is equal to or exceeds invoice amount) -if ($balance <= 0) { - // Invoice is fully paid (either exact payment or overpayment) - $gateway_fee = 0; // Zero out the gateway fee - $amount_paid = $invoice_amount; // Adjust amount paid to equal invoice amount - $balance = 0; // Balance is zero since invoice is fully paid -} else { - // If invoice is not fully paid - // Check if client is responsible for paying Stripe fees - if ($config_stripe_client_pays_fees == 1) { - // Calculate the total amount to charge the client, including Stripe fees - $balance_to_pay = ($balance + $config_stripe_flat_fee) / (1 - $config_stripe_percentage_fee); - $gateway_fee = $balance_to_pay - $balance; // Calculate gateway fee based on Stripe fees - } else { - // If client is not responsible for Stripe fees, gateway fee remains zero - $gateway_fee = 0; - } -} +// Calculate Gateway Fee +$gateway_fee = round($balance * $config_stripe_percentage_fee + $config_stripe_flat_fee, 2); //check to see if overdue $invoice_color = $invoice_badge_color; // Default @@ -155,7 +139,7 @@ $sql_invoice_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE it ');">Download - Pay Online + Pay Online @@ -312,16 +296,6 @@ $sql_invoice_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE it 0) { - ?> - - -
Gateway Fee
- - - Balance From 1303f18218eb50e58232ea454cbfa2251f2f7538 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 31 Jan 2024 22:16:21 -0500 Subject: [PATCH 98/98] Tidy --- guest_view_invoice.php | 1 - 1 file changed, 1 deletion(-) diff --git a/guest_view_invoice.php b/guest_view_invoice.php index 59406616..d4233dd4 100644 --- a/guest_view_invoice.php +++ b/guest_view_invoice.php @@ -2,7 +2,6 @@ require_once "guest_header.php"; - if (!isset($_GET['invoice_id'], $_GET['url_key'])) { echo "

Oops, something went wrong! Please raise a ticket if you believe this is an error.

"; require_once "guest_footer.php";