From 6d1b654d0cf29061f7ecdaf53b453f19c960d130 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 20 Mar 2026 17:44:33 -0400 Subject: [PATCH 01/50] Invoice: Do not apply late fee on first overdue reminder (day 1) --- cron/cron.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cron/cron.php b/cron/cron.php index 71cff90c..4ab6c21a 100644 --- a/cron/cron.php +++ b/cron/cron.php @@ -524,7 +524,7 @@ if ($config_send_invoice_reminders == 1) { // Late Charges - if ($config_invoice_late_fee_enable == 1) { + if ($config_invoice_late_fee_enable == 1 && $day > 1) { $todays_date = date('Y-m-d'); $late_fee_amount = ($invoice_amount * $config_invoice_late_fee_percent) / 100; From 22d33847c36c242fc0fbd2cddd5624ae9deb7299 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 22 Mar 2026 19:53:35 -0400 Subject: [PATCH 02/50] Fix edit client --- agent/post/client.php | 62 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/agent/post/client.php b/agent/post/client.php index 6eb859c2..b5f0ac45 100644 --- a/agent/post/client.php +++ b/agent/post/client.php @@ -260,25 +260,63 @@ if (isset($_POST['edit_client'])) { $client_id = intval($_POST['client_id']); - mysqli_query($mysqli, "UPDATE clients SET client_name = '$name', client_type = '$type', client_website = '$website', client_referral = '$referral', client_rate = $rate, client_net_terms = $net_terms, client_tax_id_number = '$tax_id_number', client_lead = $lead, client_abbreviation = '$abbreviation', client_notes = '$notes' WHERE client_id = $client_id"); + // Update client using prepared statement + $query = mysqli_prepare( + $mysqli, + "UPDATE clients SET + client_name = ?, + client_type = ?, + client_website = ?, + client_referral = ?, + client_rate = ?, + client_net_terms = ?, + client_tax_id_number = ?, + client_lead = ?, + client_abbreviation = ?, + client_notes = ? + WHERE client_id = ?" + ); + mysqli_stmt_bind_param( + $query, + "ssssdisiisi", + $name, + $type, + $website, + $referral, + $rate, + $net_terms, + $tax_id_number, + $lead, + $abbreviation, + $notes, + $client_id + ); + mysqli_stmt_execute($query); - // Create Referral if it doesn't exist - $sql = mysqli_query($mysqli, "SELECT category_name FROM categories WHERE category_type = 'Referral' AND category_archived_at IS NULL AND category_name = '$referral'"); - if(mysqli_num_rows($sql) == 0) { - mysqli_query($mysqli, "INSERT INTO categories SET category_name = '$referral', category_type = 'Referral'"); + // Create referral category if it doesn't exist + $query = mysqli_prepare($mysqli, "SELECT category_name FROM categories WHERE category_type = 'Referral' AND category_archived_at IS NULL AND category_name = ?"); + mysqli_stmt_bind_param($query, "s", $referral); + mysqli_stmt_execute($query); + mysqli_stmt_store_result($query); + if (mysqli_stmt_num_rows($query) == 0) { + $query = mysqli_prepare($mysqli, "INSERT INTO categories SET category_name = ?, category_type = 'Referral'"); + mysqli_stmt_bind_param($query, "s", $referral); + mysqli_stmt_execute($query); logAction("Category", "Create", "$session_name created referral category $referral"); } - // Tags - // Delete existing tags - mysqli_query($mysqli, "DELETE FROM client_tags WHERE client_id = $client_id"); + // Tags - delete existing and re-insert + $query = mysqli_prepare($mysqli, "DELETE FROM client_tags WHERE client_id = ?"); + mysqli_stmt_bind_param($query, "i", $client_id); + mysqli_stmt_execute($query); - // Add new tags - if(isset($_POST['tags'])) { - foreach($_POST['tags'] as $tag) { + if (isset($_POST['tags'])) { + $query = mysqli_prepare($mysqli, "INSERT INTO client_tags SET client_id = ?, tag_id = ?"); + foreach ($_POST['tags'] as $tag) { $tag = intval($tag); - mysqli_query($mysqli, "INSERT INTO client_tags SET client_id = $client_id, tag_id = $tag"); + mysqli_stmt_bind_param($query, "ii", $client_id, $tag); + mysqli_stmt_execute($query); } } From 619dd0d472db9dada3340e7cdee437df9841c012 Mon Sep 17 00:00:00 2001 From: wrongecho Date: Mon, 23 Mar 2026 16:36:15 +0000 Subject: [PATCH 03/50] Fix missing csrf tokens in category modals --- admin/modals/category/category_add.php | 1 + admin/modals/category/category_edit.php | 1 + 2 files changed, 2 insertions(+) diff --git a/admin/modals/category/category_add.php b/admin/modals/category/category_add.php index 8fa6ac74..0d28f1fa 100644 --- a/admin/modals/category/category_add.php +++ b/admin/modals/category/category_add.php @@ -15,6 +15,7 @@ $category_types_array = ['Expense', 'Income', 'Referral', 'Ticket'];
+ +

-
+
"> diff --git a/agent/certificates.php b/agent/certificates.php index bbeb4773..db65cc03 100644 --- a/agent/certificates.php +++ b/agent/certificates.php @@ -148,7 +148,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
diff --git a/agent/clients.php b/agent/clients.php index f7a8e0c9..e5a0dea3 100644 --- a/agent/clients.php +++ b/agent/clients.php @@ -444,7 +444,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); } $client_tag_id_array[] = $client_tag_id; - $client_tag_name_display_array[] = "$client_tag_name"; + $client_tag_name_display_array[] = "$client_tag_name"; } $client_tags_display = implode('', $client_tag_name_display_array); @@ -512,10 +512,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
- +
diff --git a/agent/contacts.php b/agent/contacts.php index 73eacde9..40e9630a 100644 --- a/agent/contacts.php +++ b/agent/contacts.php @@ -288,7 +288,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); -
+
"> diff --git a/agent/credentials.php b/agent/credentials.php index 5ec6a538..4762ecf0 100644 --- a/agent/credentials.php +++ b/agent/credentials.php @@ -276,7 +276,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); -
+
text-nowrap"> diff --git a/agent/domains.php b/agent/domains.php index 926b5034..b3e49292 100644 --- a/agent/domains.php +++ b/agent/domains.php @@ -172,7 +172,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
diff --git a/agent/expenses.php b/agent/expenses.php index 2403b438..f0fa8023 100644 --- a/agent/expenses.php +++ b/agent/expenses.php @@ -202,7 +202,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
"> diff --git a/agent/invoices.php b/agent/invoices.php index 7a7d1009..17466994 100644 --- a/agent/invoices.php +++ b/agent/invoices.php @@ -257,7 +257,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
text-nowrap"> diff --git a/agent/locations.php b/agent/locations.php index 164dba37..bd91d70f 100644 --- a/agent/locations.php +++ b/agent/locations.php @@ -216,7 +216,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); -
+
"> diff --git a/agent/networks.php b/agent/networks.php index 12c5b6a3..88dfacc7 100644 --- a/agent/networks.php +++ b/agent/networks.php @@ -187,7 +187,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
diff --git a/agent/payments.php b/agent/payments.php index 936b03fe..30f294fd 100644 --- a/agent/payments.php +++ b/agent/payments.php @@ -138,7 +138,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));

-
+
text-nowrap"> diff --git a/agent/products.php b/agent/products.php index a0fb9be8..2fed030f 100644 --- a/agent/products.php +++ b/agent/products.php @@ -169,7 +169,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); -
+
text-nowrap"> diff --git a/agent/projects.php b/agent/projects.php index d58ef67c..4809ea7d 100644 --- a/agent/projects.php +++ b/agent/projects.php @@ -108,7 +108,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
text-nowrap"> diff --git a/agent/quotes.php b/agent/quotes.php index f60658c3..f56a2e25 100644 --- a/agent/quotes.php +++ b/agent/quotes.php @@ -91,7 +91,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
text-nowrap"> diff --git a/agent/recurring_expenses.php b/agent/recurring_expenses.php index 27262add..54dc20c1 100644 --- a/agent/recurring_expenses.php +++ b/agent/recurring_expenses.php @@ -63,7 +63,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
"> diff --git a/agent/recurring_invoices.php b/agent/recurring_invoices.php index 44159909..32932b50 100644 --- a/agent/recurring_invoices.php +++ b/agent/recurring_invoices.php @@ -93,7 +93,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
text-nowrap"> diff --git a/agent/recurring_tickets.php b/agent/recurring_tickets.php index 74d76072..bfbec629 100644 --- a/agent/recurring_tickets.php +++ b/agent/recurring_tickets.php @@ -212,7 +212,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
diff --git a/agent/revenues.php b/agent/revenues.php index 67b7240b..2e429d4d 100644 --- a/agent/revenues.php +++ b/agent/revenues.php @@ -60,7 +60,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));

-
+
text-nowrap"> diff --git a/agent/services.php b/agent/services.php index fe542edc..82755085 100644 --- a/agent/services.php +++ b/agent/services.php @@ -110,7 +110,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
"> diff --git a/agent/software.php b/agent/software.php index 2c3bedad..d1ee865d 100644 --- a/agent/software.php +++ b/agent/software.php @@ -146,7 +146,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
text-nowrap"> diff --git a/agent/ticket_list.php b/agent/ticket_list.php index 2bab24e4..82775e5f 100644 --- a/agent/ticket_list.php +++ b/agent/ticket_list.php @@ -3,7 +3,7 @@ -
+
text-nowrap"> diff --git a/agent/transfers.php b/agent/transfers.php index 6d91576b..744b43d6 100644 --- a/agent/transfers.php +++ b/agent/transfers.php @@ -120,7 +120,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
text-nowrap"> diff --git a/agent/trips.php b/agent/trips.php index a2327c8d..bd63a48c 100644 --- a/agent/trips.php +++ b/agent/trips.php @@ -85,7 +85,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
+
"> diff --git a/agent/vendors.php b/agent/vendors.php index a6dbbd0f..ce705df0 100644 --- a/agent/vendors.php +++ b/agent/vendors.php @@ -113,7 +113,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); -
+
text-nowrap"> From bb3e311fb71f408d48575de556cc35b09dfd6f6e Mon Sep 17 00:00:00 2001 From: johnnyq Date: Fri, 27 Mar 2026 17:02:13 -0400 Subject: [PATCH 06/50] Racks: Fix Device Removal --- agent/post/rack.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/post/rack.php b/agent/post/rack.php index 7b953f63..672c49a7 100644 --- a/agent/post/rack.php +++ b/agent/post/rack.php @@ -265,7 +265,7 @@ if (isset($_POST['edit_rack_unit'])) { if (isset($_GET['remove_rack_unit'])) { - validateCSRFToken($_POST['csrf_token']); + validateCSRFToken($_GET['csrf_token']); enforceUserPermission('module_support', 2); From 793b14885b3757a218c01604a6894e72d2a9cc55 Mon Sep 17 00:00:00 2001 From: wrongecho <32306651+wrongecho@users.noreply.github.com> Date: Mon, 30 Mar 2026 10:28:45 +0100 Subject: [PATCH 07/50] Remove unnecessary blank line in account.php --- agent/post/account.php | 1 - 1 file changed, 1 deletion(-) diff --git a/agent/post/account.php b/agent/post/account.php index cd776049..9140d250 100644 --- a/agent/post/account.php +++ b/agent/post/account.php @@ -12,7 +12,6 @@ if (isset($_POST['add_account'])) { enforceUserPermission('module_financial', 2); - $name = sanitizeInput($_POST['name']); $opening_balance = floatval($_POST['opening_balance']); $currency_code = sanitizeInput($_POST['currency_code']); From 35fb8b1ee62276597400240a0bd54fc81743775c Mon Sep 17 00:00:00 2001 From: johnnyq Date: Mon, 30 Mar 2026 11:58:22 -0400 Subject: [PATCH 08/50] Update Changelog for 26.03.1 Release --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e06f7b4b..93907eef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ This file documents all notable changes made to ITFlow. +## [26.03.1] Maint Release +### Bug Fixes +- Racks: Fix Device Removal. +- Table Lists: replace class table-responsive-sm with just table-reponsive was causing ui issues with certain screen sizes. +- Client: Fix Edit erroring on certain characters. +- Category: Fix Add/Edit due to missing CSRF fields. +- Invoice: Do not apply late fee on first overdue reminder (1 day). + ## [26.03] Stable Release ### Bug Fixes - Ticket Templates: Fix Task Sorting. From d8359e1049184b5075134a6b000ee5ab1e6dd168 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Mon, 30 Mar 2026 15:24:09 -0400 Subject: [PATCH 09/50] Network Interface Types: Moved to creatable/editable Categories with common defaults --- admin/category.php | 6 + admin/database_updates.php | 24 +++- agent/modals/asset/asset_interface_add.php | 15 +- .../asset/asset_interface_bulk_edit_type.php | 20 ++- agent/modals/asset/asset_interface_edit.php | 15 +- .../asset/asset_interface_multiple_add.php | 15 +- db.sql | 134 +++++++++++++++++- includes/app_version.php | 2 +- includes/database_version.php | 2 +- includes/load_global_settings.php | 6 - setup/index.php | 10 ++ 11 files changed, 220 insertions(+), 29 deletions(-) diff --git a/admin/category.php b/admin/category.php index 7613c9af..505ac894 100644 --- a/admin/category.php +++ b/admin/category.php @@ -83,6 +83,12 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); } else { echo 'btn-default'; } ?>">Ticket + Network Interface
- +
diff --git a/agent/modals/asset/asset_interface_bulk_edit_type.php b/agent/modals/asset/asset_interface_bulk_edit_type.php index 7796b956..575d428a 100644 --- a/agent/modals/asset/asset_interface_bulk_edit_type.php +++ b/agent/modals/asset/asset_interface_bulk_edit_type.php @@ -24,16 +24,26 @@ ob_start();
diff --git a/admin/database_updates.php b/admin/database_updates.php index 46a22bc7..3b787f05 100644 --- a/admin/database_updates.php +++ b/admin/database_updates.php @@ -4350,13 +4350,25 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Fiber', category_type = 'network_interface', category_order = 7"); // 7 mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'WiFi', category_type = 'network_interface', category_order = 8"); // 8 + + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.3'"); } - // - // // if (CURRENT_DATABASE_VERSION == '2.4.3') { - // // Insert queries here required to update to DB version 2.4.4 + + if (CURRENT_DATABASE_VERSION == '2.4.3') { + // Asset Status + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Ready to Deploy', category_description = 'Asset is configured and ready to be assigned', category_type = 'asset_status', category_order = 1"); // 1 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Deployed', category_description = 'Asset is actively in use and assigned to a client or location', category_type = 'asset_status', category_order = 2"); // 2 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Out for Repair', category_description = 'Asset has been sent out for servicing or repair', category_type = 'asset_status', category_order = 3"); // 3 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Lost', category_description = 'Asset location is unknown and cannot be accounted for', category_type = 'asset_status', category_order = 4"); // 4 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Stolen', category_description = 'Asset has been reported stolen', category_type = 'asset_status', category_order = 5"); // 5 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Retired', category_description = 'Asset has been decommissioned and is no longer in service', category_type = 'asset_status', category_order = 6"); // 6 + } + + // if (CURRENT_DATABASE_VERSION == '2.4.4') { + // // Insert queries here required to update to DB version 2.4.5 // // Then, update the database to the next sequential version - // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.4'"); + // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.5'"); // } } else { diff --git a/admin/modals/category/category_add.php b/admin/modals/category/category_add.php index 40a53221..d4b5715c 100644 --- a/admin/modals/category/category_add.php +++ b/admin/modals/category/category_add.php @@ -60,6 +60,16 @@ $category_types_array = ['Expense', 'Income', 'Referral', 'Ticket']; +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ diff --git a/agent/modals/asset/asset_bulk_edit_status.php b/agent/modals/asset/asset_bulk_edit_status.php index 2e6407f6..6cbca8bd 100644 --- a/agent/modals/asset/asset_bulk_edit_status.php +++ b/agent/modals/asset/asset_bulk_edit_status.php @@ -26,12 +26,21 @@ ob_start();
- +
diff --git a/agent/modals/asset/asset_copy.php b/agent/modals/asset/asset_copy.php index 9b903f12..a02653a9 100644 --- a/agent/modals/asset/asset_copy.php +++ b/agent/modals/asset/asset_copy.php @@ -228,8 +228,20 @@ ob_start(); diff --git a/agent/modals/asset/asset_edit.php b/agent/modals/asset/asset_edit.php index 6d2cccc8..78cc4e37 100644 --- a/agent/modals/asset/asset_edit.php +++ b/agent/modals/asset/asset_edit.php @@ -270,8 +270,20 @@ ob_start(); diff --git a/includes/database_version.php b/includes/database_version.php index af7a117a..53c431bc 100644 --- a/includes/database_version.php +++ b/includes/database_version.php @@ -5,4 +5,4 @@ * It is used in conjunction with database_updates.php */ -DEFINE("LATEST_DATABASE_VERSION", "2.4.3"); +DEFINE("LATEST_DATABASE_VERSION", "2.4.4"); diff --git a/includes/load_global_settings.php b/includes/load_global_settings.php index 98429693..1fad611a 100644 --- a/includes/load_global_settings.php +++ b/includes/load_global_settings.php @@ -243,15 +243,6 @@ $document_types_array = array ( '2'=>'Global Template' ); -$asset_status_array = array ( - 'Ready to Deploy', - 'Deployed', - 'Out for Repair', - 'Lost', - 'Stolen', - 'Retired' -); - $ticket_status_array = array ( 'Open', 'On Hold', diff --git a/setup/index.php b/setup/index.php index efc5a47d..607bf2f4 100644 --- a/setup/index.php +++ b/setup/index.php @@ -593,6 +593,14 @@ if (isset($_POST['add_company_settings'])) { mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Fiber', category_type = 'network_interface', category_order = 7"); // 7 mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'WiFi', category_type = 'network_interface', category_order = 8"); // 8 + // Asset statuses + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Ready to Deploy', category_description = 'Asset is configured and ready to be assigned', category_type = 'asset_status', category_order = 1"); // 1 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Deployed', category_description = 'Asset is actively in use and assigned to a client or location', category_type = 'asset_status', category_order = 2"); // 2 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Out for Repair', category_description = 'Asset has been sent out for servicing or repair', category_type = 'asset_status', category_order = 3"); // 3 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Lost', category_description = 'Asset location is unknown and cannot be accounted for', category_type = 'asset_status', category_order = 4"); // 4 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Stolen', category_description = 'Asset has been reported stolen', category_type = 'asset_status', category_order = 5"); // 5 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Retired', category_description = 'Asset has been decommissioned and is no longer in service', category_type = 'asset_status', category_order = 6"); // 6 + $_SESSION['alert_message'] = "Company $name created"; From 11288ce78242ca43a226ef40bd567aebdbcdd42f Mon Sep 17 00:00:00 2001 From: johnnyq Date: Mon, 30 Mar 2026 17:31:15 -0400 Subject: [PATCH 12/50] Fix missing setting DB Version --- admin/database_updates.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/admin/database_updates.php b/admin/database_updates.php index 3b787f05..79879215 100644 --- a/admin/database_updates.php +++ b/admin/database_updates.php @@ -4363,6 +4363,9 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) { mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Lost', category_description = 'Asset location is unknown and cannot be accounted for', category_type = 'asset_status', category_order = 4"); // 4 mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Stolen', category_description = 'Asset has been reported stolen', category_type = 'asset_status', category_order = 5"); // 5 mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Retired', category_description = 'Asset has been decommissioned and is no longer in service', category_type = 'asset_status', category_order = 6"); // 6 + + mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.4.4'"); + } // if (CURRENT_DATABASE_VERSION == '2.4.4') { From aa194725129d2519c024791ac7e8864b60fc01da Mon Sep 17 00:00:00 2001 From: johnnyq Date: Mon, 30 Mar 2026 17:38:44 -0400 Subject: [PATCH 13/50] Ticket: Fix missing contact in version 1 Create Ticket --- agent/modals/ticket/ticket_add.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agent/modals/ticket/ticket_add.php b/agent/modals/ticket/ticket_add.php index 0d1f3395..9b683c34 100644 --- a/agent/modals/ticket/ticket_add.php +++ b/agent/modals/ticket/ticket_add.php @@ -247,7 +247,7 @@ ob_start();
- Date: Mon, 30 Mar 2026 17:41:52 -0400 Subject: [PATCH 14/50] Update Changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 93907eef..63159769 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ This file documents all notable changes made to ITFlow. - Client: Fix Edit erroring on certain characters. - Category: Fix Add/Edit due to missing CSRF fields. - Invoice: Do not apply late fee on first overdue reminder (1 day). +- Ticket: Fix issue with contact not being added with Add contact modal v1. + +### New Features & Updates +- Categories: Add Description Field. +- Categories: Add DB Field for order. +- Categories: Move Asset Status and Network Interface Type to categories so custom ones can be created and edited. More to come... ## [26.03] Stable Release ### Bug Fixes From 52eb0b9c218a4b54708b7121f35946fcc28ae9db Mon Sep 17 00:00:00 2001 From: johnnyq Date: Tue, 31 Mar 2026 17:19:27 -0400 Subject: [PATCH 15/50] Files: Allow .swb file extensions for MikroTik Backups --- agent/modals/file/file_upload.php | 2 +- agent/post/file.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/agent/modals/file/file_upload.php b/agent/modals/file/file_upload.php index 2cb367fd..8c41b0fa 100644 --- a/agent/modals/file/file_upload.php +++ b/agent/modals/file/file_upload.php @@ -50,7 +50,7 @@ ob_start();
- +
Up to 20 files can be uploaded at once by holding down CTRL and selecting files diff --git a/agent/post/file.php b/agent/post/file.php index 5eb8096b..483aae4a 100644 --- a/agent/post/file.php +++ b/agent/post/file.php @@ -33,7 +33,7 @@ if (isset($_POST['upload_files'])) { 'odt', 'csv', 'xls', 'xlsx', 'ods', 'pptx', 'odp', 'zip', 'tar', 'gz', 'msg', 'json', 'wav', 'mp3', 'ogg', 'mov', 'mp4', 'av1', 'ovpn', 'cfg', 'ps1', 'vsdx', 'drawio', 'pfx', 'pages', 'numbers', 'unf', 'unifi', - 'key', 'bat', 'stk' + 'key', 'bat', 'stk', 'swb' ]; // Loop through each uploaded file From 02d217402ced9d32524ebc9a1379899a36a3847a Mon Sep 17 00:00:00 2001 From: johnnyq Date: Tue, 31 Mar 2026 18:05:16 -0400 Subject: [PATCH 16/50] Categories: Moved note type, software type, rack type to be creatable/editable Categories with common defaults and descriptions --- admin/category.php | 18 +++++ admin/database_updates.php | 26 +++++++ .../software_template_add.php | 15 +++- .../software_template_edit.php | 16 ++++- agent/contact_details.php | 8 +++ agent/modals/contact/contact_note_add.php | 13 +++- agent/modals/rack/rack_add.php | 13 +++- agent/modals/rack/rack_edit.php | 15 +++- agent/modals/software/software_add.php | 13 +++- agent/modals/software/software_edit.php | 16 ++++- includes/load_global_settings.php | 69 ------------------- setup/index.php | 25 +++++++ 12 files changed, 163 insertions(+), 84 deletions(-) diff --git a/admin/category.php b/admin/category.php index 6789f06f..d144b207 100644 --- a/admin/category.php +++ b/admin/category.php @@ -95,6 +95,24 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); } else { echo 'btn-default'; } ?>">Asset Status + Software Type + Rack Type + Contact Note Type diff --git a/admin/modals/software_template/software_template_edit.php b/admin/modals/software_template/software_template_edit.php index d12ccab3..18236c34 100644 --- a/admin/modals/software_template/software_template_edit.php +++ b/admin/modals/software_template/software_template_edit.php @@ -66,8 +66,20 @@ ob_start(); diff --git a/agent/contact_details.php b/agent/contact_details.php index 85256291..0eee557e 100644 --- a/agent/contact_details.php +++ b/agent/contact_details.php @@ -1101,6 +1101,14 @@ if (isset($_GET['contact_id'])) {
'fa-phone-alt', + 'Email'=>'fa-envelope', + 'Meeting'=>'fa-handshake', + 'In Person'=>'fa-people-arrows', + 'Note'=>'fa-sticky-note' + ); + while ($row = mysqli_fetch_assoc($sql_related_notes)) { $contact_note_id = intval($row['contact_note_id']); $contact_note_type = nullable_htmlentities($row['contact_note_type']); diff --git a/agent/modals/contact/contact_note_add.php b/agent/modals/contact/contact_note_add.php index 6c3c8768..a150c4b0 100644 --- a/agent/modals/contact/contact_note_add.php +++ b/agent/modals/contact/contact_note_add.php @@ -32,8 +32,17 @@ ob_start(); diff --git a/agent/modals/rack/rack_add.php b/agent/modals/rack/rack_add.php index 1b09c7cb..284d2248 100644 --- a/agent/modals/rack/rack_add.php +++ b/agent/modals/rack/rack_add.php @@ -43,8 +43,17 @@ ob_start(); diff --git a/agent/modals/rack/rack_edit.php b/agent/modals/rack/rack_edit.php index 93418505..28d980ad 100644 --- a/agent/modals/rack/rack_edit.php +++ b/agent/modals/rack/rack_edit.php @@ -59,8 +59,19 @@ ob_start(); diff --git a/agent/modals/software/software_add.php b/agent/modals/software/software_add.php index b5fc1040..8c98a6f4 100644 --- a/agent/modals/software/software_add.php +++ b/agent/modals/software/software_add.php @@ -79,8 +79,17 @@ ob_start(); diff --git a/agent/modals/software/software_edit.php b/agent/modals/software/software_edit.php index 401d71f6..b456167f 100644 --- a/agent/modals/software/software_edit.php +++ b/agent/modals/software/software_edit.php @@ -86,8 +86,20 @@ ob_start(); diff --git a/includes/load_global_settings.php b/includes/load_global_settings.php index 1fad611a..a496f634 100644 --- a/includes/load_global_settings.php +++ b/includes/load_global_settings.php @@ -195,14 +195,6 @@ $records_per_page_array = array ('5','10','15','20','30','50','100'); include_once "settings_localization_array.php"; - -$category_types_array = array ( - 'Expense', - 'Income', - 'Payment Method', - 'Referral' -); - $asset_types_array = array ( 'Laptop'=>'fa-laptop', 'Desktop'=>'fa-desktop', @@ -220,18 +212,6 @@ $asset_types_array = array ( 'Other'=>'fa-tag' ); -$software_types_array = array ( - 'Software as a Service (SaaS)', - 'Productivity Suites', - 'Web Application', - 'Desktop Application', - 'Mobile Application', - 'Security Software', - 'System Software', - 'Operating System', - 'Other' -); - $license_types_array = array ( 'Device', 'User' @@ -243,58 +223,9 @@ $document_types_array = array ( '2'=>'Global Template' ); -$ticket_status_array = array ( - 'Open', - 'On Hold', - 'Auto Close', - 'Closed' -); - -$industry_select_array = array( - "Accounting", - "Agriculture", - "Automotive", - "Construction", - "Education", - "Entertainent", - "Finance", - "Government", - "Healthcare", - "Hospititality", - "Information Technology", - "Insurance", - "Pharmacy", - "Law", - "Manufacturing", - "Marketing & Advertising", - "Military", - "Non-Profit", - "Real Estate", - "Retail", - "Services", - "Transportation", - "Other" // An 'Other' option for industries not listed -); - $start_page_select_array = array ( 'dashboard.php'=>'Dashboard', 'clients.php'=> 'Client Management', 'tickets.php'=> 'Support Tickets', 'invoices.php' => 'Invoices' ); - -$rack_type_select_array = array( - "Open Wall-Mount", - "Enclosed Wall-Mount", - "Open Floor-Standing", - "Enclosed Floor-Standing", - "Other" -); - -$note_types_array = array ( - 'Call'=>'fa-phone-alt', - 'Email'=>'fa-envelope', - 'Meeting'=>'fa-handshake', - 'In Person'=>'fa-people-arrows', - 'Note'=>'fa-sticky-note' -); diff --git a/setup/index.php b/setup/index.php index 607bf2f4..334420cf 100644 --- a/setup/index.php +++ b/setup/index.php @@ -601,6 +601,31 @@ if (isset($_POST['add_company_settings'])) { mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Stolen', category_description = 'Asset has been reported stolen', category_type = 'asset_status', category_order = 5"); // 5 mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Retired', category_description = 'Asset has been decommissioned and is no longer in service', category_type = 'asset_status', category_order = 6"); // 6 + // Contact note types + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Call', category_description = 'Phone call with a client or contact', category_icon = 'fa-phone-alt', category_type = 'contact_note_type', category_order = 1"); // 1 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Email', category_description = 'Email correspondence with a client or contact', category_icon = 'fa-envelope', category_type = 'contact_note_type', category_order = 2"); // 2 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Meeting', category_description = 'Scheduled meeting with a client or contact', category_icon = 'fa-handshake', category_type = 'contact_note_type', category_order = 3"); // 3 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'In Person', category_description = 'In person visit or on-site interaction', category_icon = 'fa-people-arrows', category_type = 'contact_note_type', category_order = 4"); // 4 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Note', category_description = 'General note or internal comment', category_icon = 'fa-sticky-note', category_type = 'contact_note_type', category_order = 5"); // 5 + + // Rack Types + mysqli_query($mysqli, "INSERT INTO categories SET category_name = '2-Post Open Frame', category_description = 'Two-post open frame rack for patch panels and lightweight equipment', category_type = 'rack_type', category_order = 1"); // 1 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = '4-Post Open Frame', category_description = 'Four-post open frame rack for servers and heavier equipment', category_type = 'rack_type', category_order = 2"); // 2 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = '4-Post Enclosed Cabinet', category_description = 'Four-post enclosed cabinet with doors and sides for secure equipment housing', category_type = 'rack_type', category_order = 3"); // 3 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Wall-Mount Open', category_description = 'Open frame rack mounted directly to a wall for small deployments', category_type = 'rack_type', category_order = 4"); // 4 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Wall-Mount Enclosed', category_description = 'Enclosed cabinet rack mounted to a wall with a locking door', category_type = 'rack_type', category_order = 5"); // 5 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Other', category_description = 'Rack type does not fit any standard category', category_type = 'rack_type', category_order = 6"); // 6 + + // Software Types + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Software as a Service (SaaS)', category_description = 'Cloud-hosted software accessed via a web browser or API', category_type = 'software_type', category_order = 1"); // 1 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Productivity Suite', category_description = 'Bundled office and collaboration tools such as Microsoft 365 or Google Workspace', category_type = 'software_type', category_order = 2"); // 2 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Web Application', category_description = 'Application hosted on a web server and accessed through a browser', category_type = 'software_type', category_order = 3"); // 3 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Desktop Application', category_description = 'Application installed and run locally on a workstation or laptop', category_type = 'software_type', category_order = 4"); // 4 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Mobile Application', category_description = 'Application installed and run on a mobile device or tablet', category_type = 'software_type', category_order = 5"); // 5 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Security Software', category_description = 'Software providing antivirus, endpoint protection, or security monitoring', category_type = 'software_type', category_order = 6"); // 6 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'System Software', category_description = 'Low-level software managing hardware resources and system operations', category_type = 'software_type', category_order = 7"); // 7 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Operating System', category_description = 'Core software managing hardware and providing a platform for applications', category_type = 'software_type', category_order = 8"); // 8 + mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Other', category_description = 'Software type does not fit any standard category', category_type = 'software_type', category_order = 9"); // 9 $_SESSION['alert_message'] = "Company $name created"; From 8591758cd72646fdb54c9296562e9164a8117f44 Mon Sep 17 00:00:00 2001 From: wrongecho Date: Sat, 4 Apr 2026 10:18:21 +0100 Subject: [PATCH 17/50] Fix asset read api - uri_2 --- api/v1/assets/read.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/assets/read.php b/api/v1/assets/read.php index bf3d1d14..1dc1d9d0 100644 --- a/api/v1/assets/read.php +++ b/api/v1/assets/read.php @@ -37,7 +37,7 @@ if (isset($_GET['asset_id'])) { } elseif (isset($_GET['asset_uri_2'])) { // Asset query via uri2 - $uri2 = mysqli_real_escape_string($mysqli, $_GET['asset_uri']); + $uri2 = mysqli_real_escape_string($mysqli, $_GET['asset_uri_2']); $sql = mysqli_query($mysqli, "SELECT * FROM assets WHERE asset_uri_2 = '$uri2' AND asset_client_id LIKE '$client_id' ORDER BY asset_id LIMIT $limit OFFSET $offset"); }else { From 52c2ba69cb0d40c74141bc4d3a1ad01c684dda4e Mon Sep 17 00:00:00 2001 From: wrongecho Date: Sat, 4 Apr 2026 10:49:40 +0100 Subject: [PATCH 18/50] Don't set client ID from POST - this is properly done via require_post_method instead only if it's an all-clients key. --- api/v1/clients/update.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/api/v1/clients/update.php b/api/v1/clients/update.php index 13ec877e..cf2fb52c 100644 --- a/api/v1/clients/update.php +++ b/api/v1/clients/update.php @@ -3,9 +3,6 @@ require_once '../validate_api_key.php'; require_once '../require_post_method.php'; -// Parse Info -$client_id = intval($_POST['client_id']); - // Default $update_count = false; From 9389f2cc91e3494405a45c14664b791d919b0580 Mon Sep 17 00:00:00 2001 From: wrongecho Date: Sat, 4 Apr 2026 10:49:50 +0100 Subject: [PATCH 19/50] More helpful error --- api/v1/update_output.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/v1/update_output.php b/api/v1/update_output.php index da985b54..ed9402be 100644 --- a/api/v1/update_output.php +++ b/api/v1/update_output.php @@ -16,7 +16,7 @@ if (isset($update_count) && is_numeric($update_count) && $update_count > 0) { // Query returned false: something went wrong, or it was declined due to required variables missing else { $return_arr['success'] = "False"; - $return_arr['message'] = "Auth success but update query failed/returned no results. Ensure ALL required variables are provided and database schema is up-to-date. Most likely cause: non-existent module ID (i.e. bad contact ID/ticket ID/etc)."; + $return_arr['message'] = "Auth success but update query failed/returned no results. Ensure ALL required variables are provided and database schema is up-to-date. Most likely cause: non-existent module ID (i.e. bad contact ID/ticket ID/etc) or no rows changed."; // Log any database/schema related errors to the PHP Error log if (mysqli_error($mysqli)) { From 0ae4c2fac9c7f40e2d73d47fb8d83aeaa4671fec Mon Sep 17 00:00:00 2001 From: wrongecho Date: Sat, 4 Apr 2026 10:52:32 +0100 Subject: [PATCH 20/50] - Prevent error 500s when existing data can't be cleanly re-inserted to database - Full support for asset_uri_2 --- api/v1/assets/asset_model.php | 38 +++++++++++++++++++++-------------- api/v1/assets/update.php | 3 +-- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/api/v1/assets/asset_model.php b/api/v1/assets/asset_model.php index b17db3aa..60c90081 100644 --- a/api/v1/assets/asset_model.php +++ b/api/v1/assets/asset_model.php @@ -4,7 +4,7 @@ if (isset($_POST['asset_name'])) { $name = sanitizeInput($_POST['asset_name']); } elseif (isset($asset_row) && isset($asset_row['asset_name'])) { - $name = $asset_row['asset_name']; + $name = mysqli_real_escape_string($mysqli, $asset_row['asset_name']); } else { $name = ''; } @@ -12,7 +12,7 @@ if (isset($_POST['asset_name'])) { if (isset($_POST['asset_description'])) { $description = sanitizeInput($_POST['asset_description']); } elseif (isset($asset_row) && isset($asset_row['asset_description'])) { - $description = $asset_row['asset_description']; + $description = mysqli_real_escape_string($mysqli, $asset_row['asset_description']); } else { $description = ''; } @@ -20,7 +20,7 @@ if (isset($_POST['asset_description'])) { if (isset($_POST['asset_type'])) { $type = sanitizeInput($_POST['asset_type']); } elseif (isset($asset_row) && isset($asset_row['asset_type'])) { - $type = $asset_row['asset_type']; + $type = mysqli_real_escape_string($mysqli, $asset_row['asset_type']); } else { $type = ''; } @@ -28,14 +28,14 @@ if (isset($_POST['asset_type'])) { if (isset($_POST['asset_make'])) { $make = sanitizeInput($_POST['asset_make']); } elseif (isset($asset_row) && isset($asset_row['asset_make'])) { - $make = $asset_row['asset_make']; + $make = mysqli_real_escape_string($mysqli, $asset_row['asset_make']); } else { $make = ''; } if (isset($_POST['asset_model'])) { $model = sanitizeInput($_POST['asset_model']); } elseif (isset($asset_row) && isset($asset_row['asset_model'])) { - $model = $asset_row['asset_model']; + $model = mysqli_real_escape_string($mysqli, $asset_row['asset_model']); } else { $model = ''; } @@ -43,7 +43,7 @@ if (isset($_POST['asset_model'])) { if (isset($_POST['asset_serial'])) { $serial = sanitizeInput($_POST['asset_serial']); } elseif (isset($asset_row) && isset($asset_row['asset_serial'])) { - $serial = $asset_row['asset_serial']; + $serial = mysqli_real_escape_string($mysqli, $asset_row['asset_serial']); } else { $serial = ''; } @@ -51,7 +51,7 @@ if (isset($_POST['asset_serial'])) { if (isset($_POST['asset_os'])) { $os = sanitizeInput($_POST['asset_os']); } elseif (isset($asset_row) && isset($asset_row['asset_os'])) { - $os = $asset_row['asset_os']; + $os = mysqli_real_escape_string($mysqli, $asset_row['asset_os']); } else { $os = ''; } @@ -59,7 +59,7 @@ if (isset($_POST['asset_os'])) { if (isset($_POST['asset_ip'])) { $ip = sanitizeInput($_POST['asset_ip']); } elseif (isset($asset_row) && isset($asset_row['interface_ip'])) { - $ip = $asset_row['interface_ip']; + $ip = mysqli_real_escape_string($mysqli, $asset_row['interface_ip']); } else { $ip = ''; } @@ -67,7 +67,7 @@ if (isset($_POST['asset_ip'])) { if (isset($_POST['asset_mac'])) { $mac = sanitizeInput($_POST['asset_mac']); } elseif (isset($asset_row) && isset($asset_row['interface_mac'])) { - $mac = $asset_row['interface_mac']; + $mac = mysqli_real_escape_string($mysqli, $asset_row['interface_mac']); } else { $mac = ''; } @@ -75,15 +75,23 @@ if (isset($_POST['asset_mac'])) { if (isset($_POST['asset_uri'])) { $uri = sanitizeInput($_POST['asset_uri']); } elseif (isset($asset_row) && isset($asset_row['asset_uri'])) { - $uri = $asset_row['asset_uri']; + $uri = mysqli_real_escape_string($mysqli, $asset_row['asset_uri']); } else { $uri = ''; } +if (isset($_POST['asset_uri_2'])) { + $uri_2 = sanitizeInput($_POST['asset_uri_2']); +} elseif (isset($asset_row) && isset($asset_row['asset_uri_2'])) { + $uri_2 = mysqli_real_escape_string($mysqli, $asset_row['asset_uri_2']); +} else { + $uri_2 = ''; +} + if (isset($_POST['asset_status'])) { $status = sanitizeInput($_POST['asset_status']); } elseif (isset($asset_row) && isset($asset_row['asset_status'])) { - $status = $asset_row['asset_status']; + $status = mysqli_real_escape_string($mysqli, $asset_row['asset_status']); } else { $status = ''; } @@ -91,7 +99,7 @@ if (isset($_POST['asset_status'])) { if (isset($_POST['asset_purchase_date']) && !empty($_POST['asset_purchase_date'])) { $purchase_date = "'" . sanitizeInput($_POST['asset_purchase_date']) . "'"; } elseif (isset($asset_row) && isset($asset_row['asset_purchase_date'])) { - $purchase_date = "'" . $asset_row['asset_purchase_date'] . "'"; + $purchase_date = "'" . mysqli_real_escape_string($mysqli, $asset_row['asset_purchase_date']) . "'"; } else { $purchase_date = "NULL"; } @@ -99,7 +107,7 @@ if (isset($_POST['asset_purchase_date']) && !empty($_POST['asset_purchase_date'] if (isset($_POST['asset_warranty_expire']) && !empty($_POST['asset_warranty_expire'])) { $warranty_expire = "'" . sanitizeInput($_POST['asset_warranty_expire']) . "'"; } elseif (isset($asset_row) && isset($asset_row['asset_warranty_expire'])) { - $warranty_expire = "'" . $asset_row['asset_warranty_expire'] . "'"; + $warranty_expire = "'" . mysqli_real_escape_string($mysqli, $asset_row['asset_warranty_expire']) . "'"; } else { $warranty_expire = "NULL"; } @@ -107,7 +115,7 @@ if (isset($_POST['asset_warranty_expire']) && !empty($_POST['asset_warranty_expi if (isset($_POST['asset_install_date']) && !empty($_POST['asset_install_date'])) { $install_date = "'" . sanitizeInput($_POST['asset_install_date']) . "'"; } elseif (isset($asset_row) && isset($asset_row['asset_install_date'])) { - $install_date = "'" . $asset_row['asset_install_date'] . "'"; + $install_date = "'" . mysqli_real_escape_string($mysqli, $asset_row['asset_install_date']) . "'"; } else { $install_date = "NULL"; } @@ -115,7 +123,7 @@ if (isset($_POST['asset_install_date']) && !empty($_POST['asset_install_date'])) if (isset($_POST['asset_notes'])) { $notes = sanitizeInput($_POST['asset_notes']); } elseif (isset($asset_row) && isset($asset_row['asset_notes'])) { - $notes = $asset_row['asset_notes']; + $notes = mysqli_real_escape_string($mysqli, $asset_row['asset_notes']); } else { $notes = ''; } diff --git a/api/v1/assets/update.php b/api/v1/assets/update.php index 86f59b57..b6d5eb77 100644 --- a/api/v1/assets/update.php +++ b/api/v1/assets/update.php @@ -18,8 +18,7 @@ if (!empty($asset_id)) { // Variable assignment from POST - assigning the current database value if a value is not provided require_once 'asset_model.php'; - - $update_sql = mysqli_query($mysqli, "UPDATE assets SET asset_name = '$name', asset_description = '$description', asset_type = '$type', asset_make = '$make', asset_model = '$model', asset_serial = '$serial', asset_os = '$os', asset_uri = '$uri', asset_status = '$status', asset_location_id = $location, asset_vendor_id = $vendor, asset_contact_id = $contact, asset_purchase_date = $purchase_date, asset_warranty_expire = $warranty_expire, asset_install_date = $install_date, asset_notes = '$notes' WHERE asset_id = $asset_id AND asset_client_id = $client_id LIMIT 1"); + $update_sql = mysqli_query($mysqli, "UPDATE assets SET asset_name = '$name', asset_description = '$description', asset_type = '$type', asset_make = '$make', asset_model = '$model', asset_serial = '$serial', asset_os = '$os', asset_uri = '$uri', asset_uri_2 = '$uri_2', asset_status = '$status', asset_location_id = $location, asset_vendor_id = $vendor, asset_contact_id = $contact, asset_purchase_date = $purchase_date, asset_warranty_expire = $warranty_expire, asset_install_date = $install_date, asset_notes = '$notes' WHERE asset_id = $asset_id AND asset_client_id = $client_id LIMIT 1"); // Check insert & get insert ID if ($update_sql) { From 4617f44cda8a8d5688955e39959c84c70685e532 Mon Sep 17 00:00:00 2001 From: wrongecho Date: Sat, 4 Apr 2026 11:01:34 +0100 Subject: [PATCH 21/50] - Prevent error 500s when existing data can't be cleanly re-inserted to database --- api/v1/clients/client_model.php | 16 ++++++++-------- api/v1/contacts/contact_model.php | 16 ++++++++-------- api/v1/credentials/credential_model.php | 12 ++++++------ api/v1/documents/document_model.php | 8 ++++---- api/v1/locations/location_model.php | 18 +++++++++--------- api/v1/tickets/ticket_model.php | 8 ++++---- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/api/v1/clients/client_model.php b/api/v1/clients/client_model.php index 42321016..4ab7a9c7 100644 --- a/api/v1/clients/client_model.php +++ b/api/v1/clients/client_model.php @@ -5,7 +5,7 @@ if (isset($_POST['client_name'])) { $name = sanitizeInput($_POST['client_name']); } elseif ($client_row) { - $name = $client_row['client_name']; + $name = mysqli_real_escape_string($mysqli, $client_row['client_name']); } else { $name = ''; } @@ -13,7 +13,7 @@ if (isset($_POST['client_name'])) { if (isset($_POST['client_type'])) { $type = sanitizeInput($_POST['client_type']); } elseif ($client_row) { - $type = $client_row['client_type']; + $type = mysqli_real_escape_string($mysqli, $client_row['client_type']); } else { $type = ''; } @@ -21,7 +21,7 @@ if (isset($_POST['client_type'])) { if (isset($_POST['client_website'])) { $website = preg_replace("(^https?://)", "", sanitizeInput($_POST['client_website'])); } elseif ($client_row) { - $website = $client_row['client_website']; + $website = mysqli_real_escape_string($mysqli, $client_row['client_website']); } else { $website = ''; } @@ -29,7 +29,7 @@ if (isset($_POST['client_website'])) { if (isset($_POST['client_referral'])) { $referral = sanitizeInput($_POST['client_referral']); } elseif ($client_row) { - $referral = $client_row['client_referral']; + $referral = mysqli_real_escape_string($mysqli, $client_row['client_referral']); } else { $referral = ''; } @@ -45,7 +45,7 @@ if (isset($_POST['client_rate'])) { if (isset($_POST['client_currency_code'])) { $currency_code = sanitizeInput($_POST['client_currency_code']); } elseif ($client_row) { - $currency_code = $client_row['client_currency_code']; + $currency_code = mysqli_real_escape_string($mysqli, $client_row['client_currency_code']); } else { $currency_code = ''; } @@ -61,7 +61,7 @@ if (isset($_POST['client_net_terms'])) { if (isset($_POST['client_tax_id_number'])) { $tax_id_number = sanitizeInput($_POST['client_tax_id_number']); } elseif ($client_row) { - $tax_id_number = $client_row['client_tax_id_number']; + $tax_id_number = mysqli_real_escape_string($mysqli, $client_row['client_tax_id_number']); } else { $tax_id_number = ''; } @@ -69,7 +69,7 @@ if (isset($_POST['client_tax_id_number'])) { if (isset($_POST['client_abbreviation'])) { $abbreviation = sanitizeInput(substr($_POST['client_abbreviation'], 0, 6)); } elseif ($client_row) { - $abbreviation = $client_row['client_abbreviation']; + $abbreviation = mysqli_real_escape_string($mysqli, $client_row['client_abbreviation']); } else { $abbreviation = ''; } @@ -85,7 +85,7 @@ if (isset($_POST['client_is_lead'])) { if (isset($_POST['client_notes'])) { $notes = sanitizeInput($_POST['client_notes']); } elseif ($client_row) { - $notes = $client_row['client_notes']; + $notes = mysqli_real_escape_string($mysqli, $client_row['client_notes']); } else { $notes = ''; } diff --git a/api/v1/contacts/contact_model.php b/api/v1/contacts/contact_model.php index dbac6bda..e92f4246 100644 --- a/api/v1/contacts/contact_model.php +++ b/api/v1/contacts/contact_model.php @@ -5,7 +5,7 @@ define('number_regex', '/[^0-9]/'); if (isset($_POST['contact_name'])) { $name = sanitizeInput($_POST['contact_name']); } elseif ($contact_row) { - $name = $contact_row['contact_name']; + $name = mysqli_real_escape_string($mysqli, $contact_row['contact_name']); } else { $name = ''; } @@ -13,7 +13,7 @@ if (isset($_POST['contact_name'])) { if (isset($_POST['contact_title'])) { $title = sanitizeInput($_POST['contact_title']); } elseif ($contact_row) { - $title = $contact_row['contact_title']; + $title = mysqli_real_escape_string($mysqli, $contact_row['contact_title']); } else { $title = ''; } @@ -21,7 +21,7 @@ if (isset($_POST['contact_title'])) { if (isset($_POST['contact_department'])) { $department = sanitizeInput($_POST['contact_department']); } elseif ($contact_row) { - $department = $contact_row['contact_department']; + $department = mysqli_real_escape_string($mysqli, $contact_row['contact_department']); } else { $department = ''; } @@ -29,7 +29,7 @@ if (isset($_POST['contact_department'])) { if (isset($_POST['contact_email'])) { $email = sanitizeInput($_POST['contact_email']); } elseif ($contact_row) { - $email = $contact_row['contact_email']; + $email = mysqli_real_escape_string($mysqli, $contact_row['contact_email']); } else { $email = ''; } @@ -37,7 +37,7 @@ if (isset($_POST['contact_email'])) { if (isset($_POST['contact_phone'])) { $phone = preg_replace(number_regex, '', $_POST['contact_phone']); } elseif ($contact_row) { - $phone = $contact_row['contact_phone']; + $phone = mysqli_real_escape_string($mysqli, $contact_row['contact_phone']); } else { $phone = ''; } @@ -45,7 +45,7 @@ if (isset($_POST['contact_phone'])) { if (isset($_POST['contact_extension'])) { $extension = preg_replace(number_regex, '', $_POST['contact_extension']); } elseif ($contact_row) { - $extension = $contact_row['contact_extension']; + $extension = mysqli_real_escape_string($mysqli, $contact_row['contact_extension']); } else { $extension = ''; } @@ -53,7 +53,7 @@ if (isset($_POST['contact_extension'])) { if (isset($_POST['contact_mobile'])) { $mobile = preg_replace(number_regex, '', $_POST['contact_mobile']); } elseif ($contact_row) { - $mobile = $contact_row['contact_mobile']; + $mobile = mysqli_real_escape_string($mysqli, $contact_row['contact_mobile']); } else { $mobile = ''; } @@ -61,7 +61,7 @@ if (isset($_POST['contact_mobile'])) { if (isset($_POST['contact_notes'])) { $notes = sanitizeInput($_POST['contact_notes']); } elseif ($contact_row) { - $notes = $contact_row['contact_notes']; + $notes = mysqli_real_escape_string($mysqli, $contact_row['contact_notes']); } else { $notes = ''; } diff --git a/api/v1/credentials/credential_model.php b/api/v1/credentials/credential_model.php index ac2faf5f..f4243082 100644 --- a/api/v1/credentials/credential_model.php +++ b/api/v1/credentials/credential_model.php @@ -11,7 +11,7 @@ if (isset($_POST['api_key_decrypt_password'])) { if (isset($_POST['credential_name'])) { $name = sanitizeInput($_POST['credential_name']); } elseif (isset($credential_row) && isset($credential_row['credential_name'])) { - $name = $credential_row['credential_name']; + $name = mysqli_real_escape_string($mysqli, $credential_row['credential_name']); } else { $name = ''; } @@ -19,7 +19,7 @@ if (isset($_POST['credential_name'])) { if (isset($_POST['credential_description'])) { $description = sanitizeInput($_POST['credential_description']); } elseif (isset($credential_row) && isset($credential_row['credential_description'])) { - $description = $credential_row['credential_description']; + $description = mysqli_real_escape_string($mysqli, $credential_row['credential_description']); } else { $description = ''; } @@ -27,7 +27,7 @@ if (isset($_POST['credential_description'])) { if (isset($_POST['credential_uri'])) { $uri = sanitizeInput($_POST['credential_uri']); } elseif (isset($credential_row) && isset($credential_row['credential_uri'])) { - $uri = $credential_row['credential_uri']; + $uri = mysqli_real_escape_string($mysqli, $credential_row['credential_uri']); } else { $uri = ''; } @@ -35,7 +35,7 @@ if (isset($_POST['credential_uri'])) { if (isset($_POST['credential_uri_2'])) { $uri_2 = sanitizeInput($_POST['credential_uri_2']); } elseif (isset($credential_row) && isset($credential_row['credential_uri_2'])) { - $uri_2 = $credential_row['credential_uri_2']; + $uri_2 = mysqli_real_escape_string($mysqli, $credential_row['credential_uri_2']); } else { $uri_2 = ''; } @@ -66,7 +66,7 @@ if (isset($_POST['credential_password'])) { if (isset($_POST['credential_otp_secret'])) { $otp_secret = sanitizeInput($_POST['credential_otp_secret']); } elseif (isset($credential_row) && isset($credential_row['credential_otp_secret'])) { - $otp_secret = $credential_row['credential_otp_secret']; + $otp_secret = mysqli_real_escape_string($mysqli, $credential_row['credential_otp_secret']); } else { $otp_secret = ''; } @@ -74,7 +74,7 @@ if (isset($_POST['credential_otp_secret'])) { if (isset($_POST['credential_note'])) { $note = sanitizeInput($_POST['credential_note']); } elseif (isset($credential_row) && isset($credential_row['credential_note'])) { - $note = $credential_row['credential_note']; + $note = mysqli_real_escape_string($mysqli, $credential_row['credential_note']); } else { $note = ''; } diff --git a/api/v1/documents/document_model.php b/api/v1/documents/document_model.php index 75a93d56..47d5962f 100644 --- a/api/v1/documents/document_model.php +++ b/api/v1/documents/document_model.php @@ -4,7 +4,7 @@ if (isset($_POST['document_name'])) { $name = sanitizeInput($_POST['document_name']); } elseif (isset($document_row) && isset($document_row['document_name'])) { - $name = $document_row['document_name']; + $name = mysqli_real_escape_string($mysqli, $document_row['document_name']); } else { $name = ''; } @@ -12,7 +12,7 @@ if (isset($_POST['document_name'])) { if (isset($_POST['document_description'])) { $description = sanitizeInput($_POST['document_description']); } elseif (isset($document_row) && isset($document_row['document_description'])) { - $description = $document_row['document_description']; + $description = mysqli_real_escape_string($mysqli, $document_row['document_description']); } else { $description = ''; } @@ -20,7 +20,7 @@ if (isset($_POST['document_description'])) { if (isset($_POST['document_content'])) { $content = mysqli_real_escape_string($mysqli, $_POST['document_content']); } elseif (isset($document_row) && isset($document_row['document_content'])) { - $content = $document_row['document_content']; + $content = mysqli_real_escape_string($mysqli, $document_row['document_content']); } else { $content = ''; } @@ -29,7 +29,7 @@ if (isset($_POST['document_content'])) { if (isset($_POST['document_content'])) { $content_raw = sanitizeInput($_POST['document_name'] . $_POST['document_description'] . " " . str_replace("<", " <", $_POST['document_content'])); } elseif (isset($document_row) && isset($document_row['document_content_raw'])) { - $content_raw = $document_row['document_content_raw']; + $content_raw = mysqli_real_escape_string($mysqli, $document_row['document_content_raw']); } else { $content_raw = ''; } diff --git a/api/v1/locations/location_model.php b/api/v1/locations/location_model.php index 6f031a79..b177a4e5 100644 --- a/api/v1/locations/location_model.php +++ b/api/v1/locations/location_model.php @@ -5,7 +5,7 @@ if (isset($_POST['location_name'])) { $name = sanitizeInput($_POST['location_name']); } elseif ($location_row) { - $name = $location_row['location_name']; + $name = mysqli_real_escape_string($mysqli, $location_row['location_name']); } else { $name = ''; } @@ -13,7 +13,7 @@ if (isset($_POST['location_name'])) { if (isset($_POST['location_description'])) { $description = sanitizeInput($_POST['location_description']); } elseif ($location_row) { - $description = $location_row['location_description']; + $description = mysqli_real_escape_string($mysqli, $location_row['location_description']); } else { $description = ''; } @@ -21,7 +21,7 @@ if (isset($_POST['location_description'])) { if (isset($_POST['location_country'])) { $country = sanitizeInput($_POST['location_country']); } elseif ($location_row) { - $country = $location_row['location_country']; + $country = mysqli_real_escape_string($mysqli, $location_row['location_country']); } else { $country = ''; } @@ -29,7 +29,7 @@ if (isset($_POST['location_country'])) { if (isset($_POST['location_address'])) { $address = sanitizeInput($_POST['location_address']); } elseif ($location_row) { - $address = $location_row['location_address']; + $address = mysqli_real_escape_string($mysqli, $location_row['location_address']); } else { $address = ''; } @@ -37,7 +37,7 @@ if (isset($_POST['location_address'])) { if (isset($_POST['location_city'])) { $city = sanitizeInput($_POST['location_city']); } elseif ($location_row) { - $city = $location_row['location_city']; + $city = mysqli_real_escape_string($mysqli, $location_row['location_city']); } else { $city = ''; } @@ -45,7 +45,7 @@ if (isset($_POST['location_city'])) { if (isset($_POST['location_state'])) { $state = sanitizeInput($_POST['location_state']); } elseif ($location_row) { - $state = $location_row['location_state']; + $state = mysqli_real_escape_string($mysqli, $location_row['location_state']); } else { $state = ''; } @@ -53,7 +53,7 @@ if (isset($_POST['location_state'])) { if (isset($_POST['location_zip'])) { $zip = sanitizeInput($_POST['location_zip']); } elseif ($location_row) { - $zip = $location_row['location_zip']; + $zip = mysqli_real_escape_string($mysqli, $location_row['location_zip']); } else { $zip = ''; } @@ -61,7 +61,7 @@ if (isset($_POST['location_zip'])) { if (isset($_POST['location_hours'])) { $hours = sanitizeInput($_POST['location_hours']); } elseif ($location_row) { - $hours = $location_row['location_hours']; + $hours = mysqli_real_escape_string($mysqli, $location_row['location_hours']); } else { $hours = ''; } @@ -69,7 +69,7 @@ if (isset($_POST['location_hours'])) { if (isset($_POST['location_notes'])) { $notes = sanitizeInput($_POST['location_notes']); } elseif ($location_row) { - $notes = $location_row['location_notes']; + $notes = mysqli_real_escape_string($mysqli, $location_row['location_notes']); } else { $notes = ''; } diff --git a/api/v1/tickets/ticket_model.php b/api/v1/tickets/ticket_model.php index 633e6905..d6bd2c5d 100644 --- a/api/v1/tickets/ticket_model.php +++ b/api/v1/tickets/ticket_model.php @@ -21,7 +21,7 @@ if (isset($_POST['ticket_asset_id'])) { if (isset($_POST['ticket_subject'])) { $subject = sanitizeInput($_POST['ticket_subject']); } elseif ($ticket_row) { - $subject = $ticket_row['ticket_subject']; + $subject = mysqli_real_escape_string($mysqli, $ticket_row['ticket_subject']); } else { $subject = ''; } @@ -30,16 +30,16 @@ if (isset($_POST['ticket_subject'])) { if (isset($_POST['ticket_priority'])) { $priority = sanitizeInput($_POST['ticket_priority']); } elseif ($ticket_row) { - $priority = $ticket_row['ticket_priority']; + $priority = mysqli_real_escape_string($mysqli, $ticket_row['ticket_priority']); } else { $priority = 'Low'; } if (isset($_POST['ticket_details'])) { - $details = mysqli_escape_string($mysqli, $_POST['ticket_details'] . "
"); + $details = mysqli_real_escape_string($mysqli, $_POST['ticket_details'] . "
"); } elseif ($ticket_row) { - $details = $ticket_row['ticket_details']; + $details = mysqli_real_escape_string($mysqli, $ticket_row['ticket_details']); } else { $details = '< blank >
'; } From 20be416fa647f68016c022a8ef48e8dfd10528d0 Mon Sep 17 00:00:00 2001 From: wrongecho Date: Sat, 4 Apr 2026 11:20:52 +0100 Subject: [PATCH 22/50] API - Fix credential errors since field names changed - Sort domains properly --- api/v1/credentials/create.php | 2 +- api/v1/credentials/credential_model.php | 20 +++++++++----------- api/v1/credentials/update.php | 2 +- api/v1/domains/read.php | 2 +- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/api/v1/credentials/create.php b/api/v1/credentials/create.php index 5fb2b224..44618610 100644 --- a/api/v1/credentials/create.php +++ b/api/v1/credentials/create.php @@ -13,7 +13,7 @@ $insert_id = false; if (!empty($api_key_decrypt_password) && !empty($name) && !(empty($password))) { // Add credential - $insert_sql = mysqli_query($mysqli,"INSERT INTO credentials SET credential_name = '$name', credential_description = '$description', credential_uri = '$uri', credential_uri_2 = '$uri_2', credential_username = '$username', credential_password = '$password', credential_otp_secret = '$otp_secret', credential_note = '$note', credential_important = $important, credential_contact_id = $contact_id, credential_vendor_id = $vendor_id, credential_asset_id = $asset_id, credential_software_id = $software_id, credential_client_id = $client_id"); + $insert_sql = mysqli_query($mysqli,"INSERT INTO credentials SET credential_name = '$name', credential_description = '$description', credential_uri = '$uri', credential_uri_2 = '$uri_2', credential_username = '$username', credential_password = '$password', credential_otp_secret = '$otp_secret', credential_note = '$note', credential_favorite = $favorite, credential_contact_id = $contact_id, credential_asset_id = $asset_id, credential_client_id = $client_id"); // Check insert & get insert ID if ($insert_sql) { diff --git a/api/v1/credentials/credential_model.php b/api/v1/credentials/credential_model.php index f4243082..04531727 100644 --- a/api/v1/credentials/credential_model.php +++ b/api/v1/credentials/credential_model.php @@ -61,8 +61,6 @@ if (isset($_POST['credential_password'])) { $password_changed = false; } - - if (isset($_POST['credential_otp_secret'])) { $otp_secret = sanitizeInput($_POST['credential_otp_secret']); } elseif (isset($credential_row) && isset($credential_row['credential_otp_secret'])) { @@ -79,12 +77,12 @@ if (isset($_POST['credential_note'])) { $note = ''; } -if (isset($_POST['credential_important'])) { - $important = intval($_POST['credential_important']); -} elseif (isset($credential_row) && isset($credential_row['credential_important'])) { - $important = $credential_row['credential_important']; +if (isset($_POST['credential_favorite'])) { + $favorite = intval($_POST['credential_favorite']); +} elseif (isset($credential_row) && isset($credential_row['credential_favorite'])) { + $favorite = $credential_row['credential_favorite']; } else { - $important = ''; + $favorite = 0; } if (isset($_POST['credential_contact_id'])) { @@ -92,7 +90,7 @@ if (isset($_POST['credential_contact_id'])) { } elseif (isset($credential_row) && isset($credential_row['credential_contact_id'])) { $contact_id = $credential_row['credential_contact_id']; } else { - $contact_id = ''; + $contact_id = 0; } if (isset($_POST['credential_vendor_id'])) { @@ -100,7 +98,7 @@ if (isset($_POST['credential_vendor_id'])) { } elseif (isset($credential_row) && isset($credential_row['credential_vendor_id'])) { $vendor_id = $credential_row['credential_vendor_id']; } else { - $vendor_id = ''; + $vendor_id = 0; } if (isset($_POST['credential_asset_id'])) { @@ -108,7 +106,7 @@ if (isset($_POST['credential_asset_id'])) { } elseif (isset($credential_row) && isset($credential_row['credential_asset_id'])) { $asset_id = $credential_row['credential_asset_id']; } else { - $asset_id = ''; + $asset_id = 0; } if (isset($_POST['credential_software_id'])) { @@ -116,5 +114,5 @@ if (isset($_POST['credential_software_id'])) { } elseif (isset($credential_row) && isset($credential_row['credential_software_id'])) { $software_id = $credential_row['credential_software_id']; } else { - $software_id = ''; + $software_id = 0; } diff --git a/api/v1/credentials/update.php b/api/v1/credentials/update.php index 78c4f296..2aff7a6b 100644 --- a/api/v1/credentials/update.php +++ b/api/v1/credentials/update.php @@ -17,7 +17,7 @@ if (!empty($_POST['api_key_decrypt_password']) && !empty($credential_id)) { // Variable assignment from POST - assigning the current database value if a value is not provided require_once 'credential_model.php'; - $update_sql = mysqli_query($mysqli,"UPDATE credentials SET credential_name = '$name', credential_description = '$description', credential_uri = '$uri', credential_uri_2 = '$uri_2', credential_username = '$username', credential_password = '$password', credential_otp_secret = '$otp_secret', credential_note = '$note', credential_important = $important, credential_contact_id = $contact_id, credential_vendor_id = $vendor_id, credential_asset_id = $asset_id, credential_software_id = $software_id, credential_client_id = $client_id WHERE credential_id = '$credential_id' AND credential_client_id = $client_id LIMIT 1"); + $update_sql = mysqli_query($mysqli,"UPDATE credentials SET credential_name = '$name', credential_description = '$description', credential_uri = '$uri', credential_uri_2 = '$uri_2', credential_username = '$username', credential_password = '$password', credential_otp_secret = '$otp_secret', credential_note = '$note', credential_favorite = $favorite, credential_contact_id = $contact_id, credential_asset_id = $asset_id, credential_client_id = $client_id WHERE credential_id = '$credential_id' AND credential_client_id = $client_id LIMIT 1"); // Check insert & get insert ID if ($update_sql) { diff --git a/api/v1/domains/read.php b/api/v1/domains/read.php index b65aab99..6bbd96a2 100644 --- a/api/v1/domains/read.php +++ b/api/v1/domains/read.php @@ -13,7 +13,7 @@ if (isset($_GET['domain_id'])) { } elseif (isset($_GET['domain_name'])) { // Domain by name $name = mysqli_real_escape_string($mysqli, $_GET['domain_name']); - $sql = mysqli_query($mysqli, "SELECT * FROM domains WHERE domain_name = '$name' AND domain_client_id LIKE '$client_id' ORDER BY asset_id LIMIT $limit OFFSET $offset"); + $sql = mysqli_query($mysqli, "SELECT * FROM domains WHERE domain_name = '$name' AND domain_client_id LIKE '$client_id' ORDER BY domain_id LIMIT $limit OFFSET $offset"); } else { // All domains (by client ID or all in general if key permits) From 065e674a68a8b87896507c47c99104698dd1eddb Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 4 Apr 2026 17:38:12 -0400 Subject: [PATCH 23/50] Quotes: Fix Quote Copy missing client --- agent/modals/quote/quote_add.php | 4 ++-- agent/post/quote.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/agent/modals/quote/quote_add.php b/agent/modals/quote/quote_add.php index 3d47bbe7..1eb3d72b 100644 --- a/agent/modals/quote/quote_add.php +++ b/agent/modals/quote/quote_add.php @@ -29,7 +29,7 @@ ob_start(); - +
@@ -38,7 +38,7 @@ ob_start();
- Date: Sat, 4 Apr 2026 17:46:56 -0400 Subject: [PATCH 24/50] Update Changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63159769..58e75556 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ This file documents all notable changes made to ITFlow. - Category: Fix Add/Edit due to missing CSRF fields. - Invoice: Do not apply late fee on first overdue reminder (1 day). - Ticket: Fix issue with contact not being added with Add contact modal v1. +- Quote: Fix Copy was missing client. +- API: Don't set client ID from POST - this is properly done via require_post_method instead only if it's an all-clients key. +- API: Prevent error 500s when existing data can't be cleanly re-inserted to database. +- API: Add more helpful errors. +- API: Fix asset read uri_2 field. +- API: Various other field fixes. ### New Features & Updates - Categories: Add Description Field. From c25b5aac9d908d422abb97880691017ebbbde115 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 4 Apr 2026 17:49:48 -0400 Subject: [PATCH 25/50] Update Changelog --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58e75556..1ba27e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,9 @@ This file documents all notable changes made to ITFlow. ### New Features & Updates - Categories: Add Description Field. - Categories: Add DB Field for order. -- Categories: Move Asset Status and Network Interface Type to categories so custom ones can be created and edited. More to come... +- Categories: Move Asset Status and Network Interface Type to categories so custom ones can be created and edited. +- Categories: Moved note type, software type, rack type to be creatable/editable Categories with common defaults and descriptions +- Files: Allow .swb file for MikroTik Backup Files. ## [26.03] Stable Release ### Bug Fixes From 8a4bb2e80db39fbd42f5c163c92fcab9497cc991 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 4 Apr 2026 17:51:14 -0400 Subject: [PATCH 26/50] Update App version --- CHANGELOG.md | 4 ++-- includes/app_version.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ba27e56..5fc90a83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ This file documents all notable changes made to ITFlow. -## [26.03.1] Maint Release +## [26.04] Stable Release ### Bug Fixes - Racks: Fix Device Removal. - Table Lists: replace class table-responsive-sm with just table-reponsive was causing ui issues with certain screen sizes. @@ -26,7 +26,7 @@ This file documents all notable changes made to ITFlow. ## [26.03] Stable Release ### Bug Fixes -- Ticket Templates: Fix Task Sorting. +- Ticket Templates: Fix Task Sortinhahahg. - Ticket: Lower autoclose setting minimum value from 48 to 24 Hours. - Ticket: Fix Task Approval. - Recurring Ticket: add empty value placeholder for Ticket Frequency. diff --git a/includes/app_version.php b/includes/app_version.php index c04690b7..738d2d0c 100644 --- a/includes/app_version.php +++ b/includes/app_version.php @@ -5,4 +5,4 @@ * Update this file each time we merge develop into master. Format is YY.MM (add a .v if there is more than one release a month. */ -DEFINE("APP_VERSION", "26.03.1"); +DEFINE("APP_VERSION", "26.04"); From 78971d1ccb736dea2c6b1c82bb47bac6eee23c8f Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 4 Apr 2026 18:09:29 -0400 Subject: [PATCH 27/50] Setup cli: add categories to mimic setup web ui --- scripts/setup_cli.php | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/scripts/setup_cli.php b/scripts/setup_cli.php index e055707d..903abd46 100644 --- a/scripts/setup_cli.php +++ b/scripts/setup_cli.php @@ -329,6 +329,50 @@ mysqli_query($mysqli, "INSERT INTO user_roles SET role_id = 3, role_name = 'Admi // Custom Links mysqli_query($mysqli,"INSERT INTO custom_links SET custom_link_name = 'Docs', custom_link_uri = 'https://docs.itflow.org', custom_link_new_tab = 1, custom_link_icon = 'question-circle'"); +// network_interfaces +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Ethernet', category_type = 'network_interface', category_order = 1"); // 1 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'SFP', category_type = 'network_interface', category_order = 2"); // 2 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'SFP+', category_type = 'network_interface', category_order = 3"); // 3 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'QSFP28', category_type = 'network_interface', category_order = 4"); // 4 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'QSFP-DD', category_type = 'network_interface', category_order = 5"); // 5 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Coaxial', category_type = 'network_interface', category_order = 6"); // 6 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Fiber', category_type = 'network_interface', category_order = 7"); // 7 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'WiFi', category_type = 'network_interface', category_order = 8"); // 8 + +// Asset statuses +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Ready to Deploy', category_description = 'Asset is configured and ready to be assigned', category_type = 'asset_status', category_order = 1"); // 1 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Deployed', category_description = 'Asset is actively in use and assigned to a client or location', category_type = 'asset_status', category_order = 2"); // 2 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Out for Repair', category_description = 'Asset has been sent out for servicing or repair', category_type = 'asset_status', category_order = 3"); // 3 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Lost', category_description = 'Asset location is unknown and cannot be accounted for', category_type = 'asset_status', category_order = 4"); // 4 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Stolen', category_description = 'Asset has been reported stolen', category_type = 'asset_status', category_order = 5"); // 5 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Retired', category_description = 'Asset has been decommissioned and is no longer in service', category_type = 'asset_status', category_order = 6"); // 6 + +// Contact note types +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Call', category_description = 'Phone call with a client or contact', category_icon = 'fa-phone-alt', category_type = 'contact_note_type', category_order = 1"); // 1 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Email', category_description = 'Email correspondence with a client or contact', category_icon = 'fa-envelope', category_type = 'contact_note_type', category_order = 2"); // 2 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Meeting', category_description = 'Scheduled meeting with a client or contact', category_icon = 'fa-handshake', category_type = 'contact_note_type', category_order = 3"); // 3 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'In Person', category_description = 'In person visit or on-site interaction', category_icon = 'fa-people-arrows', category_type = 'contact_note_type', category_order = 4"); // 4 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Note', category_description = 'General note or internal comment', category_icon = 'fa-sticky-note', category_type = 'contact_note_type', category_order = 5"); // 5 + +// Rack Types +mysqli_query($mysqli, "INSERT INTO categories SET category_name = '2-Post Open Frame', category_description = 'Two-post open frame rack for patch panels and lightweight equipment', category_type = 'rack_type', category_order = 1"); // 1 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = '4-Post Open Frame', category_description = 'Four-post open frame rack for servers and heavier equipment', category_type = 'rack_type', category_order = 2"); // 2 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = '4-Post Enclosed Cabinet', category_description = 'Four-post enclosed cabinet with doors and sides for secure equipment housing', category_type = 'rack_type', category_order = 3"); // 3 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Wall-Mount Open', category_description = 'Open frame rack mounted directly to a wall for small deployments', category_type = 'rack_type', category_order = 4"); // 4 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Wall-Mount Enclosed', category_description = 'Enclosed cabinet rack mounted to a wall with a locking door', category_type = 'rack_type', category_order = 5"); // 5 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Other', category_description = 'Rack type does not fit any standard category', category_type = 'rack_type', category_order = 6"); // 6 + +// Software Types +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Software as a Service (SaaS)', category_description = 'Cloud-hosted software accessed via a web browser or API', category_type = 'software_type', category_order = 1"); // 1 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Productivity Suite', category_description = 'Bundled office and collaboration tools such as Microsoft 365 or Google Workspace', category_type = 'software_type', category_order = 2"); // 2 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Web Application', category_description = 'Application hosted on a web server and accessed through a browser', category_type = 'software_type', category_order = 3"); // 3 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Desktop Application', category_description = 'Application installed and run locally on a workstation or laptop', category_type = 'software_type', category_order = 4"); // 4 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Mobile Application', category_description = 'Application installed and run on a mobile device or tablet', category_type = 'software_type', category_order = 5"); // 5 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Security Software', category_description = 'Software providing antivirus, endpoint protection, or security monitoring', category_type = 'software_type', category_order = 6"); // 6 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'System Software', category_description = 'Low-level software managing hardware resources and system operations', category_type = 'software_type', category_order = 7"); // 7 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Operating System', category_description = 'Core software managing hardware and providing a platform for applications', category_type = 'software_type', category_order = 8"); // 8 +mysqli_query($mysqli, "INSERT INTO categories SET category_name = 'Other', category_description = 'Software type does not fit any standard category', category_type = 'software_type', category_order = 9"); // 9 + // Finalizing mysqli_query($mysqli,"UPDATE companies SET company_locale = '$locale', company_currency = '$currency_code' WHERE company_id = 1"); mysqli_query($mysqli,"UPDATE settings SET config_timezone = '$timezone' WHERE company_id = 1"); From e7ed88e10ebb03db853a5430fea3e70771a4e355 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 4 Apr 2026 18:14:13 -0400 Subject: [PATCH 28/50] Remove custom_hosting tables from db.sql --- db.sql | 128 +-------------------------------------------------------- 1 file changed, 1 insertion(+), 127 deletions(-) diff --git a/db.sql b/db.sql index a1c36a53..b9b8b8e8 100644 --- a/db.sql +++ b/db.sql @@ -962,132 +962,6 @@ CREATE TABLE `custom_fields` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; --- --- Table structure for table `custom_hosting_api_keys` --- - -DROP TABLE IF EXISTS `custom_hosting_api_keys`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `custom_hosting_api_keys` ( - `api_key_id` int(11) NOT NULL AUTO_INCREMENT, - `api_key_name` varchar(200) NOT NULL, - `api_key_url` varchar(250) NOT NULL, - `api_key_token_id` varchar(200) NOT NULL, - `api_key_token_secret` varchar(250) NOT NULL, - `api_key_created_at` datetime NOT NULL DEFAULT current_timestamp(), - PRIMARY KEY (`api_key_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `custom_hosting_networks` --- - -DROP TABLE IF EXISTS `custom_hosting_networks`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `custom_hosting_networks` ( - `network_id` int(11) NOT NULL AUTO_INCREMENT, - `network_name` varchar(200) NOT NULL, - `network` varchar(100) NOT NULL, - `network_mask` varchar(100) NOT NULL, - `gateway` varchar(100) NOT NULL, - `network_start` varchar(100) NOT NULL, - `network_end` varchar(100) NOT NULL, - PRIMARY KEY (`network_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `custom_hosting_plans` --- - -DROP TABLE IF EXISTS `custom_hosting_plans`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `custom_hosting_plans` ( - `plan_id` int(11) NOT NULL AUTO_INCREMENT, - `plan_name` varchar(250) NOT NULL, - `plan_description` text NOT NULL, - `plan_created_at` datetime NOT NULL DEFAULT current_timestamp(), - PRIMARY KEY (`plan_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `custom_hosting_regions` --- - -DROP TABLE IF EXISTS `custom_hosting_regions`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `custom_hosting_regions` ( - `region_id` int(11) NOT NULL AUTO_INCREMENT, - `region_name` varchar(200) NOT NULL, - `region_created_at` datetime NOT NULL DEFAULT current_timestamp(), - PRIMARY KEY (`region_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `custom_hosting_servers` --- - -DROP TABLE IF EXISTS `custom_hosting_servers`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `custom_hosting_servers` ( - `server_id` int(11) NOT NULL AUTO_INCREMENT, - `server_node` varchar(200) NOT NULL, - `server_storage` varchar(200) NOT NULL, - `server_created_at` datetime NOT NULL DEFAULT current_timestamp(), - `server_region_id` int(11) NOT NULL, - `server_api_key_id` varchar(200) NOT NULL, - PRIMARY KEY (`server_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `custom_hosting_vm_templates` --- - -DROP TABLE IF EXISTS `custom_hosting_vm_templates`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `custom_hosting_vm_templates` ( - `template_id` int(11) NOT NULL AUTO_INCREMENT, - `template_name` varchar(200) NOT NULL, - `vcpus` int(11) NOT NULL, - `memory` int(11) NOT NULL, - `disk` int(11) NOT NULL, - `template_created_at` datetime NOT NULL DEFAULT current_timestamp(), - `template_plan_id` int(11) NOT NULL, - PRIMARY KEY (`template_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Table structure for table `custom_hosting_vms` --- - -DROP TABLE IF EXISTS `custom_hosting_vms`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8mb4 */; -CREATE TABLE `custom_hosting_vms` ( - `vm_id` int(11) NOT NULL AUTO_INCREMENT, - `vm_hostname` varchar(200) NOT NULL, - `vm_ip` varchar(100) NOT NULL, - `vm_created_at` datetime NOT NULL DEFAULT current_timestamp(), - `vm_network_id` int(11) NOT NULL, - `vm_server_id` int(11) NOT NULL, - `vm_template_id` int(11) NOT NULL, - `vm_recurring_invoice_id` int(11) DEFAULT NULL, - `vm_client_id` int(11) NOT NULL, - PRIMARY KEY (`vm_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - -- -- Table structure for table `custom_links` -- @@ -3123,4 +2997,4 @@ CREATE TABLE `vendors` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2026-03-30 15:22:51 +-- Dump completed on 2026-04-04 18:13:53 From c434b5e6f02f9b752b3ead4f62a64bd4c6d9bce3 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sat, 4 Apr 2026 18:22:05 -0400 Subject: [PATCH 29/50] Categories: Fix Restore function and restore icon and color --- admin/category.php | 4 ++-- admin/post/category.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/admin/category.php b/admin/category.php index d144b207..16bca100 100644 --- a/admin/category.php +++ b/admin/category.php @@ -166,9 +166,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); -
- Restore + Restore diff --git a/admin/post/category.php b/admin/post/category.php index ac68dd7e..0a6bccf7 100644 --- a/admin/post/category.php +++ b/admin/post/category.php @@ -68,7 +68,7 @@ if (isset($_GET['restore_category'])) { validateCSRFToken($_GET['csrf_token']); - $category_id = intval($_GET['retore_category']); + $category_id = intval($_GET['restore_category']); // Get Category Name and Type for logging $sql = mysqli_query($mysqli,"SELECT category_name, category_type FROM categories WHERE category_id = $category_id"); From fae74a8b1e27b7571a12cbe7675d2059aa1aa224 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 5 Apr 2026 11:48:07 -0400 Subject: [PATCH 30/50] Software: Add Additional License Types --- CHANGELOG.md | 1 + admin/settings_theme.php | 126 ++++++++++++++++++------------ agent/project_details.php | 5 +- includes/load_global_settings.php | 29 ++----- 4 files changed, 83 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fc90a83..d84cd6ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This file documents all notable changes made to ITFlow. - Table Lists: replace class table-responsive-sm with just table-reponsive was causing ui issues with certain screen sizes. - Client: Fix Edit erroring on certain characters. - Category: Fix Add/Edit due to missing CSRF fields. +- Category: Fix Restore function and Icon and text color. - Invoice: Do not apply late fee on first overdue reminder (1 day). - Ticket: Fix issue with contact not being added with Add contact modal v1. - Quote: Fix Copy was missing client. diff --git a/admin/settings_theme.php b/admin/settings_theme.php index 80957ff1..6e5cc6a5 100644 --- a/admin/settings_theme.php +++ b/admin/settings_theme.php @@ -1,68 +1,90 @@ -
- diff --git a/includes/load_global_settings.php b/includes/load_global_settings.php index a496f634..3cd7829f 100644 --- a/includes/load_global_settings.php +++ b/includes/load_global_settings.php @@ -135,28 +135,6 @@ $config_whitelabel_key = $row['config_whitelabel_key']; // Select Arrays - -$theme_colors_array = array ( - 'lightblue', - 'blue', - 'cyan', - 'green', - 'olive', - 'teal', - 'red', - 'maroon', - 'pink', - 'purple', - 'indigo', - 'fuchsia', - 'yellow', - 'orange', - 'yellow', - 'black', - 'navy', - 'gray' -); - $colors_array = array ( 'lightblue', 'blue', @@ -214,7 +192,12 @@ $asset_types_array = array ( $license_types_array = array ( 'Device', - 'User' + 'User', + 'Site', + 'Concurrent', + 'Trial', + 'Perpetual', + 'Usage-based' ); $document_types_array = array ( From b79a6c390e54772c87a42f07bdde9e14d66177bf Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 5 Apr 2026 12:00:56 -0400 Subject: [PATCH 31/50] Move some arrays out of load global settings and into their own entity --- .../software_template_add.php | 10 ++++++ .../software_template_edit.php | 12 ++++++- admin/settings_default.php | 22 ++++++++++-- agent/modals/client/client_add.php | 11 ++++++ .../client/client_bulk_edit_net_terms.php | 11 ++++++ agent/modals/client/client_edit.php | 14 +++++++- agent/modals/software/software_add.php | 10 ++++++ agent/modals/software/software_edit.php | 13 ++++++- includes/load_global_settings.php | 34 ------------------- 9 files changed, 98 insertions(+), 39 deletions(-) diff --git a/admin/modals/software_template/software_template_add.php b/admin/modals/software_template/software_template_add.php index f1db368a..8434c1a0 100644 --- a/admin/modals/software_template/software_template_add.php +++ b/admin/modals/software_template/software_template_add.php @@ -2,6 +2,16 @@ require_once '../../../includes/modal_header.php'; +$license_types_array = array ( + 'Device', + 'User', + 'Site', + 'Concurrent', + 'Trial', + 'Perpetual', + 'Usage-based' +); + ob_start(); ?> diff --git a/admin/modals/software_template/software_template_edit.php b/admin/modals/software_template/software_template_edit.php index 18236c34..df9156f7 100644 --- a/admin/modals/software_template/software_template_edit.php +++ b/admin/modals/software_template/software_template_edit.php @@ -13,8 +13,18 @@ $software_type = nullable_htmlentities($row['software_template_type']); $software_license_type = nullable_htmlentities($row['software_template_license_type']); $software_notes = nullable_htmlentities($row['software_template_notes']); -// Generate the HTML form content using output buffering. +$license_types_array = array ( + 'Device', + 'User', + 'Site', + 'Concurrent', + 'Trial', + 'Perpetual', + 'Usage-based' +); + ob_start(); + ?>
- +
@@ -494,7 +494,6 @@ if (isset($_GET['project_id'])) {