Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

This file documents all notable changes made to ITFlow.

## [26.05] Stable Release
### Bug Fixes
- Stripe Payment: Fix adding saved cards on client portal.
- Various client and module enforments fixes.
- Projects: Fix slow load by using an optimized query to count tickets and tasks.
- Show correct currency for the account balance when adding payment to invoice.
- Expire all Password reset tokens nightly with cron.
- Shared Items via secure link: Do not delete shared items that have not been viewed before cron runs.
- Client: Fix Client Abbreviation being converted to an int on edit.

### New Features & Updates
- Bump TinyMCE from 8.4.0 to 8.5.0.
- Bump TCPDF from 6.11.2 to 6.11.3.
- DeBump stripe-php from 20.0.0 to 19.4.1.

## [26.04] Stable Release
### Bug Fixes
- Racks: Fix Device Removal.
Expand Down
2 changes: 2 additions & 0 deletions agent/ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@
$totp_secret = $sql['credential_otp_secret'];
$client_id = intval($sql['credential_client_id']);

enforceClientAccess();

$otp = TokenAuth6238::getTokenCode(strtoupper($totp_secret));
echo json_encode($otp);

Expand Down
4 changes: 4 additions & 0 deletions agent/asset_details.php
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,8 @@
</form>
</div>

<?php if (lookupUserPermission('module_credential')) { // Begin Credential Enforcement ?>

<div class="card card-dark <?php if ($credential_count == 0) { echo "d-none"; } ?>">
<div class="card-header">
<h3 class="card-title"><i class="fa fa-fw fa-key mr-2"></i>Credentials</h3>
Expand Down Expand Up @@ -744,6 +746,8 @@
</div>
</div>

<?php } // End Credential Enforcement ?>

<div class="card card-dark <?php if ($software_count == 0) { echo "d-none"; } ?>">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-cube mr-2"></i>Licenses</h3>
Expand Down
2 changes: 1 addition & 1 deletion agent/client_overview.php
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@

<?php } ?>

<?php if (mysqli_num_rows($sql_favorite_credentials) > 0) { ?>
<?php if ((mysqli_num_rows($sql_favorite_credentials) > 0) && (lookupUserPermission('module_credential'))) { ?>

<div class="col-md-4">

Expand Down
4 changes: 4 additions & 0 deletions agent/contact_details.php
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ class="btn btn-secondary btn-sm" title="Unlink">
</div>
</div>

<?php if (lookupUserPermission('module_credential')) { // Begin Credential Enforcement ?>

<div class="card card-dark <?php if ($credential_count == 0) { echo "d-none"; } ?>">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-key mr-2"></i>Credentials</h3>
Expand Down Expand Up @@ -644,6 +646,8 @@ class="btn btn-secondary btn-sm" title="Unlink">
</div>
</div>

<?php } // End Credential Enforcement ?>

<div class="card card-dark <?php if ($software_count == 0) { echo "d-none"; } ?>">
<div class="card-header py-2">
<h3 class="card-title mt-2"><i class="fa fa-fw fa-cube mr-2"></i>Related Licenses</h3>
Expand Down
2 changes: 1 addition & 1 deletion agent/modals/asset/asset_details.php
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ function updateAssetNotes(asset_id) {
</div>
<?php } ?>

<?php if ($credential_count) { ?>
<?php if (lookupUserPermission('module_credential') && ($credential_count)) { ?>
<div class="tab-pane fade" id="pills-asset-credentials">
<div class="table-responsive-sm-sm">
<table class="table table-sm table-striped table-borderless table-hover">
Expand Down
5 changes: 3 additions & 2 deletions agent/modals/contact/contact_details.php
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@
</a>
<?php } ?>

<?php if ($credential_count) { ?>
<?php
if (lookupUserPermission('module_credential') && ($credential_count)) { ?>
<a class="nav-link <?= ($first_tab === "credentials") ? "active" : "" ?>"
data-toggle="pill"
href="#pills-contact-credentials<?= $contact_id ?>"
Expand Down Expand Up @@ -519,7 +520,7 @@
</div>
<?php } ?>

<?php if ($credential_count) { ?>
<?php if (lookupUserPermission('module_credential') && ($credential_count)) { ?>
<div class="tab-pane fade <?= ($first_tab === "credentials") ? "show active" : "" ?>" id="pills-contact-credentials<?= $contact_id ?>">
<div class="table-responsive-sm">
<table class="table table-striped table-borderless table-hover table-sm dataTables" style="width:100%">
Expand Down
4 changes: 4 additions & 0 deletions agent/modals/credential/credential_edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

require_once '../../../includes/modal_header.php';

enforceUserPermission('module_credential', 2);

$credential_id = intval($_GET['id']);

$sql = mysqli_query($mysqli, "SELECT * FROM credentials WHERE credential_id = $credential_id LIMIT 1");
Expand Down Expand Up @@ -32,6 +34,8 @@
$credential_tag_id_array[] = $credential_tag_id;
}

enforceClientAccess();

// Generate the HTML form content using output buffering.
ob_start();
?>
Expand Down
5 changes: 5 additions & 0 deletions agent/modals/credential/credential_view.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

require_once '../../../includes/modal_header.php';

enforceUserPermission('module_credential');

$credential_id = intval($_GET['id']);

$sql = mysqli_query($mysqli, "SELECT * FROM credentials WHERE credential_id = $credential_id LIMIT 1");

$row = mysqli_fetch_assoc($sql);
$client_id = intval($row['credential_client_id']);
$credential_name = nullable_htmlentities($row['credential_name']);
$credential_description = nullable_htmlentities($row['credential_description']);
$credential_uri = nullable_htmlentities($row['credential_uri']);
Expand All @@ -23,6 +26,8 @@
$credential_note = nullable_htmlentities($row['credential_note']);
$credential_created_at = nullable_htmlentities($row['credential_created_at']);

enforceClientAccess();

// Generate the HTML form content using output buffering.
ob_start();
?>
Expand Down
3 changes: 2 additions & 1 deletion agent/modals/payment/payment_add.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
$account_id = intval($row['account_id']);
$account_name = nullable_htmlentities($row['account_name']);
$opening_balance = floatval($row['opening_balance']);
$account_currency = nullable_htmlentities($row['account_currency_code']);

$sql_payments = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS total_payments FROM payments WHERE payment_account_id = $account_id");
$row = mysqli_fetch_assoc($sql_payments);
Expand All @@ -113,7 +114,7 @@
?>
<option <?php if ($config_default_payment_account == $account_id) { echo "selected"; } ?>
value="<?php echo $account_id; ?>">
<?php echo $account_name; ?> [$<?php echo number_format($account_balance, 2); ?>]
<?php echo $account_name; ?> [<?php echo numfmt_format_currency($currency_format, $account_balance, $account_currency); ?>]
</option>

<?php
Expand Down
2 changes: 1 addition & 1 deletion agent/post/client.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@
);
mysqli_stmt_bind_param(
$query,
"ssssdisiisi",
"ssssdisissi",
$name,
$type,
$website,
Expand Down
26 changes: 8 additions & 18 deletions agent/projects.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,34 +190,24 @@ class="btn btn-<?php if ($archived == 1) { echo "primary"; } else { echo "defaul

// Get Tasks and Tickets Stats
// Get Tickets
$sql_tickets = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_project_id = $project_id");
$ticket_count = mysqli_num_rows($sql_tickets);
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS count FROM tickets WHERE ticket_project_id = $project_id"));
$ticket_count = $row['count'];

// Get Closed Ticket Count
$sql_closed_tickets = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_project_id = $project_id AND ticket_closed_at IS NOT NULL");

$closed_ticket_count = mysqli_num_rows($sql_closed_tickets);
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS count FROM tickets WHERE ticket_project_id = $project_id AND ticket_closed_at IS NOT NULL"));
$closed_ticket_count = $row['count'];

// Ticket Closed Percent
if($ticket_count) {
$tickets_closed_percent = round(($closed_ticket_count / $ticket_count) * 100);
}
// Get All Tasks
$sql_tasks = mysqli_query($mysqli,
"SELECT * FROM tickets, tasks
WHERE ticket_id = task_ticket_id
AND ticket_project_id = $project_id"
);
$task_count = mysqli_num_rows($sql_tasks);
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('task_id') AS count FROM tickets, tasks WHERE ticket_id = task_ticket_id AND ticket_project_id = $project_id"));
$task_count = $row['count'];

// Get Completed Task Count
$sql_tasks_completed = mysqli_query($mysqli,
"SELECT * FROM tickets, tasks
WHERE ticket_id = task_ticket_id
AND ticket_project_id = $project_id
AND task_completed_at IS NOT NULL"
);
$completed_task_count = mysqli_num_rows($sql_tasks_completed);
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('task_id') AS count FROM tickets, tasks WHERE ticket_id = task_ticket_id AND ticket_project_id = $project_id AND task_completed_at IS NOT NULL"));
$completed_task_count = $row['count'];

// Tasks Completed Percent
if($task_count) {
Expand Down
3 changes: 3 additions & 0 deletions agent/ticket_list.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@


// Get Tasks
// Get Tasks
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('task_id') AS count FROM tickets, tasks WHERE ticket_id = task_ticket_id AND ticket_project_id = $project_id"));
$task_count = $row['count'];
$sql_tasks = mysqli_query( $mysqli, "SELECT * FROM tasks WHERE task_ticket_id = $ticket_id ORDER BY task_created_at ASC");
$task_count = mysqli_num_rows($sql_tasks);
// Get Completed Task Count
Expand Down
2 changes: 1 addition & 1 deletion client/post.php
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,7 @@

if (isset($_GET['stripe_save_card'])) {

validateCSRFToken($_GET['csrf_token']);
// validateCSRFToken($_GET['csrf_token']); Broken with Stripe Save Card JQ 2026-5-4

if ($session_contact_primary == 0 && !$session_contact_is_billing_contact) {
redirect("post.php?logout");
Expand Down
3 changes: 2 additions & 1 deletion cron/cron.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,14 @@
mysqli_query($mysqli, "TRUNCATE TABLE ticket_views");

// Clean-up shared items that have been used
mysqli_query($mysqli, "DELETE FROM shared_items WHERE item_views = item_view_limit");
mysqli_query($mysqli, "DELETE FROM shared_items WHERE item_view_limit > 0 AND item_views >= item_view_limit");

// Clean-up shared items that have expired
mysqli_query($mysqli, "DELETE FROM shared_items WHERE item_expire_at < NOW()");

// Invalidate any password reset links
mysqli_query($mysqli, "UPDATE users SET user_password_reset_token = NULL WHERE user_archived_at IS NULL");
mysqli_query($mysqli, "UPDATE users SET user_password_reset_token = NULL"); // TODO: Make this 'expired' tokens only when we actually use expiry

Check warning on line 115 in cron/cron.php

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this "TODO" comment.

See more on https://sonarcloud.io/project/issues?id=itflow-org_itflow&issues=AZ30yfwakfeY0H1DkKHh&open=AZ30yfwakfeY0H1DkKHh&pullRequest=1281

// Clean-up old dismissed notifications
mysqli_query($mysqli, "DELETE FROM notifications WHERE notification_dismissed_at < CURDATE() - INTERVAL 90 DAY");
Expand Down
2 changes: 1 addition & 1 deletion includes/app_version.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.04");
DEFINE("APP_VERSION", "26.05");
5 changes: 5 additions & 0 deletions plugins/TCPDF/CHANGELOG.TXT
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
6.11.3 (2026-04-21)
- Added deprecation notice.
- Improved composer.json.
- Added Makefile for common automation tasks.

6.11.2 (2026-03-03)
- Refactor setCompression().

Expand Down
Loading
Loading