mirror of
https://github.com/itflow-org/itflow
synced 2026-07-26 18:27:14 +00:00
Replaces the duplicated primary/billing/technical checks across portal pages, post.php handlers, nav, and dashboard with contactCan()/enforceContactCan(). Same behavior, but the rules now live in one place instead of being copy-pasted, which is what let them drift before. file.php keeps its 404 response; ticket-visibility and approval-routing checks are intentionally left as-is.
106 lines
3.8 KiB
PHP
106 lines
3.8 KiB
PHP
<?php
|
|
/*
|
|
* Client Portal
|
|
* Functions
|
|
*/
|
|
|
|
/*
|
|
* Verifies a contact has access to a particular ticket ID, and that the ticket is in the correct state (open/closed) to perform an action
|
|
*/
|
|
function verifyContactTicketAccess($requested_ticket_id, $expected_ticket_state) {
|
|
|
|
// Access the global variables
|
|
global $mysqli, $session_contact_id, $session_contact_primary, $session_contact_is_technical_contact, $session_client_id;
|
|
|
|
// Setup
|
|
if ($expected_ticket_state == "Closed") {
|
|
// Closed tickets
|
|
$ticket_state_snippet = "ticket_status = 5";
|
|
} else {
|
|
// Open (working/hold) tickets
|
|
$ticket_state_snippet = "ticket_status != 5";
|
|
}
|
|
|
|
// Verify the contact has access to the provided ticket ID
|
|
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $requested_ticket_id AND $ticket_state_snippet AND ticket_client_id = $session_client_id LIMIT 1"));
|
|
if ($row) {
|
|
$ticket_id = $row['ticket_id'];
|
|
|
|
if (intval($ticket_id) && ($session_contact_id == $row['ticket_contact_id'] || $session_contact_primary == 1 || $session_contact_is_technical_contact)) {
|
|
// Client is ticket owner, primary contact, or a technical contact
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Client is NOT ticket owner or primary/tech contact
|
|
return false;
|
|
|
|
}
|
|
|
|
/*
|
|
* Portal access control - single source of truth for what a logged-in contact can do.
|
|
* Primary contacts have full access; others are gated by their billing / technical flags.
|
|
* Capabilities are named by area so the rule for one can change without touching callers.
|
|
*/
|
|
function contactCan($capability) {
|
|
global $session_contact_primary, $session_contact_is_billing_contact, $session_contact_is_technical_contact;
|
|
|
|
// Primary contacts can do everything in the portal
|
|
if ($session_contact_primary == 1) {
|
|
return true;
|
|
}
|
|
|
|
switch ($capability) {
|
|
case 'accounting': // invoices, quotes, recurring invoices, saved payment methods
|
|
return (bool) $session_contact_is_billing_contact;
|
|
|
|
case 'itdoc': // assets, certificates, domains, documents, files
|
|
case 'contacts': // view / manage contacts
|
|
return (bool) $session_contact_is_technical_contact;
|
|
|
|
default: // unknown capability -> deny (fail closed)
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Enforce a capability at the top of a page or handler - bounce the contact out if they lack it.
|
|
*/
|
|
function enforceContactCan($capability) {
|
|
if (!contactCan($capability)) {
|
|
redirect("post.php?logout");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns appropriate FontAwesome icon for file extension
|
|
*/
|
|
function getFileIcon($file_extension) {
|
|
$file_extension = strtolower($file_extension);
|
|
|
|
// Document icons
|
|
if (in_array($file_extension, ['pdf'])) {
|
|
return 'file-pdf';
|
|
} elseif (in_array($file_extension, ['doc', 'docx'])) {
|
|
return 'file-word';
|
|
} elseif (in_array($file_extension, ['xls', 'xlsx'])) {
|
|
return 'file-excel';
|
|
} elseif (in_array($file_extension, ['ppt', 'pptx'])) {
|
|
return 'file-powerpoint';
|
|
} elseif (in_array($file_extension, ['txt', 'md', 'rtf'])) {
|
|
return 'file-alt';
|
|
} elseif (in_array($file_extension, ['zip', 'rar', '7z', 'tar', 'gz'])) {
|
|
return 'file-archive';
|
|
} elseif (in_array($file_extension, ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'])) {
|
|
return 'file-image';
|
|
} elseif (in_array($file_extension, ['mp4', 'avi', 'mov', 'wmv', 'flv'])) {
|
|
return 'file-video';
|
|
} elseif (in_array($file_extension, ['mp3', 'wav', 'ogg', 'flac'])) {
|
|
return 'file-audio';
|
|
} elseif (in_array($file_extension, ['html', 'htm', 'css', 'js', 'php', 'py', 'java'])) {
|
|
return 'file-code';
|
|
} else {
|
|
return 'file';
|
|
}
|
|
}
|