Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
1aa6419
Fix Broken Updating asset noted in asset details modal
johnnyq Nov 17, 2025
a79c1c8
Remove Duplicate get_query_strings code as this is all handled in the…
johnnyq Nov 17, 2025
215fc68
Fix Bulk Ticket Merging due to missing modal footer
johnnyq Nov 17, 2025
b991f78
Introduce subject-based automatic ticket merging/reply detection wher…
Nov 18, 2025
169619c
Merge branch 'develop' of https://github.com/itflow-org/itflow into d…
Nov 18, 2025
3d11926
Add cleanInput function without mysqli_escape_string and converted ad…
johnnyq Nov 22, 2025
ac7623d
Update Add Client to use prepared statments
johnnyq Nov 22, 2025
185ea7d
Fix 'Email from at' On tickets that come from emails, was cuasing dup…
johnnyq Nov 22, 2025
29839d3
Implemented saveBase64Images() to convert base64 <img> tags into real…
johnnyq Nov 23, 2025
48719ce
Add Exclude uploads/documents to gitignore
johnnyq Nov 23, 2025
0bdd578
use saveBase64Image function for edit document as well and when docum…
johnnyq Nov 23, 2025
e73af99
Also Delete Documents/Document_id folder during bulk delete
johnnyq Nov 23, 2025
4353508
Cleanup UI for document details title header
johnnyq Nov 23, 2025
a3b2517
Fix up UI on document details header
johnnyq Nov 23, 2025
414a84d
Focus on Author and Date values
johnnyq Nov 23, 2025
ebd9aae
Add Document Templates to uploads dir
johnnyq Nov 23, 2025
435da99
Add custom folder to uploads for custom uploading for custom modules
johnnyq Nov 23, 2025
18429fd
Remove all side nav Quick adds
johnnyq Nov 23, 2025
a99b19a
Update add and edit Document template to extract base64 images and pl…
johnnyq Nov 23, 2025
4153c91
Add function copyDirectory so when creating a document from a templat…
johnnyq Nov 23, 2025
155b859
Introduce cleanupUnusedImages function to delete referenced files tha…
johnnyq Nov 23, 2025
1a9a368
Process base64 Images for document creation and editing for the API a…
johnnyq Nov 24, 2025
698b416
Add back deleted client edit in post
johnnyq Nov 24, 2025
5ef53b5
Create upload folders for recurring tickets and ticket_templates
johnnyq Nov 24, 2025
c851e54
Fix Decimal not showing on the iphone for specific fields associated …
johnnyq Nov 26, 2025
840460a
Update Bulk Action JS to accept and pass multiple custom name selecto…
johnnyq Nov 26, 2025
0347382
Invoices - Allow specifying discount during creation
Nov 27, 2025
53178b8
Updated bulk action js to pass the checkboxe names into the get array…
johnnyq Nov 27, 2025
5a64b19
Convert Document from Template modal to ajax
johnnyq Nov 27, 2025
a388a27
Convert Bulk Edit Product Category modal to ajax
johnnyq Nov 27, 2025
ba2d6b6
Convert Bulk Edit Product Category modal to ajax
johnnyq Nov 27, 2025
c486e3f
Conver the what should be the last bulk asset interfaces modals to th…
johnnyq Nov 27, 2025
f09d8ff
Fix dupe ticket numbering when being created in parallel Atomically u…
johnnyq Nov 28, 2025
99e2487
Fix dupe race condition with ticket, invoice, quote, project, recurri…
johnnyq Nov 28, 2025
faa94d8
Convert Quote to Invoice to use ajax-modal
johnnyq Nov 28, 2025
7737dbc
Migrate Invoice to Recurring Invoice to an ajax modal
johnnyq Nov 28, 2025
540512a
remove folder location vars as no longer needed as files and document…
johnnyq Nov 28, 2025
78e4787
Bump PHPMailer from 7.0.0 to 7.0.1
johnnyq Nov 28, 2025
3ffef6d
Remove library phpMimeParser as its no longer needed and php-imap web…
johnnyq Nov 28, 2025
cc92a4b
Bump stripe-php from 18.1.0 to 19.0.0
johnnyq Nov 28, 2025
0f8a8d1
Bump TCPDF from 6.10.0 to 6.10.1
johnnyq Nov 28, 2025
29b79b9
Bump TinyMCE from 8.2.0 to 8.2.2
johnnyq Nov 28, 2025
5bb410f
Converted all Document Link Modals to the new ajax-modal, also switch…
johnnyq Dec 1, 2025
fe8df66
Migrate Import/export clients to ajax-modals
johnnyq Dec 2, 2025
e1a5793
Convert all Import / Export Modals to Ajax and a few other lingering …
johnnyq Dec 2, 2025
a430bb9
Add CSV Escaping to the Sample Export CSV Files
johnnyq Dec 2, 2025
81550bd
Ticket merge input - strip text
Dec 3, 2025
10bfbed
Mail queue - introduce a --no-mx-validation flag to bypass recipient …
Dec 3, 2025
7c83ba1
Mail queue - minor comment syntax error
Dec 3, 2025
4a26ea7
Hide Permission Modules on sidenav admin menu as this is not ready fo…
johnnyq Dec 5, 2025
7e39a7e
Merge branch 'develop' of github.com:itflow-org/itflow into develop
johnnyq Dec 5, 2025
0e4cc76
Bump Version for 25.12 updated changelog
johnnyq Dec 6, 2025
523da0d
Added a few more things to the changelog
johnnyq Dec 6, 2025
da561b2
Added php-xml as a requirement
johnnyq Dec 6, 2025
ca5fb2e
refined php-xml ext notice
johnnyq Dec 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@ config.php
uploads/favicon.ico
uploads/clients/*
!uploads/clients/index.php
uploads/custom/*
!uploads/custom/index.php
uploads/documents/*
!uploads/documents/index.php
uploads/document_templates/*
!uploads/document_templates/index.php
uploads/expenses/*
!uploads/expenses/index.php
uploads/recurring_tickets/*
!uploads/recurring_tickets/index.php
uploads/settings/*
!uploads/settings/index.php
uploads/users/*
Expand All @@ -14,6 +22,8 @@ uploads/tmp/*
!uploads/tmp/index.php
uploads/tickets/*
!uploads/tickets/index.php
uploads/ticket_templates/*
!uploads/ticket_templates/index.php
.idea/*
plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/HTML/*
!plugins/htmlpurifier/standalone/HTMLPurifier/DefinitionCache/Serializer/HTML/.gitkeep
Expand Down
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,39 @@

This file documents all notable changes made to ITFlow.

## [25.12] Stable Release

### Breaking Changes ###
- For Existing installs: **php-xml** extension needs to be installed for document creation and editing, new install script does this for you as of Dec 6th 2025. To install php-xml: `sudo apt install php-xml`

### Major Changes
- Consolidated "Files" and "Documents" into a single section called **Files**.

### Bug Fixes
- Resolved issue with updating asset notes in asset details.
- Fixed problem with bulk ticket merging.
- Corrected issue where decimal inputs (e.g., price, cost) weren’t displaying on iPhones in certain forms.
- Added CSV escaping to the sample export data in areas where a sample CSV template is provided.
- Fix a race condition where dupe tickets, invoices, recurring invoices, recurring tickets, quotes will be created using the same number if created in parallel espcecially when using the API.

### New Features & Updates
- Introduced automatic subject-based ticket merging/reply detection. Now, if an email comes from a known contact or domain and the subject matches 95% of a ticket opened in the last 7 days, it will be merged automatically.
- Added `cleanInput` function to sanitize data before inserting it into the database when using MySQLi prepared statements.
- Migrated client post functionality to use MySQLi prepared statements.
- Updated payment method post functionality to use MySQLi prepared statements.
- Implemented `saveBase64Images()` to convert base64-encoded `<img>` tags into actual image files stored under `/uploads/<module>/<id>/` with secure filenames. Added wrapper functions, and updated document creation to use processed image paths.
- For new documents and document templates, images are now stored in `/uploads/documents/$document_id` instead of being stored as base64 in the database, using the `saveBase64Images()` function.
- UI/UX improvements made to the document details page.
- Removed sidebar quick-add options.
- Created new folders in the uploads directory: `documents`, `document_templates`, and `recurring_tickets`.
- Reworked the bulk action function to pass the name arrays, instead of a generic `selected_ids` array. This allows multiple bulk name arrays to be passed at once, currently used for the new file-document merge.
- Big task: Converted the remaining modals to use the new `ajax-modal` system, enabling more flexible flow expansion going forward.
- Mail queue: Added a `--no-mx-validation` flag to bypass recipient domain MX validation.
- Bump PHPMailer from 7.0.0 to 7.0.1.
- Bump stripe-php from 18.1.0 to 19.0.0.
- Bump TCPDF from 6.10.0 to 6.10.1.
- Bump TinyMCE from 8.2.0 to 8.2.2.

## [25.11.1] Maint Release

### Fixes
Expand Down
4 changes: 2 additions & 2 deletions admin/debug.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
'php-mbstring' => 'mbstring',
'php-gd' => 'gd',
'php-zip' => 'zip',
'php-xml' => 'xml',
];

foreach ($extensions as $name => $ext) {
Expand Down Expand Up @@ -682,7 +683,7 @@ function getDirStats($dir) {
</tbody>
</table>
</div>


<!-- Database Structure Comparison Table -->
<h3 class="mt-3">Database Structure Comparison</h3>
Expand Down Expand Up @@ -765,4 +766,3 @@ function getDirStats($dir) {
<?php

require_once "../includes/footer.php";

81 changes: 19 additions & 62 deletions admin/includes/side_nav.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,76 +18,54 @@
<li class="nav-item">
<a href="/admin/users.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "users.php") {echo "active";} ?>">
<i class="nav-icon fas fa-users"></i>
<p>
Users
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/user/user_add.php"></span>
</p>
<p>Users</p>
</a>
</li>
<li class="nav-item">
<a href="/admin/roles.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "roles.php") {echo "active";} ?>">
<i class="nav-icon fas fa-user-shield"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/role/role_add.php"></span>
Roles
</p>
<p>Roles</p>
</a>
</li>
<!-- 2025-12-05 JQ - Hide Permission Modules currently just shows modules

Check warning on line 30 in admin/includes/side_nav.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this commented out code.

See more on https://sonarcloud.io/project/issues?id=itflow-org_itflow&issues=AZr0_tS6v78fvmSAZUf_&open=AZr0_tS6v78fvmSAZUf_&pullRequest=1250
<li class="nav-item">
<a href="/admin/modules.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "modules.php") {echo "active";} ?>">
<i class="nav-icon fas fa-puzzle-piece"></i>
<p>
Modules
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/module/module_add.php"></span>
</p>
<p>Modules</p>
</a>
</li>
-->
<li class="nav-item">
<a href="/admin/api_keys.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "api_keys.php") {echo "active";} ?>">
<i class="nav-icon fas fa-key"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/api/api_key_add.php"></span>
API Keys
</p>
<p>API Keys</p>
</a>
</li>
<li class="nav-header">TAGS & CATEGORIES</li>

<li class="nav-item">
<a href="/admin/tag.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'tag.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-tags"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/tag/tag_add.php"></span>
Tags
</p>
<p>Tags</p>
</a>
</li>
<li class="nav-item">
<a href="/admin/category.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'category.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-list-ul"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/category/category_add.php"></span>
Categories
</p>
<p>Categories</p>
</a>
</li>
<?php if ($config_module_enable_accounting) { ?>
<li class="nav-item">
<a href="/admin/tax.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'tax.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-balance-scale"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/tax/tax_add.php"></span>
Taxes
</p>
<p>Taxes</p>
</a>
</li>
<li class="nav-item">
<a href="/admin/payment_method.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'payment_method.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-hand-holding-usd"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/payment_method/payment_method_add.php"></span>
Payment Methods
</p>
<p>Payment Methods</p>
</a>
</li>
<li class="nav-item">
Expand Down Expand Up @@ -115,25 +93,19 @@
<p>AI Models</p>
</a>
</li>

<?php if ($config_module_enable_ticketing) { ?>
<li class="nav-item">
<a href="/admin/ticket_status.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'ticket_status.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-info-circle"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/ticket_status/ticket_status_add.php"></span>
Ticket Statuses
</p>
<p>Ticket Statuses</p>
</a>
</li>
<?php } ?>
<li class="nav-item">
<a href="/admin/custom_link.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'custom_link.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-external-link-alt"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/custom_link/custom_link_add.php"></span>
Custom Links
</p>
<p>Custom Links</p>
</a>
</li>

Expand All @@ -154,46 +126,31 @@
<li class="nav-item">
<a href="/admin/project_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['project_template.php', 'project_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-project-diagram"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/project_template/project_template_add.php"></span>
Project Templates
</p>
<p>Project Templates</p>
</a>
</li>
<li class="nav-item">
<a href="/admin/ticket_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['ticket_template.php', 'ticket_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-life-ring"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/ticket_template/ticket_template_add.php" data-modal-size="lg"></span>
Ticket Templates
</p>
<p>Ticket Templates</p>
</a>
</li>
<li class="nav-item">
<a href="/admin/vendor_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'vendor_template.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-building"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/vendor_template/vendor_template_add.php"></span>
Vendor Templates
</p>
<p>Vendor Templates</p>
</a>
</li>
<li class="nav-item">
<a href="/admin/software_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'software_template.php' ? 'active' : ''); ?>">
<i class="nav-icon fas fa-rocket"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/software_template/software_template_add.php"></span>
License Templates
</p>
<p>License Templates</p>
</a>
</li>
<li class="nav-item">
<a href="/admin/document_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['document_template.php', 'document_template_details.php']) ? 'active' : ''); ?>">
<i class="nav-icon fas fa-file"></i>
<p>
<span href="#" class="fas fa-plus-circle right ajax-modal" data-modal-url="/admin/modals/document_template/document_template_add.php" data-modal-size="lg"></span>
Document Templates
</p>
<p>Document Templates</p>
</a>
</li>
<?php } ?>
Expand Down Expand Up @@ -341,7 +298,7 @@
</li>

<?php
$sql_custom_links = mysqli_query($mysqli, "SELECT * FROM custom_links
$sql_custom_links = mysqli_query($mysqli, "SELECT * FROM custom_links
WHERE custom_link_location = 4 AND custom_link_archived_at IS NULL
ORDER BY custom_link_order ASC, custom_link_name ASC"
);
Expand Down
6 changes: 3 additions & 3 deletions admin/modals/payment_provider/payment_provider_add.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00">
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00">
</div>
<small class="form-text text-muted">Will not show as an option at Checkout if invoice amount is above this number, 0 disables the threshold check.</small>
</div>
Expand All @@ -79,7 +79,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" placeholder="Enter Percentage">
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" placeholder="Enter Percentage">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
Expand All @@ -90,7 +90,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" placeholder="0.030">
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" placeholder="0.030">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
Expand Down
6 changes: 3 additions & 3 deletions admin/modals/payment_provider/payment_provider_edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00" value="<?php echo $threshold; ?>">
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="threshold" placeholder="1000.00" value="<?php echo $threshold; ?>">
</div>
<small class="form-text text-muted">Will not show as an option at Checkout if above this number</small>
</div>
Expand All @@ -79,7 +79,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-percent"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" value="<?php echo $percent_fee; ?>" placeholder="Enter Percentage">
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,2}" name="percentage_fee" value="<?php echo $percent_fee; ?>" placeholder="Enter Percentage">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
Expand All @@ -90,7 +90,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
</div>
<input type="text" class="form-control" inputmode="numeric" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" value="<?php echo $flat_fee; ?>" placeholder="0.030">
<input type="text" class="form-control" inputmode="decimal" pattern="[0-9]*\.?[0-9]{0,3}" name="flat_fee" value="<?php echo $flat_fee; ?>" placeholder="0.030">
</div>
<small class="form-text text-muted">See <a href="https://stripe.com/pricing" target="_blank">here <i class="fas fa-fw fa-external-link-alt"></i></a> for the latest Stripe Fees.</small>
</div>
Expand Down
Loading