diff --git a/admin_categories.php b/admin_categories.php index 00c0991d..c747ba79 100644 --- a/admin_categories.php +++ b/admin_categories.php @@ -93,6 +93,12 @@ if (isset($_GET['archived'])) { echo 'btn-default'; } ?>">Payment Method + Ticket $value) { if (is_array($value)) { if (!isset($array2[$key]) || !is_array($array2[$key])) { @@ -56,7 +56,7 @@ function arrayDiffRecursive($array1, $array2) { } } } - + return $diff; } @@ -64,17 +64,17 @@ function arrayDiffRecursive($array1, $array2) { function loadTableStructuresFromSQLDumpURL($fileURL) { $context = stream_context_create(array('http' => array('header' => 'Accept: application/octet-stream'))); $fileContent = file_get_contents($fileURL, false, $context); - + if ($fileContent === false) { return null; } - + $structure = array(); $queries = explode(";", $fileContent); - + foreach ($queries as $query) { $query = trim($query); - + if (!empty($query)) { if (preg_match("/^CREATE TABLE `(.*)` \((.*)\)$/s", $query, $matches)) { $tableName = $matches[1]; @@ -83,7 +83,7 @@ function loadTableStructuresFromSQLDumpURL($fileURL) { } } } - + return $structure; } @@ -91,31 +91,31 @@ function loadTableStructuresFromSQLDumpURL($fileURL) { function fetchDatabaseStructureFromServer() { global $mysqli; - + $tables = array(); - + // Fetch table names $result = $mysqli->query("SHOW TABLES"); - + if ($result->num_rows > 0) { while ($row = $result->fetch_row()) { $tableName = $row[0]; $tables[$tableName] = array(); } } - + // Fetch table structures foreach ($tables as $tableName => &$table) { $result = $mysqli->query("SHOW CREATE TABLE `$tableName`"); - + if ($result->num_rows > 0) { $row = $result->fetch_row(); $table['structure'] = $row[1]; } } - + //$mysqli->close(); - + return $tables; } @@ -185,11 +185,12 @@ while ($row = $tablesResult->fetch_row()) { //Get loaded PHP modules $loadedModules = get_loaded_extensions(); -//Get Versions +//Get Server Info / Service versions $phpVersion = phpversion(); $mysqlVersion = $mysqli->server_version; -$operatingSystem = shell_exec('uname -a'); +$operatingSystem = php_uname(); $webServer = $_SERVER['SERVER_SOFTWARE']; +$errorLog = ini_get('error_log'); ?> @@ -198,20 +199,43 @@ $webServer = $_SERVER['SERVER_SOFTWARE'];

Debug

- -

Database Structure Check

- + +

Server Info

+ + "; + echo "MySQL Version: " . $mysqlVersion . "
"; + echo "Operating System: " . $operatingSystem . "
"; + echo "Web Server: " . $webServer . "
"; + echo "PHP Error Log: " . $errorLog + ?> +
+

File System

+ "; + echo "Total size of files in $folderPath and its subdirectories: " . $totalSizeMB . " MB"; + ?> + +
+ +

Database Structure Check

+

Database stats

- + "; echo "Total number of fields: " . $numFields . "
"; echo "Total number of rows: " . $numRows . "
"; echo "Current Database Version: " . CURRENT_DATABASE_VERSION . "
"; ?> - +

Table Stats

@@ -255,34 +279,8 @@ $webServer = $_SERVER['SERVER_SOFTWARE'];
-

Versions

- - "; - echo "MySQL Version: " . $mysqlVersion . "
"; - echo "Operating System: " . $operatingSystem . "
"; - echo "Web Server: " . $webServer; - - - ?> - -
- -

File System

- "; - echo "Total size of files in $folderPath and its subdirectories: " . $totalSizeMB . " MB"; - ?> - -
-

PHP Modules Installed

- + "; @@ -311,7 +309,7 @@ $webServer = $_SERVER['SERVER_SOFTWARE']; //Output the result echo $phpinfo; ?> - +
diff --git a/admin_tag_add_modal.php b/admin_tag_add_modal.php index e3654f61..b0eaa4b4 100644 --- a/admin_tag_add_modal.php +++ b/admin_tag_add_modal.php @@ -30,6 +30,7 @@ diff --git a/admin_tag_edit_modal.php b/admin_tag_edit_modal.php index 0d21df3b..319c63ad 100644 --- a/admin_tag_edit_modal.php +++ b/admin_tag_edit_modal.php @@ -30,6 +30,7 @@ diff --git a/admin_tags.php b/admin_tags.php index 939e4c4c..cce37dce 100644 --- a/admin_tags.php +++ b/admin_tags.php @@ -62,6 +62,13 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $tag_id = intval($row['tag_id']); $tag_name = nullable_htmlentities($row['tag_name']); $tag_type = intval($row['tag_type']); + if ( $tag_type == 1) { + $tag_type_display = "Client Tag"; + } elseif ( $tag_type == 2) { + $tag_type_display = "Location Tag"; + } else { + $tag_type_display = "Unknown Tag"; + } $tag_color = nullable_htmlentities($row['tag_color']); $tag_icon = nullable_htmlentities($row['tag_icon']); @@ -72,7 +79,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
- + +
+ +
+
+ +
+ +
+ Leave Blank for Full access to all clients, no affect on users with the admin role. +
+
diff --git a/admin_user_edit_modal.php b/admin_user_edit_modal.php index 85e8caf3..188d4974 100644 --- a/admin_user_edit_modal.php +++ b/admin_user_edit_modal.php @@ -67,23 +67,43 @@
+
+ +
+
+ +
+ +
+ Leave Blank for Full access to all clients, no affect on users with the admin role. +
+
diff --git a/admin_users.php b/admin_users.php index ce764ede..78392192 100644 --- a/admin_users.php +++ b/admin_users.php @@ -12,8 +12,9 @@ $url_query_strings_sort = http_build_query($get_copy); $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM users, user_settings + "SELECT SQL_CALC_FOUND_ROWS * FROM users, user_settings, user_roles WHERE users.user_id = user_settings.user_id + AND user_settings.user_role = user_roles.user_role_id AND (user_name LIKE '%$q%' OR user_email LIKE '%$q%') AND user_archived_at IS NULL ORDER BY $sort $order LIMIT $record_from, $record_to" @@ -98,13 +99,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); } $user_config_force_mfa = intval($row['user_config_force_mfa']); $user_role = $row['user_role']; - if ($user_role == 3) { - $user_role_display = "Administrator"; - } elseif ($user_role == 2) { - $user_role_display = "Technician"; - } else { - $user_role_display = "Accountant"; - } + $user_role_display = nullable_htmlentities($row['user_role_name']); $user_initials = nullable_htmlentities(initials($user_name)); $sql_last_login = mysqli_query( @@ -125,9 +120,18 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $last_login = "$log_created_at
$log_user_os
$log_user_browser
$log_ip
"; } + // Get User Client Access Permissions + $user_client_access_sql = mysqli_query($mysqli,"SELECT client_id FROM user_permissions WHERE user_id = $user_id"); + $client_access_array = []; + while ($row = mysqli_fetch_assoc($user_client_access_sql)) { + $client_access_array[] = intval($row['client_id']); + } + $sql_remember_tokens = mysqli_query($mysqli, "SELECT * FROM remember_tokens WHERE remember_token_user_id = $user_id"); $remember_token_count = mysqli_num_rows($sql_remember_tokens); + + ?> diff --git a/ajax.php b/ajax.php index 9476b40e..47011ac1 100644 --- a/ajax.php +++ b/ajax.php @@ -19,37 +19,22 @@ require_once "rfc6238.php"; * Fetches SSL certificates from remote hosts & returns the relevant info (issuer, expiry, public key) */ if (isset($_GET['certificate_fetch_parse_json_details'])) { + // PHP doesn't appreciate attempting SSL sockets to non-existent domains if (empty($_GET['domain'])) { exit(); } - $domain = $_GET['domain']; - // FQDNs in database shouldn't have a URL scheme, adding one - $domain = "https://".$domain; + $name = $_GET['domain']; - // Parse host and port - $url = parse_url($domain, PHP_URL_HOST); - $port = parse_url($domain, PHP_URL_PORT); - // Default port - if (!$port) { - $port = "443"; - } + // Get SSL cert for domain (if exists) + $certificate = getSSL($name); - // Get certificate (using verify peer false to allow for self-signed certs) - $socket = "ssl://$url:$port"; - $get = stream_context_create(array("ssl" => array("capture_peer_cert" => true, "verify_peer" => false,))); - $read = stream_socket_client($socket, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $get); - $cert = stream_context_get_params($read); - $cert_public_key_obj = openssl_x509_parse($cert['options']['ssl']['peer_certificate']); - openssl_x509_export($cert['options']['ssl']['peer_certificate'], $export); - - // Process data - if ($cert_public_key_obj) { + if ($certificate['success'] == "TRUE") { $response['success'] = "TRUE"; - $response['expire'] = date('Y-m-d', $cert_public_key_obj['validTo_time_t']); - $response['issued_by'] = strip_tags($cert_public_key_obj['issuer']['O']); - $response['public_key'] = $export; //nl2br + $response['expire'] = $certificate['expire']; + $response['issued_by'] = $certificate['issued_by']; + $response['public_key'] = $certificate['public_key']; } else { $response['success'] = "FALSE"; } diff --git a/api/v1/contacts/contact_model.php b/api/v1/contacts/contact_model.php index 8fa13b27..7cb724b4 100644 --- a/api/v1/contacts/contact_model.php +++ b/api/v1/contacts/contact_model.php @@ -74,6 +74,14 @@ if (isset($_POST['contact_auth_method'])) { $auth_method = ''; } +if (isset($_POST['contact_primary'])) { + $primary = intval($_POST['contact_primary']); +} elseif ($contact_row) { + $primary = $contact_row['contact_primary']; +} else { + $primary = '0'; +} + if (isset($_POST['contact_important'])) { $important = intval($_POST['contact_important']); } elseif ($contact_row) { diff --git a/api/v1/contacts/create.php b/api/v1/contacts/create.php index 2599eaa2..cf51f7c9 100644 --- a/api/v1/contacts/create.php +++ b/api/v1/contacts/create.php @@ -20,7 +20,7 @@ if (!empty($name) && !empty($email) && !empty($client_id)) { if (mysqli_num_rows($email_duplication_sql) == 0) { // Insert contact - $insert_sql = mysqli_query($mysqli, "INSERT INTO contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_auth_method = '$auth_method', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id"); + $insert_sql = mysqli_query($mysqli, "INSERT INTO contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_auth_method = '$auth_method', contact_primary = '$primary', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id"); // Check insert & get insert ID if ($insert_sql) { diff --git a/api/v1/contacts/update.php b/api/v1/contacts/update.php index 19ae914a..a5049f47 100644 --- a/api/v1/contacts/update.php +++ b/api/v1/contacts/update.php @@ -19,7 +19,7 @@ if (!empty($contact_id)) { require_once 'contact_model.php'; - $update_sql = mysqli_query($mysqli, "UPDATE contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_auth_method = '$auth_method', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id WHERE contact_id = $contact_id LIMIT 1"); + $update_sql = mysqli_query($mysqli, "UPDATE contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_auth_method = '$auth_method', contact_primary = '$primary', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id WHERE contact_id = $contact_id LIMIT 1"); // Check insert & get insert ID if ($update_sql) { diff --git a/calendar_events.php b/calendar_events.php index 68841c31..e8f7eac4 100644 --- a/calendar_events.php +++ b/calendar_events.php @@ -180,6 +180,29 @@ while ($row = mysqli_fetch_array($sql)) { echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'ticket.php?ticket_id=$event_id' },"; } + // Recurring Tickets + $sql = mysqli_query($mysqli, "SELECT * FROM clients + LEFT JOIN scheduled_tickets ON client_id = scheduled_ticket_client_id + LEFT JOIN users ON scheduled_ticket_assigned_to = user_id" + ); + while ($row = mysqli_fetch_array($sql)) { + $event_id = intval($row['scheduled_ticket_id']); + $client_id = intval($row['client_id']); + $username = $row['user_name']; + $frequency = $row['scheduled_ticket_frequency']; + if (empty($username)) { + $username = ""; + } else { + //Limit to characters and add ... + $username = "[". substr($row['user_name'], 0, 9) . "...]"; + } + + $event_title = json_encode("R Ticket ($frequency) - " . $row['scheduled_ticket_subject'] . " " . $username); + $event_start = json_encode($row['scheduled_ticket_next_run']); + + echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'client_recurring_tickets.php?client_id=$client_id' },"; + } + //Tickets Scheduled $sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN tickets ON client_id = ticket_client_id @@ -238,6 +261,14 @@ while ($row = mysqli_fetch_array($sql)) { ?> ], eventOrder: 'allDay,start,-duration,title', + + + firstDay: , }); calendar.render(); diff --git a/check_login.php b/check_login.php index a0fd1573..57c5bd36 100644 --- a/check_login.php +++ b/check_login.php @@ -10,7 +10,8 @@ if (!isset($_SESSION)) { session_start(); } -//Check to see if setup is enabled + +// Check to see if setup is enabled if (!isset($config_enable_setup) || $config_enable_setup == 1) { header("Location: setup.php"); exit; @@ -18,13 +19,19 @@ if (!isset($config_enable_setup) || $config_enable_setup == 1) { // Check user is logged in with a valid session if (!isset($_SESSION['logged']) || !$_SESSION['logged']) { - header("Location: login.php"); + if ($_SERVER["REQUEST_URI"] == "/") { + header("Location: login.php"); + } else { + header("Location: login.php?last_visited=" . base64_encode($_SERVER["REQUEST_URI"]) ); + } exit; } + // Set Timezone require_once "inc_set_timezone.php"; + // User IP & UA $session_ip = sanitizeInput(getIP()); $session_user_agent = sanitizeInput($_SERVER['HTTP_USER_AGENT']); @@ -56,9 +63,37 @@ $session_company_country = $row['company_country']; $session_company_locale = $row['company_locale']; $session_company_currency = $row['company_currency']; -//Set Currency Format + +// Set Currency Format $currency_format = numfmt_create($session_company_locale, NumberFormatter::CURRENCY); + +try { + // Get User Client Access Permissions + $user_client_access_sql = "SELECT client_id FROM user_permissions WHERE user_id = $session_user_id"; + $user_client_access_result = mysqli_query($mysqli, $user_client_access_sql); + + $client_access_array = []; + while ($row = mysqli_fetch_assoc($user_client_access_result)) { + $client_access_array[] = $row['client_id']; + } + + $client_access_string = implode(',', $client_access_array); + + // Role / Client Access Permission Check + if ($session_user_role < 3 && !empty($client_access_string)) { + $access_permission_query = "AND client_id IN ($client_access_string)"; + } else { + $access_permission_query = ""; + } +} catch (Exception $e) { + // Handle exception + error_log('MySQL error: ' . $e->getMessage()); + $access_permission_query = ""; // Ensure safe default if query fails +} + + +// Include the settings vars require_once "get_settings.php"; @@ -73,15 +108,17 @@ if ($iPod || $iPhone || $iPad) { $session_map_source = "google"; } -//Check if mobile device + +// Check if mobile device $session_mobile = isMobile(); -//Get Notification Count for the badge on the top nav + +// Get Notification Count for the badge on the top nav $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('notification_id') AS num FROM notifications WHERE (notification_user_id = $session_user_id OR notification_user_id = 0) AND notification_dismissed_at IS NULL")); $num_notifications = $row['num']; + // FORCE MFA Setup //if ($session_user_config_force_mfa == 1 && $session_token == NULL) { // header("Location: force_mfa.php"); //} - diff --git a/client_documents.php b/client_documents.php index c826c5d6..f7a7e9bf 100644 --- a/client_documents.php +++ b/client_documents.php @@ -33,17 +33,31 @@ if (!empty($_GET['folder_id'])) { // Set Folder Location Var used when creating folders $folder_location = 0; -$sql = mysqli_query( - $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM documents - LEFT JOIN users ON document_created_by = user_id - WHERE document_client_id = $client_id - AND document_template = 0 - AND document_folder_id = $folder - AND document_archived_at IS NULL - $query_snippet - ORDER BY $sort $order LIMIT $record_from, $record_to" -); +if ($get_folder_id == 0 && $_GET["q"]) { + $sql = mysqli_query( + $mysqli, + "SELECT SQL_CALC_FOUND_ROWS * FROM documents + LEFT JOIN users ON document_created_by = user_id + WHERE document_client_id = $client_id + AND document_template = 0 + + AND document_archived_at IS NULL + $query_snippet + ORDER BY $sort $order LIMIT $record_from, $record_to" + ); +}else{ + $sql = mysqli_query( + $mysqli, + "SELECT SQL_CALC_FOUND_ROWS * FROM documents + LEFT JOIN users ON document_created_by = user_id + WHERE document_client_id = $client_id + AND document_template = 0 + AND document_folder_id = $folder + AND document_archived_at IS NULL + $query_snippet + ORDER BY $sort $order LIMIT $record_from, $record_to" + ); +} $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); diff --git a/client_events.php b/client_events.php index 590b202e..f4777ed7 100644 --- a/client_events.php +++ b/client_events.php @@ -180,6 +180,29 @@ while ($row = mysqli_fetch_array($sql)) { echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'ticket.php?ticket_id=$event_id' },"; } + // Recurring Tickets + $sql = mysqli_query($mysqli, "SELECT * FROM clients + LEFT JOIN scheduled_tickets ON client_id = scheduled_ticket_client_id + LEFT JOIN users ON scheduled_ticket_assigned_to = user_id" + ); + while ($row = mysqli_fetch_array($sql)) { + $event_id = intval($row['scheduled_ticket_id']); + $client_id = intval($row['client_id']); + $username = $row['user_name']; + $frequency = $row['scheduled_ticket_frequency']; + if (empty($username)) { + $username = ""; + } else { + //Limit to characters and add ... + $username = "[". substr($row['user_name'], 0, 9) . "...]"; + } + + $event_title = json_encode("R Ticket ($frequency) - " . $row['scheduled_ticket_subject'] . " " . $username); + $event_start = json_encode($row['scheduled_ticket_next_run']); + + echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'client_recurring_tickets.php?client_id=$client_id' },"; + } + //Tickets Scheduled $sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN tickets ON client_id = ticket_client_id diff --git a/client_file_upload_modal.php b/client_file_upload_modal.php index 68e29748..3fcb869a 100644 --- a/client_file_upload_modal.php +++ b/client_file_upload_modal.php @@ -11,7 +11,7 @@ -
- -
-
@@ -180,6 +176,27 @@
+
+ +
+
+ +
+ +
+
+ diff --git a/client_location_edit_modal.php b/client_location_edit_modal.php index 7c140b93..5e76eae5 100644 --- a/client_location_edit_modal.php +++ b/client_location_edit_modal.php @@ -194,6 +194,27 @@ +
+ +
+
+ +
+ +
+
+ diff --git a/client_locations.php b/client_locations.php index c92cedf9..88e77774 100644 --- a/client_locations.php +++ b/client_locations.php @@ -12,10 +12,13 @@ $url_query_strings_sort = http_build_query($get_copy); $sql = mysqli_query( $mysqli, - "SELECT SQL_CALC_FOUND_ROWS * FROM locations + "SELECT SQL_CALC_FOUND_ROWS locations.*, GROUP_CONCAT(tag_name) FROM locations + LEFT JOIN location_tags ON location_tags.location_id = locations.location_id + LEFT JOIN tags ON tags.tag_id = location_tags.tag_id WHERE location_client_id = $client_id AND location_$archive_query - AND (location_name LIKE '%$q%' OR location_description LIKE '%$q%' OR location_address LIKE '%$q%' OR location_phone LIKE '%$phone_query%') + AND (location_name LIKE '%$q%' OR location_description LIKE '%$q%' OR location_address LIKE '%$q%' OR location_phone LIKE '%$phone_query%' OR tag_name LIKE '%$q%') + GROUP BY location_id ORDER BY location_primary DESC, $sort $order LIMIT $record_from, $record_to" ); @@ -118,6 +121,29 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $location_primary_display = ""; } + // Tags + + $location_tag_name_display_array = array(); + $location_tag_id_array = array(); + $sql_location_tags = mysqli_query($mysqli, "SELECT * FROM location_tags LEFT JOIN tags ON location_tags.tag_id = tags.tag_id WHERE location_tags.location_id = $location_id ORDER BY tag_name ASC"); + while ($row = mysqli_fetch_array($sql_location_tags)) { + + $location_tag_id = intval($row['tag_id']); + $location_tag_name = nullable_htmlentities($row['tag_name']); + $location_tag_color = nullable_htmlentities($row['tag_color']); + if (empty($location_tag_color)) { + $location_tag_color = "dark"; + } + $location_tag_icon = nullable_htmlentities($row['tag_icon']); + if (empty($location_tag_icon)) { + $location_tag_icon = "tag"; + } + + $location_tag_id_array[] = $location_tag_id; + $location_tag_name_display_array[] = "$location_tag_name"; + } + $location_tags_display = implode('', $location_tag_name_display_array); + ?> @@ -128,6 +154,12 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
>
+ +
+ +
+ diff --git a/client_logins.php b/client_logins.php index 3e9e7437..5ab1f1ed 100644 --- a/client_logins.php +++ b/client_logins.php @@ -89,8 +89,8 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $login_uri = nullable_htmlentities($row['login_uri']); if (empty($login_uri)) { $login_uri_display = "-"; - } else { - $login_uri_display = "$login_uri"; + } else { + $login_uri_display = truncate($login_uri,40) . ""; } $login_uri_2 = nullable_htmlentities($row['login_uri_2']); $login_username = nullable_htmlentities(decryptLoginEntry($row['login_username'])); diff --git a/clients.php b/clients.php index da3bd024..7d06c569 100644 --- a/clients.php +++ b/clients.php @@ -44,23 +44,24 @@ $url_query_strings_sort = http_build_query($get_copy); $sql = mysqli_query( $mysqli, " - SELECT SQL_CALC_FOUND_ROWS clients.*, contacts.*, locations.*, GROUP_CONCAT(tags.tag_name) AS tag_names + SELECT SQL_CALC_FOUND_ROWS clients.*, contacts.*, locations.*, GROUP_CONCAT(tag_name) FROM clients LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 - LEFT JOIN client_tags ON client_tags.client_tag_client_id = clients.client_id - LEFT JOIN tags ON tags.tag_id = client_tags.client_tag_tag_id - WHERE (clients.client_name LIKE '%$q%' OR clients.client_type LIKE '%$q%' OR clients.client_referral LIKE '%$q%' - OR contacts.contact_email LIKE '%$q%' OR contacts.contact_name LIKE '%$q%' OR contacts.contact_phone LIKE '%$phone_query%' - OR contacts.contact_mobile LIKE '%$phone_query%' OR locations.location_address LIKE '%$q%' - OR locations.location_city LIKE '%$q%' OR locations.location_state LIKE '%$q%' OR locations.location_zip LIKE '%$q%' - OR tags.tag_name LIKE '%$q%' OR clients.client_tax_id_number LIKE '%$q%') - AND clients.client_$archive_query - AND DATE(clients.client_created_at) BETWEEN '$dtf' AND '$dtt' - AND clients.client_lead = $leads + LEFT JOIN client_tags ON client_tags.client_id = clients.client_id + LEFT JOIN tags ON tags.tag_id = client_tags.tag_id + WHERE (client_name LIKE '%$q%' OR client_type LIKE '%$q%' OR client_referral LIKE '%$q%' + OR contact_email LIKE '%$q%' OR contact_name LIKE '%$q%' OR contact_phone LIKE '%$phone_query%' + OR contact_mobile LIKE '%$phone_query%' OR location_address LIKE '%$q%' + OR location_city LIKE '%$q%' OR location_state LIKE '%$q%' OR location_zip LIKE '%$q%' + OR tag_name LIKE '%$q%' OR client_tax_id_number LIKE '%$q%') + AND client_$archive_query + AND DATE(client_created_at) BETWEEN '$dtf' AND '$dtt' + AND client_lead = $leads + $access_permission_query $industry_query $referral_query - GROUP BY clients.client_id + GROUP BY client_id ORDER BY $sort $order LIMIT $record_from, $record_to "); @@ -245,7 +246,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $client_tag_name_display_array = array(); $client_tag_id_array = array(); - $sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.client_tag_tag_id = tags.tag_id WHERE client_tags.client_tag_client_id = $client_id ORDER BY tag_name ASC"); + $sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.tag_id = tags.tag_id WHERE client_id = $client_id ORDER BY tag_name ASC"); while ($row = mysqli_fetch_array($sql_client_tags)) { $client_tag_id = intval($row['tag_id']); diff --git a/cron.php b/cron.php index ca64d611..856e7461 100644 --- a/cron.php +++ b/cron.php @@ -252,6 +252,7 @@ if (mysqli_num_rows($sql_scheduled_tickets) > 0) { $details = mysqli_real_escape_string($mysqli, $row['scheduled_ticket_details']); $priority = sanitizeInput($row['scheduled_ticket_priority']); $frequency = sanitizeInput(strtolower($row['scheduled_ticket_frequency'])); + $billable = intval($row['scheduled_ticket_billable']); $created_id = intval($row['scheduled_ticket_created_by']); $assigned_id = intval($row['scheduled_ticket_assigned_to']); $client_id = intval($row['scheduled_ticket_client_id']); @@ -272,7 +273,7 @@ if (mysqli_num_rows($sql_scheduled_tickets) > 0) { mysqli_query($mysqli, "UPDATE settings SET config_ticket_next_number = $new_config_ticket_next_number WHERE company_id = 1"); // Raise the ticket - 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_status = '$ticket_status', ticket_created_by = $created_id, ticket_assigned_to = $assigned_id, ticket_contact_id = $contact_id, ticket_client_id = $client_id, ticket_asset_id = $asset_id"); + 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_status = '$ticket_status', ticket_billable = $billable, ticket_created_by = $created_id, ticket_assigned_to = $assigned_id, ticket_contact_id = $contact_id, ticket_client_id = $client_id, ticket_asset_id = $asset_id"); $id = mysqli_insert_id($mysqli); // Logging @@ -733,7 +734,7 @@ while ($row = mysqli_fetch_array($sql_recurring_expenses)) { // TELEMETRY -if ($config_telemetry > 0 OR $config_telemetry = 2) { +if ($config_telemetry > 0 OR $config_telemetry == 2) { $current_version = exec("git rev-parse HEAD"); @@ -979,6 +980,19 @@ 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'"); } + +// Fetch Updates +$updates = fetchUpdates(); + +$update_message = $updates->update_message; + +if ($updates->current_version !== $updates->latest_version) { + // Send Alert to inform Updates Available + mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Update', notification = '$update_message', notification_action = 'admin_update.php'"); +} + + + /* * ############################################################################################################### * FINISH UP diff --git a/css/ticket_time_tracking.css b/css/ticket_time_tracking.css deleted file mode 100644 index eb2c2c5c..00000000 --- a/css/ticket_time_tracking.css +++ /dev/null @@ -1,13 +0,0 @@ -/* Custom CSS Styling for time tracking */ - -/* Small bit of space between the ticket status and time tracking inputs */ -.custom-tt-horizontal-spacing { - width: 20px; /* Adjust the width as needed for smaller spacing */ - display: inline-block; -} - -/* Adjust Hour, min, and second fields to be close together */ -.custom-tt-width { - width: 50px; /* Adjust the width as needed */ - padding: 0; /* Remove padding to maintain the desired width */ -} diff --git a/database_updates.php b/database_updates.php index 43f32d54..39ea33fb 100644 --- a/database_updates.php +++ b/database_updates.php @@ -335,7 +335,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { if (CURRENT_DATABASE_VERSION == '0.2.0') { //Insert queries here required to update to DB version 0.2.1 - mysqli_query($mysqli, "ALTER TABLE `vendors` + mysqli_query($mysqli, "ALTER TABLE `vendors` ADD `vendor_hours` VARCHAR(200) NULL DEFAULT NULL AFTER `vendor_website`, ADD `vendor_sla` VARCHAR(200) NULL DEFAULT NULL AFTER `vendor_hours`, ADD `vendor_code` VARCHAR(200) NULL DEFAULT NULL AFTER `vendor_sla`, @@ -343,11 +343,11 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { "); mysqli_query($mysqli, "ALTER TABLE `vendors` - DROP `vendor_country`, - DROP `vendor_address`, - DROP `vendor_city`, - DROP `vendor_state`, - DROP `vendor_zip`, + DROP `vendor_country`, + DROP `vendor_address`, + DROP `vendor_city`, + DROP `vendor_state`, + DROP `vendor_zip`, DROP `vendor_global` "); @@ -355,7 +355,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { mysqli_query($mysqli, "CREATE TABLE `vendor_templates` (`vendor_template_id` int(11) AUTO_INCREMENT PRIMARY KEY, `vendor_template_name` varchar(200) NOT NULL, `vendor_template_description` varchar(200) NULL DEFAULT NULL, - `vendor_template_phone` varchar(200) NULL DEFAULT NULL, + `vendor_template_phone` varchar(200) NULL DEFAULT NULL, `vendor_template_email` varchar(200) NULL DEFAULT NULL, `vendor_template_website` varchar(200) NULL DEFAULT NULL, `vendor_template_hours` varchar(200) NULL DEFAULT NULL, @@ -397,7 +397,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { mysqli_query($mysqli, "CREATE TABLE `interfaces` (`interface_id` int(11) AUTO_INCREMENT PRIMARY KEY, `interface_number` int(11) NULL DEFAULT NULL, `interface_description` varchar(200) NULL DEFAULT NULL, - `interface_connected_asset` varchar(200) NULL DEFAULT NULL, + `interface_connected_asset` varchar(200) NULL DEFAULT NULL, `interface_ip` varchar(200) NULL DEFAULT NULL, `interface_created_at` datetime DEFAULT CURRENT_TIMESTAMP, `interface_updated_at` datetime NULL ON UPDATE CURRENT_TIMESTAMP, @@ -1802,24 +1802,24 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { mysqli_query($mysqli, "UPDATE ticket_statuses SET ticket_status_color = '#28a745' WHERE ticket_status_id = 3"); // On Hold mysqli_query($mysqli, "UPDATE ticket_statuses SET ticket_status_color = '#343a40' WHERE ticket_status_id = 4"); // Auto Close mysqli_query($mysqli, "UPDATE ticket_statuses SET ticket_status_color = '#343a40' WHERE ticket_status_id = 5"); // Closed - + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.1.9'"); } if (CURRENT_DATABASE_VERSION == '1.1.9') { mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_login_remember_me_expire` INT(11) NOT NULL DEFAULT 3 AFTER `config_login_key_secret`"); - + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.0'"); } if (CURRENT_DATABASE_VERSION == '1.2.0') { mysqli_query($mysqli, "ALTER TABLE `ticket_templates` ADD `ticket_template_order` INT(11) NOT NULL DEFAULT 0 AFTER `ticket_template_details`"); - + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.1'"); } if (CURRENT_DATABASE_VERSION == '1.2.1') { - + // Ticket Templates can have many project templates and Project Template can have have many ticket template, so instead create a many to many table relationship mysqli_query($mysqli, "ALTER TABLE `ticket_templates` DROP `ticket_template_order`"); mysqli_query($mysqli, "ALTER TABLE `ticket_templates` DROP `ticket_template_project_template_id`"); @@ -1831,61 +1831,121 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { `ticket_template_order` INT(11) NOT NULL DEFAULT 0, PRIMARY KEY (`ticket_template_id`,`project_template_id`) )"); - + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.2'"); } if (CURRENT_DATABASE_VERSION == '1.2.2') { - + mysqli_query($mysqli, "ALTER TABLE `tasks` DROP `task_description`"); mysqli_query($mysqli, "ALTER TABLE `task_templates` DROP `task_template_description`"); - + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.3'"); } if (CURRENT_DATABASE_VERSION == '1.2.3') { - + mysqli_query($mysqli, "ALTER TABLE `projects` ADD `project_manager` INT(11) NOT NULL DEFAULT 0 AFTER `project_due`"); - + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.4'"); } if (CURRENT_DATABASE_VERSION == '1.2.4') { - + mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_project_prefix` VARCHAR(200) NOT NULL DEFAULT 'PRJ-' AFTER `config_default_hourly_rate`"); mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_project_next_number` INT(11) NOT NULL DEFAULT 1 AFTER `config_project_prefix`"); - + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.5'"); } if (CURRENT_DATABASE_VERSION == '1.2.5') { - + mysqli_query($mysqli, "ALTER TABLE `projects` ADD `project_prefix` VARCHAR(200) DEFAULT NULL AFTER `project_id`"); mysqli_query($mysqli, "ALTER TABLE `projects` ADD `project_number` INT(11) NOT NULL DEFAULT 1 AFTER `project_prefix`"); - + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.6'"); } if (CURRENT_DATABASE_VERSION == '1.2.6') { - + mysqli_query($mysqli, "ALTER TABLE `domains` ADD `domain_dnshost` INT(11) NOT NULL DEFAULT 0 AFTER `domain_webhost`"); mysqli_query($mysqli, "ALTER TABLE `domains` ADD `domain_mailhost` INT(11) NOT NULL DEFAULT 0 AFTER `domain_dnshost`"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.7'"); } if (CURRENT_DATABASE_VERSION == '1.2.7') { - + mysqli_query($mysqli, "ALTER TABLE `recurring` ADD `recurring_invoice_email_notify` TINYINT(1) NOT NULL DEFAULT 1 AFTER `recurring_note`"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.8'"); } - // if (CURRENT_DATABASE_VERSION == '1.2.8') { - // // Insert queries here required to update to DB version 1.2.9 + if (CURRENT_DATABASE_VERSION == '1.2.8') { + + mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_phone_mask` TINYINT(1) NOT NULL DEFAULT 1 AFTER `config_destructive_deletes_enable`"); + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.9'"); + } + + if (CURRENT_DATABASE_VERSION == '1.2.9') { + + mysqli_query($mysqli, "CREATE TABLE `user_permissions` (`user_id` int(11) NOT NULL,`client_id` int(11) NOT NULL, PRIMARY KEY (`user_id`,`client_id`))"); + + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.0'"); + } + + if (CURRENT_DATABASE_VERSION == '1.3.0') { + + mysqli_query($mysqli, "CREATE TABLE `user_roles` ( + `user_role_id` INT(11) NOT NULL AUTO_INCREMENT, + `user_role_name` VARCHAR(200) NOT NULL, + `user_role_description` VARCHAR(200) NULL DEFAULT NULL, + `user_role_created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `user_role_updated_at` DATETIME ON UPDATE CURRENT_TIMESTAMP NULL, + `user_role_archived_at` DATETIME NULL, + PRIMARY KEY (`user_role_id`) + )"); + + mysqli_query($mysqli, "INSERT INTO `user_roles` SET user_role_id = 1, user_role_name = 'Accountant', user_role_description = 'Built-in - Limited access to financial-focused modules'"); + mysqli_query($mysqli, "INSERT INTO `user_roles` SET user_role_id = 2, user_role_name = 'Technician', user_role_description = 'Built-in - Limited access to technical-focused modules'"); + mysqli_query($mysqli, "INSERT INTO `user_roles` SET user_role_id = 3, user_role_name = 'Administrator', user_role_description = 'Built-in - Full administrative access to all modules (including user management)'"); + + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.1'"); + } + + if (CURRENT_DATABASE_VERSION == '1.3.1') { + mysqli_query($mysqli, "ALTER TABLE `user_settings` ADD `user_config_calendar_first_day` TINYINT(1) NOT NULL DEFAULT 0 AFTER `user_config_dashboard_technical_enable`"); + + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.2'"); + } + + if (CURRENT_DATABASE_VERSION == '1.3.2') { + mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_ticket_default_billable` TINYINT(1) NOT NULL DEFAULT 0 AFTER `config_ticket_new_ticket_notification_email`"); + mysqli_query($mysqli, "ALTER TABLE `scheduled_tickets` ADD `scheduled_ticket_billable` TINYINT(1) NOT NULL DEFAULT 0 AFTER `scheduled_ticket_frequency`"); + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.3'"); + } + + if (CURRENT_DATABASE_VERSION == '1.3.3') { + // // Insert queries here required to update to DB version 1.3.3 // // Then, update the database to the next sequential version - // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.9"); + mysqli_query($mysqli, "CREATE TABLE `location_tags` (`location_id` int(11) NOT NULL,`tag_id` int(11) NOT NULL, PRIMARY KEY (`location_id`,`tag_id`))"); + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.4'"); + } + + if (CURRENT_DATABASE_VERSION == '1.3.4') { + mysqli_query($mysqli, "ALTER TABLE `client_tags` CHANGE `client_tag_client_id` `client_id` INT(11) NOT NULL"); + mysqli_query($mysqli, "ALTER TABLE `client_tags` CHANGE `client_tag_tag_id` `tag_id` INT(11) NOT NULL"); + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.5'"); + } + + // if (CURRENT_DATABASE_VERSION == '1.3.5') { + // // Insert queries here required to update to DB version 1.3.6 + // // Then, update the database to the next sequential version + // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.6'"); // } } else { // Up-to-date } + + + diff --git a/database_version.php b/database_version.php index ac7b3dd1..cb57d13f 100644 --- a/database_version.php +++ b/database_version.php @@ -5,4 +5,4 @@ * It is used in conjunction with database_updates.php */ -DEFINE("LATEST_DATABASE_VERSION", "1.2.8"); +DEFINE("LATEST_DATABASE_VERSION", "1.3.5"); diff --git a/db.sql b/db.sql index 3b56fcd7..b09d052a 100644 --- a/db.sql +++ b/db.sql @@ -250,9 +250,9 @@ DROP TABLE IF EXISTS `client_tags`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `client_tags` ( - `client_tag_client_id` int(11) NOT NULL, - `client_tag_tag_id` int(11) NOT NULL, - PRIMARY KEY (`client_tag_client_id`,`client_tag_tag_id`) + `client_id` int(11) NOT NULL, + `tag_id` int(11) NOT NULL, + PRIMARY KEY (`client_id`,`tag_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -751,6 +751,20 @@ CREATE TABLE `invoices` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `location_tags` +-- + +DROP TABLE IF EXISTS `location_tags`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `location_tags` ( + `location_id` int(11) NOT NULL, + `tag_id` int(11) NOT NULL, + PRIMARY KEY (`location_id`,`tag_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `locations` -- @@ -1156,6 +1170,7 @@ CREATE TABLE `scheduled_tickets` ( `scheduled_ticket_details` longtext NOT NULL, `scheduled_ticket_priority` varchar(200) DEFAULT NULL, `scheduled_ticket_frequency` varchar(10) NOT NULL, + `scheduled_ticket_billable` tinyint(1) NOT NULL DEFAULT 0, `scheduled_ticket_start_date` date NOT NULL, `scheduled_ticket_next_run` date NOT NULL, `scheduled_ticket_created_at` datetime NOT NULL DEFAULT current_timestamp(), @@ -1341,6 +1356,7 @@ CREATE TABLE `settings` ( `config_ticket_autoclose` tinyint(1) NOT NULL DEFAULT 0, `config_ticket_autoclose_hours` int(5) NOT NULL DEFAULT 72, `config_ticket_new_ticket_notification_email` varchar(200) DEFAULT NULL, + `config_ticket_default_billable` tinyint(1) NOT NULL DEFAULT 0, `config_enable_cron` tinyint(1) NOT NULL DEFAULT 0, `config_cron_key` varchar(255) DEFAULT NULL, `config_recurring_auto_send_invoice` tinyint(1) NOT NULL DEFAULT 1, @@ -1375,6 +1391,7 @@ CREATE TABLE `settings` ( `config_telemetry` tinyint(1) DEFAULT 0, `config_timezone` varchar(200) NOT NULL DEFAULT 'America/New_York', `config_destructive_deletes_enable` tinyint(1) NOT NULL DEFAULT 0, + `config_phone_mask` tinyint(1) NOT NULL DEFAULT 1, PRIMARY KEY (`company_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1776,6 +1793,38 @@ CREATE TABLE `trips` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `user_permissions` +-- + +DROP TABLE IF EXISTS `user_permissions`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_permissions` ( + `user_id` int(11) NOT NULL, + `client_id` int(11) NOT NULL, + PRIMARY KEY (`user_id`,`client_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `user_roles` +-- + +DROP TABLE IF EXISTS `user_roles`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `user_roles` ( + `user_role_id` int(11) NOT NULL AUTO_INCREMENT, + `user_role_name` varchar(200) NOT NULL, + `user_role_description` varchar(200) DEFAULT NULL, + `user_role_created_at` datetime NOT NULL DEFAULT current_timestamp(), + `user_role_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(), + `user_role_archived_at` datetime DEFAULT NULL, + PRIMARY KEY (`user_role_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `user_settings` -- @@ -1790,6 +1839,7 @@ CREATE TABLE `user_settings` ( `user_config_records_per_page` int(11) NOT NULL DEFAULT 10, `user_config_dashboard_financial_enable` tinyint(1) NOT NULL DEFAULT 0, `user_config_dashboard_technical_enable` tinyint(1) NOT NULL DEFAULT 0, + `user_config_calendar_first_day` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -1902,4 +1952,4 @@ CREATE TABLE `vendors` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2024-04-12 19:37:23 +-- Dump completed on 2024-05-31 16:45:46 diff --git a/force_mfa.php b/force_mfa.php index 0a70186e..05e6d1f2 100644 --- a/force_mfa.php +++ b/force_mfa.php @@ -36,8 +36,9 @@ require_once "header.php"; if (!empty($session_token)) { - //Generate QR Code based off the generated key - print sprintf('', TokenAuth6238::getBarCodeUrl($session_name, ' ', $session_token, $_SERVER['SERVER_NAME'])); + // Generate QR Code + $data = "otpauth://totp/ITFlow:$session_email?secret=$session_token"; + print ""; echo "

$session_token

"; } diff --git a/functions.php b/functions.php index 12be4fb5..6e0b64f4 100644 --- a/functions.php +++ b/functions.php @@ -212,6 +212,16 @@ function truncate($text, $chars) function formatPhoneNumber($phoneNumber) { + global $mysqli; + + // Get Phone Mask Option + $phone_mask = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_phone_mask FROM settings WHERE company_id = 1"))[0]; + + if ($phone_mask == 0) { + return $phoneNumber; + } + + $phoneNumber = $phoneNumber ? preg_replace('/[^0-9]/', '', $phoneNumber) : ""; if (strlen($phoneNumber) > 10) { @@ -427,9 +437,18 @@ function getDomainRecords($name) // Used to automatically attempt to get SSL certificates as part of adding domains // The logic for the fetch (sync) button on the client_certificates page is in ajax.php, and allows ports other than 443 -function getSSL($name) +function getSSL($full_name) { + // Parse host and port + $name = parse_url("//$full_name", PHP_URL_HOST); + $port = parse_url("//$full_name", PHP_URL_PORT); + + // Default port + if (!$port) { + $port = "443"; + } + $certificate = array(); $certificate['success'] = false; @@ -442,7 +461,7 @@ function getSSL($name) } // Get SSL/TSL certificate (using verify peer false to allow for self-signed certs) for domain on default port - $socket = "ssl://$name:443"; + $socket = "ssl://$name:$port"; $get = stream_context_create(array("ssl" => array("capture_peer_cert" => true, "verify_peer" => false,))); $read = stream_socket_client($socket, $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $get); @@ -881,7 +900,7 @@ function getSettingValue($mysqli, $setting_name) function getMonthlyTax($tax_name, $month, $year, $mysqli) { // SQL to calculate monthly tax - $sql = "SELECT SUM(item_tax) AS monthly_tax FROM invoice_items + $sql = "SELECT SUM(item_tax) AS monthly_tax FROM invoice_items LEFT JOIN invoices ON invoice_items.item_invoice_id = invoices.invoice_id LEFT JOIN payments ON invoices.invoice_id = payments.payment_invoice_id WHERE YEAR(payments.payment_date) = $year AND MONTH(payments.payment_date) = $month @@ -898,7 +917,7 @@ function getQuarterlyTax($tax_name, $quarter, $year, $mysqli) $end_month = $start_month + 2; // SQL to calculate quarterly tax - $sql = "SELECT SUM(item_tax) AS quarterly_tax FROM invoice_items + $sql = "SELECT SUM(item_tax) AS quarterly_tax FROM invoice_items LEFT JOIN invoices ON invoice_items.item_invoice_id = invoices.invoice_id LEFT JOIN payments ON invoices.invoice_id = payments.payment_invoice_id WHERE YEAR(payments.payment_date) = $year AND MONTH(payments.payment_date) BETWEEN $start_month AND $end_month @@ -911,7 +930,7 @@ function getQuarterlyTax($tax_name, $quarter, $year, $mysqli) function getTotalTax($tax_name, $year, $mysqli) { // SQL to calculate total tax - $sql = "SELECT SUM(item_tax) AS total_tax FROM invoice_items + $sql = "SELECT SUM(item_tax) AS total_tax FROM invoice_items LEFT JOIN invoices ON invoice_items.item_invoice_id = invoices.invoice_id LEFT JOIN payments ON invoices.invoice_id = payments.payment_invoice_id WHERE YEAR(payments.payment_date) = $year @@ -1172,3 +1191,34 @@ function getTicketStatusName($ticket_status) { return "Unknown"; } + + +function fetchUpdates() { + + global $repo_branch; + + // Fetch the latest code changes but don't apply them + exec("git fetch", $output, $result); + $latest_version = exec("git rev-parse origin/$repo_branch"); + $current_version = exec("git rev-parse HEAD"); + + if ($current_version == $latest_version) { + $update_message = "No Updates available"; + } else { + $update_message = "New Updates are Available [$latest_version]"; + } + + + + $updates = new stdClass(); + $updates->output = $output; + $updates->result = $result; + $updates->current_version = $current_version; + $updates->latest_version = $latest_version; + $updates->update_message = $update_message; + + + + return $updates; + +} \ No newline at end of file diff --git a/get_settings.php b/get_settings.php index 0b53b9bc..58d5b3a6 100644 --- a/get_settings.php +++ b/get_settings.php @@ -72,6 +72,7 @@ $config_ticket_client_general_notifications = intval($row['config_ticket_client_ $config_ticket_autoclose = intval($row['config_ticket_autoclose']); $config_ticket_autoclose_hours = intval($row['config_ticket_autoclose_hours']); $config_ticket_new_ticket_notification_email = $row['config_ticket_new_ticket_notification_email']; +$config_ticket_default_billable = intval($row['config_ticket_default_billable']); // Cron $config_enable_cron = intval($row['config_enable_cron']); diff --git a/global_search.php b/global_search.php index bc1d0984..96f653cb 100644 --- a/global_search.php +++ b/global_search.php @@ -24,6 +24,7 @@ if (isset($_GET['query'])) { LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 WHERE client_archived_at IS NULL AND client_name LIKE '%$query%' + $access_permission_query ORDER BY client_id DESC LIMIT 5" ); @@ -35,6 +36,7 @@ if (isset($_GET['query'])) { OR contact_email LIKE '%$query%' OR contact_phone LIKE '%$phone_query%' OR contact_mobile LIKE '%$phone_query%') + $access_permission_query ORDER BY contact_id DESC LIMIT 5" ); @@ -43,6 +45,7 @@ if (isset($_GET['query'])) { WHERE vendor_archived_at IS NULL AND vendor_template = 0 AND (vendor_name LIKE '%$query%' OR vendor_phone LIKE '%$phone_query%') + $access_permission_query ORDER BY vendor_id DESC LIMIT 5" ); @@ -50,6 +53,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON domain_client_id = client_id WHERE domain_archived_at IS NULL AND domain_name LIKE '%$query%' + $access_permission_query ORDER BY domain_id DESC LIMIT 5" ); @@ -63,6 +67,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients on document_client_id = clients.client_id WHERE document_archived_at IS NULL AND MATCH(document_content_raw) AGAINST ('$query') + $access_permission_query ORDER BY document_id DESC LIMIT 5" ); @@ -72,6 +77,7 @@ if (isset($_GET['query'])) { WHERE file_archived_at IS NULL AND (file_name LIKE '%$query%' OR file_description LIKE '%$query%') + $access_permission_query ORDER BY file_id DESC LIMIT 5" ); @@ -81,6 +87,7 @@ if (isset($_GET['query'])) { WHERE ticket_archived_at IS NULL AND (ticket_subject LIKE '%$query%' OR ticket_number = '$ticket_num_query') + $access_permission_query ORDER BY ticket_id DESC LIMIT 5" ); @@ -88,6 +95,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON scheduled_ticket_client_id = client_id WHERE scheduled_ticket_subject LIKE '%$query%' OR scheduled_ticket_details LIKE '%$query%' + $access_permission_query ORDER BY scheduled_ticket_id DESC LIMIT 5" ); @@ -96,6 +104,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON login_client_id = client_id WHERE login_archived_at IS NULL AND (login_name LIKE '%$query%' OR login_description LIKE '%$query%') + $access_permission_query ORDER BY login_id DESC LIMIT 5" ); @@ -104,6 +113,7 @@ if (isset($_GET['query'])) { LEFT JOIN categories ON invoice_category_id = category_id WHERE invoice_archived_at IS NULL AND (CONCAT(invoice_prefix,invoice_number) LIKE '%$query%' OR invoice_scope LIKE '%$query%') + $access_permission_query ORDER BY invoice_number DESC LIMIT 5" ); @@ -113,6 +123,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON asset_client_id = client_id WHERE asset_archived_at IS NULL AND (asset_name LIKE '%$query%' OR asset_description LIKE '%$query%' OR asset_type LIKE '%$query%' OR asset_make LIKE '%$query%' OR asset_model LIKE '%$query%' OR asset_serial LIKE '%$query%' OR asset_os LIKE '%$query%' OR asset_ip LIKE '%$query%' OR asset_nat_ip LIKE '%$query%' OR asset_mac LIKE '%$query%' OR asset_status LIKE '%$query%') + $access_permission_query ORDER BY asset_name DESC LIMIT 5" ); @@ -121,6 +132,7 @@ if (isset($_GET['query'])) { LEFT JOIN clients ON ticket_client_id = client_id WHERE ticket_reply_archived_at IS NULL AND (ticket_reply LIKE '%$query%') + $access_permission_query ORDER BY ticket_id DESC, ticket_reply_id ASC LIMIT 20" ); diff --git a/guest_header.php b/guest_header.php index 9010d39a..ab0eff7d 100644 --- a/guest_header.php +++ b/guest_header.php @@ -15,6 +15,12 @@ $user_agent = sanitizeInput($_SERVER['HTTP_USER_AGENT']); $os = sanitizeInput(getOS($user_agent)); $browser = sanitizeInput(getWebBrowser($user_agent)); +// Get Company Name +$sql = mysqli_query($mysqli, "SELECT company_name FROM companies WHERE company_id = 1"); +$row = mysqli_fetch_array($sql); + +$session_company_name = $row['company_name']; + ?> @@ -25,7 +31,7 @@ $browser = sanitizeInput(getWebBrowser($user_agent)); - <?php echo nullable_htmlentities($config_app_name); ?> + <?php echo nullable_htmlentities($session_company_name); ?> - - -purify($row['ticket_details']); $ticket_priority = nullable_htmlentities($row['ticket_priority']); @@ -181,7 +176,7 @@ if (isset($_GET['ticket_id'])) { // Client Tags $client_tag_name_display_array = array(); $client_tag_id_array = array(); - $sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.client_tag_tag_id = tags.tag_id WHERE client_tags.client_tag_client_id = $client_id ORDER BY tag_name ASC"); + $sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.tag_id = tags.tag_id WHERE client_id = $client_id ORDER BY tag_name ASC"); while ($row = mysqli_fetch_array($sql_client_tags)) { $client_tag_id = intval($row['tag_id']); @@ -206,6 +201,22 @@ if (isset($_GET['ticket_id'])) { $row = mysqli_fetch_array($ticket_responses_sql); $ticket_responses = intval($row['ticket_responses']); + $ticket_all_comments_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_all_comments_count FROM ticket_replies WHERE ticket_reply_archived_at IS NULL AND ticket_reply_ticket_id = $ticket_id"); + $row = mysqli_fetch_array($ticket_all_comments_sql); + $ticket_all_comments_count = intval($row['ticket_all_comments_count']); + + $ticket_internal_notes_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_internal_notes_count FROM ticket_replies WHERE ticket_reply_archived_at IS NULL AND ticket_reply_type = 'Internal' AND ticket_reply_ticket_id = $ticket_id"); + $row = mysqli_fetch_array($ticket_internal_notes_sql); + $ticket_internal_notes_count = intval($row['ticket_internal_notes_count']); + + $ticket_public_comments_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_public_comments_count FROM ticket_replies WHERE ticket_reply_archived_at IS NULL AND (ticket_reply_type = 'Public' OR ticket_reply_type = 'Client') AND ticket_reply_ticket_id = $ticket_id"); + $row = mysqli_fetch_array($ticket_public_comments_sql); + $ticket_public_comments_count = intval($row['ticket_public_comments_count']); + + $ticket_events_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_events_count FROM ticket_replies WHERE ticket_reply_archived_at IS NULL AND ticket_reply_type = 'Event' AND ticket_reply_ticket_id = $ticket_id"); + $row = mysqli_fetch_array($ticket_events_sql); + $ticket_events_count = intval($row['ticket_events_count']); + // Get & format asset warranty expiry $date = date('Y-m-d H:i:s'); @@ -371,13 +382,6 @@ if (isset($_GET['ticket_id'])) { -
- Total time worked: -
- @@ -404,18 +408,33 @@ if (isset($_GET['ticket_id'])) {
- + Tasks Completed%
/
- + +
+ Total time worked: +
+ + +
+ + 0) { ?> +
+ +
+ +
@@ -451,7 +470,7 @@ if (isset($_GET['ticket_id'])) { - + Close @@ -513,28 +532,39 @@ if (isset($_GET['ticket_id'])) { +
+
+
+ + + +
-
- -
- -
- - -
- -
- -
+
+ + +
-
+ + + +
+ +
+
-
+
@@ -554,69 +584,32 @@ if (isset($_GET['ticket_id'])) {
- -
- -
+
-
- -
- -
- -
- -
- -
- -
- +
+
+ +
+ +
+ +
+ +
+ +
+ + +
- -
-
- - -
-
- - - - - - -
-
-
- > - -
-
-
-
- +
+ +
@@ -625,7 +618,52 @@ if (isset($_GET['ticket_id'])) { -
Responses ()
+ + +
+
All Comments
+
Public Comments
+
Internal Notes
+
Events
+
Tasks
+
- + @@ -1099,7 +1137,6 @@ require_once "footer.php"; - diff --git a/ticket_add_modal.php b/ticket_add_modal.php index 0ee8c3b0..9cb3f7cb 100644 --- a/ticket_add_modal.php +++ b/ticket_add_modal.php @@ -8,6 +8,7 @@
+
+ +
+
+ value="1" id="billableSwitch"> + +
+
+ +
diff --git a/ticket_edit_modal.php b/ticket_edit_modal.php index e972e0b7..092819a1 100644 --- a/ticket_edit_modal.php +++ b/ticket_edit_modal.php @@ -12,6 +12,7 @@ "> + -
- -
-
- +
+
+
+ +
+
+ +
+ +
+
+
+ +
+
+ +
+
+ +
+ +
-
- +
- -
-
- -
- +
+ value="1" id="billableSwitch"> +
-
diff --git a/tickets.php b/tickets.php index 14954ec4..d68420c6 100644 --- a/tickets.php +++ b/tickets.php @@ -284,7 +284,7 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); Number - Subject + Subject / Tasks Client / Contact @@ -395,6 +395,23 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); $ticket_reply_created_at_time_ago = timeAgo($ticket_reply_created_at); } + + // Get Tasks + $sql_tasks = mysqli_query( $mysqli, "SELECT * FROM tasks WHERE task_ticket_id = $ticket_id ORDER BY task_created_at ASC"); + $task_count = mysqli_num_rows($sql_tasks); + // Get Completed Task Count + $sql_tasks_completed = mysqli_query($mysqli, + "SELECT * FROM tasks + WHERE task_ticket_id = $ticket_id + AND task_completed_at IS NOT NULL" + ); + $completed_task_count = mysqli_num_rows($sql_tasks_completed); + + // Tasks Completed Percent + if($task_count) { + $tasks_completed_percent = round(($completed_task_count / $task_count) * 100); + } + ?> "> @@ -418,6 +435,12 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']); + + +
+
/
+
+ diff --git a/top_nav.php b/top_nav.php index d7db3424..6713fcd2 100644 --- a/top_nav.php +++ b/top_nav.php @@ -29,18 +29,6 @@
- + @@ -114,7 +102,7 @@ - +