Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
62fb2c9
feat: Add API endpoint to retrieve time worked by technicians on tick…
MadsIversen2024 Feb 9, 2026
bdf8038
Merge pull request #1265 from MydsiIversen/Time-API
wrongecho Feb 9, 2026
1d06e6d
Revert to old ajax-modal js code for now, Fix Assets not lising in cr…
johnnyq Feb 11, 2026
1bee085
Add Report for Client Detail Time Auditing
johnnyq Feb 13, 2026
fd29eb7
Fix Transfer Asset to client due to field change from asset_important…
johnnyq Feb 13, 2026
c0fe981
Fix Ticket Merging regressed from ticket select now use ticket_id ins…
johnnyq Feb 13, 2026
34ba5d0
Properly get the new ticket number for logging in ticket merge
johnnyq Feb 13, 2026
1a7452c
Restrict Agents that are restricted to view certain clients from cal…
johnnyq Feb 13, 2026
97958d5
Missing Generate Password js code in Create Credential modal
johnnyq Feb 13, 2026
3014bba
Update Changelog, Bump App Release
johnnyq Feb 14, 2026
6c057f4
Restrict Tickets presented in ticket listing to client restricted Agents
johnnyq Feb 14, 2026
3148906
ticket Details: Restrict Access to ticket details by restricted Agents
johnnyq Feb 14, 2026
fb9f5d9
ticket Details: Restrict Access to ticket details by restricted agents
johnnyq Feb 14, 2026
ce7daaf
ticket edit modal: Restrict Access to client restricted agents
johnnyq Feb 14, 2026
616635f
client edit modal: Restrict Access to client restricted agents
johnnyq Feb 14, 2026
ccaf152
Add a 0 IN ticket_client_id for no client tickets so agents that are …
johnnyq Feb 14, 2026
2349ef3
Remove 0 in access_permission_query
johnnyq Feb 14, 2026
f9d0a8b
Ticket: Dont display Updated at if null, Move Subject from top ticket…
johnnyq Feb 14, 2026
52b509f
Update Changelog
johnnyq Feb 14, 2026
12b3775
Update Changelog
johnnyq Feb 14, 2026
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
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@

This file documents all notable changes made to ITFlow.

## [26.02.1] Maint Release
### Bug Fixes
- Credentials: Fix Password Generator.
- Calendar: Restrict Events for client restricted agents.
- Ticket Merge: Fix.
- Asset Transfer: Fix.
- Ticket Listing: Restrict Tickets presented in ticket list view from client restricted agents.
- Ticket Details: Deny access to client restricted agents to view tickets without client_id in uri.
- Tickets: Allow agents with restricted client access to view and edit tickets without a client.
- Ticket Change client: Limit selection for agents with restricted client access.
- Ticket Details: Don't display Updated at when null.

### New Features & Updates
- Report: Added Client Detail Auditing.
- API: Added Endpoint to retrieve time worked by agent.
- ajax-modal: Revert to previous JS implementation before 26.02 release.
- Ticket: Move Subject from Ticket main ticket header to ticket details card header.

## [26.02] Stable Release
### Bug Fixes
- Mail Parser - Do not automatically send new ticket notifications to noreply/donotreply addresses.
Expand Down
2 changes: 1 addition & 1 deletion agent/ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@
LEFT JOIN contacts ON contact_id = asset_contact_id
WHERE assets.asset_archived_at IS NULL AND asset_client_id = $client_id
$access_permission_query
ORDER BY asset_important DESC, asset_name"
ORDER BY asset_favorite DESC, asset_name"
);

while ($row = mysqli_fetch_assoc($asset_sql)) {
Expand Down
22 changes: 11 additions & 11 deletions agent/calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@
echo "{ id: $event_id, title: $event_title, start: $event_start, end: $event_end, color: $calendar_color },";
}

//Invoices Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN invoices ON client_id = invoice_client_id $client_query");
// Invoices Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN invoices ON client_id = invoice_client_id $client_query $access_permission_query");
while ($row = mysqli_fetch_assoc($sql)) {
$event_id = intval($row['invoice_id']);
$scope = strval($row['invoice_scope']);
Expand All @@ -193,8 +193,8 @@
echo "{ id: $event_id, title: $event_title, start: $event_start, display: 'list-item', color: 'blue', url: 'invoice.php?invoice_id=$event_id$client_url' },";
}

//Quotes Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN quotes ON client_id = quote_client_id $client_query");
// Quotes Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN quotes ON client_id = quote_client_id $client_query $access_permission_query");
while ($row = mysqli_fetch_assoc($sql)) {
$event_id = intval($row['quote_id']);
$event_title = json_encode($row['quote_prefix'] . $row['quote_number'] . " " . $row['quote_scope']);
Expand All @@ -203,12 +203,12 @@
echo "{ id: $event_id, title: $event_title, start: $event_start, display: 'list-item', color: 'purple', url: 'quote.php?quote_id=$event_id$client_url' },";
}

//Tickets Created
// Tickets Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients
LEFT JOIN tickets ON client_id = ticket_client_id
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
LEFT JOIN users ON ticket_assigned_to = user_id
$client_query"
$client_query $access_permission_query"
);
while ($row = mysqli_fetch_assoc($sql)) {
$event_id = intval($row['ticket_id']);
Expand Down Expand Up @@ -242,7 +242,7 @@
$sql = mysqli_query($mysqli, "SELECT * FROM clients
LEFT JOIN recurring_tickets ON client_id = recurring_ticket_client_id
LEFT JOIN users ON recurring_ticket_assigned_to = user_id
$client_query"
$client_query $access_permission_query"
);
while ($row = mysqli_fetch_assoc($sql)) {
$event_id = intval($row['recurring_ticket_id']);
Expand All @@ -262,12 +262,12 @@
echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'recurring_tickets.php?client_id=$client_id$client_url' },";
}

//Tickets Scheduled
// Tickets Scheduled
$sql = mysqli_query($mysqli, "SELECT * FROM clients
LEFT JOIN tickets ON client_id = ticket_client_id
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
LEFT JOIN users ON ticket_assigned_to = user_id
$client_query AND ticket_schedule IS NOT NULL"
$client_query $access_permission_query AND ticket_schedule IS NOT NULL"
);
while ($row = mysqli_fetch_assoc($sql)) {
$event_id = intval($row['ticket_id']);
Expand Down Expand Up @@ -297,8 +297,8 @@
echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'ticket.php?ticket_id=$event_id$client_url' },";
}

//Vendors Added Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN vendors ON client_id = vendor_client_id $client_query");
// Vendors Added Created
$sql = mysqli_query($mysqli, "SELECT * FROM clients LEFT JOIN vendors ON client_id = vendor_client_id $client_query $access_permission_query");
while ($row = mysqli_fetch_assoc($sql)) {
$event_id = intval($row['vendor_id']);
$client_id = intval($row['client_id']);
Expand Down
2 changes: 1 addition & 1 deletion agent/modals/client/client_edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

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

$sql = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_id = $client_id LIMIT 1");
$sql = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_id = $client_id $access_permission_query LIMIT 1");

$row = mysqli_fetch_assoc($sql);
$client_name = nullable_htmlentities($row['client_name']);
Expand Down
2 changes: 2 additions & 0 deletions agent/modals/credential/credential_add.php
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@
</div>
</form>

<script src="/agent/js/generate_password.js"></script>

<?php

require_once '../../../includes/modal_footer.php';
2 changes: 1 addition & 1 deletion agent/modals/ticket/ticket_bulk_merge.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<select class="form-control select2" name="merge_into_ticket_number" required>
<select class="form-control select2" name="merge_into_ticket_id" required>
<option value=''>- Select a Ticket -</option>
<?php
while ($row = mysqli_fetch_assoc($sql_merge)) {
Expand Down
2 changes: 1 addition & 1 deletion agent/modals/ticket/ticket_change_client.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
</div>
<select class="form-control select2" name="new_client_id" id="client_select" required>
<?php
$sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_lead = 0 AND client_archived_at IS NULL ORDER BY client_name ASC");
$sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_lead = 0 AND client_archived_at IS NULL $access_permission_query ORDER BY client_name ASC");
while ($row = mysqli_fetch_assoc($sql_clients)) {
$client_id_select = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
Expand Down
8 changes: 7 additions & 1 deletion agent/modals/ticket/ticket_edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

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

// Ticket client access overide - This is the only way to show tickets without a client to agents with restricted client access
$access_permission_query_overide = '';
if ($client_access_string) {
$access_permission_query_overide = "AND ticket_client_id IN (0,$client_access_string)";
}

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

$sql = mysqli_query($mysqli, "SELECT * FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id LIMIT 1");
$sql = mysqli_query($mysqli, "SELECT * FROM tickets LEFT JOIN clients ON client_id = ticket_client_id WHERE ticket_id = $ticket_id $access_permission_query_overide LIMIT 1");

$row = mysqli_fetch_assoc($sql);
$client_id = intval($row['client_id']);
Expand Down
4 changes: 2 additions & 2 deletions agent/modals/ticket/ticket_merge.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</button>
</div>
<form action="post.php" method="post" autocomplete="off">
<input type="hidden" id="current_ticket_id" name="ticket_id" value="<?php echo $ticket_id; ?>">
<input type="hidden" id="current_ticket_id" name="ticket_id" value="<?= $ticket_id ?>">
<div class="modal-body">

<div class="alert alert-dark">
Expand All @@ -47,7 +47,7 @@
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<select class="form-control select2" name="merge_into_ticket_number" required>
<select class="form-control select2" name="merge_into_ticket_id" required>
<option value=''>- Select a Ticket -</option>
<?php
while ($row = mysqli_fetch_assoc($sql_merge)) {
Expand Down
4 changes: 2 additions & 2 deletions agent/post/asset.php
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,8 @@

// Create new asset
mysqli_query($mysqli, "
INSERT INTO assets (asset_type, asset_name, asset_description, asset_make, asset_model, asset_serial, asset_os, asset_status, asset_purchase_date, asset_warranty_expire, asset_install_date, asset_notes, asset_important)
SELECT asset_type, asset_name, asset_description, asset_make, asset_model, asset_serial, asset_os, asset_status, asset_purchase_date, asset_warranty_expire, asset_install_date, asset_notes, asset_important
INSERT INTO assets (asset_type, asset_name, asset_description, asset_make, asset_model, asset_serial, asset_os, asset_status, asset_purchase_date, asset_warranty_expire, asset_install_date, asset_notes, asset_favorite)
SELECT asset_type, asset_name, asset_description, asset_make, asset_model, asset_serial, asset_os, asset_status, asset_purchase_date, asset_warranty_expire, asset_install_date, asset_notes, asset_favorite
FROM assets
WHERE asset_id = $current_asset_id
");
Expand Down
14 changes: 7 additions & 7 deletions agent/post/ticket.php
Original file line number Diff line number Diff line change
Expand Up @@ -1052,19 +1052,19 @@

enforceUserPermission('module_support', 2);

$merge_into_ticket_number = intval($_POST['merge_into_ticket_number']); // Parent ticket *number*
$merge_into_ticket_id = intval($_POST['merge_into_ticket_id']); // Parent ticket id
$merge_comment = sanitizeInput($_POST['merge_comment']); // Merge comment
$ticket_reply_type = 'Internal'; // Default all replies to internal

// NEW PARENT ticket details
// Get merge into ticket id (as it may differ from the number)
$sql = mysqli_query($mysqli, "SELECT ticket_id FROM tickets WHERE ticket_number = $merge_into_ticket_number");
$sql = mysqli_query($mysqli, "SELECT ticket_id, ticket_number FROM tickets WHERE ticket_id = $merge_into_ticket_id");
if (mysqli_num_rows($sql) == 0) {
flash_alert("Cannot merge into that ticket.", 'error');
redirect();
}
$merge_row = mysqli_fetch_assoc($sql);
$merge_into_ticket_id = intval($merge_row['ticket_id']); // Parent ticket ID
$merge_into_ticket_number = intval($merge_row['ticket_number']); // Parent ticket Number

// Update & Close the selected tickets
if (isset($_POST['ticket_ids'])) {
Expand Down Expand Up @@ -1815,7 +1815,7 @@
enforceUserPermission('module_support', 2);

$ticket_id = intval($_POST['ticket_id']); // Child ticket ID to be closed
$merge_into_ticket_number = intval($_POST['merge_into_ticket_number']); // Parent ticket *number*
$merge_into_ticket_id = intval($_POST['merge_into_ticket_id']); // Parent ticket id
$merge_comment = sanitizeInput($_POST['merge_comment']); // Merge comment
$move_replies = intval($_POST['merge_move_replies']); // Whether to move replies to the new parent ticket
$ticket_reply_type = 'Internal'; // Default all replies to internal
Expand All @@ -1836,21 +1836,21 @@

// NEW PARENT ticket details
// Get merge into ticket id (as it may differ from the number)
$sql = mysqli_query($mysqli, "SELECT ticket_id, ticket_client_id FROM tickets WHERE ticket_number = $merge_into_ticket_number");
$sql = mysqli_query($mysqli, "SELECT ticket_id, ticket_number, ticket_client_id FROM tickets WHERE ticket_id = $merge_into_ticket_id");
if (mysqli_num_rows($sql) == 0) {
flash_alert("Cannot merge into that ticket.", 'error');
redirect();
}
$merge_row = mysqli_fetch_assoc($sql);
$merge_into_ticket_id = intval($merge_row['ticket_id']);
$client_id = intval($merge_row['ticket_client_id']);
$merge_into_ticket_number = intval($merge_row['ticket_number']);
if ($client_id) {
$has_client = "&client_id=$client_id";
} else {
$has_client = "";
}
// Sanity check
if ($ticket_number == $merge_into_ticket_number) {
if ($ticket_id == $merge_into_ticket_id) {
flash_alert("Cannot merge into the same ticket.", 'error');
redirect();
}
Expand Down
Loading