Merge branch 'master' into techbar

This commit is contained in:
ThaMunsta
2024-05-31 17:05:58 -04:00
68 changed files with 4427 additions and 579 deletions

View File

@@ -93,6 +93,12 @@ if (isset($_GET['archived'])) {
echo 'btn-default'; echo 'btn-default';
} ?>">Payment } ?>">Payment
Method</a> Method</a>
<a href="?category=Ticket"
class="btn <?php if ($category == 'Ticket') {
echo 'btn-primary';
} else {
echo 'btn-default';
} ?>">Ticket</a>
<a href="?archived=1" <a href="?archived=1"
class="btn <?php if (isset($_GET['archived'])) { class="btn <?php if (isset($_GET['archived'])) {
echo 'btn-primary'; echo 'btn-primary';
@@ -125,7 +131,7 @@ if (isset($_GET['archived'])) {
$category_id = intval($row['category_id']); $category_id = intval($row['category_id']);
$category_name = nullable_htmlentities($row['category_name']); $category_name = nullable_htmlentities($row['category_name']);
$category_color = nullable_htmlentities($row['category_color']); $category_color = nullable_htmlentities($row['category_color']);
?> ?>
<tr> <tr>
<td><a class="text-dark" href="#" data-toggle="modal" <td><a class="text-dark" href="#" data-toggle="modal"
@@ -170,7 +176,7 @@ if (isset($_GET['archived'])) {
</tr> </tr>
<?php <?php
include "admin_category_edit_modal.php"; include "admin_category_edit_modal.php";
} }

View File

@@ -39,7 +39,7 @@ function countFilesInDirectory($dir) {
// Function to compare two arrays recursively and return the differences // Function to compare two arrays recursively and return the differences
function arrayDiffRecursive($array1, $array2) { function arrayDiffRecursive($array1, $array2) {
$diff = array(); $diff = array();
foreach ($array1 as $key => $value) { foreach ($array1 as $key => $value) {
if (is_array($value)) { if (is_array($value)) {
if (!isset($array2[$key]) || !is_array($array2[$key])) { if (!isset($array2[$key]) || !is_array($array2[$key])) {
@@ -56,7 +56,7 @@ function arrayDiffRecursive($array1, $array2) {
} }
} }
} }
return $diff; return $diff;
} }
@@ -64,17 +64,17 @@ function arrayDiffRecursive($array1, $array2) {
function loadTableStructuresFromSQLDumpURL($fileURL) { function loadTableStructuresFromSQLDumpURL($fileURL) {
$context = stream_context_create(array('http' => array('header' => 'Accept: application/octet-stream'))); $context = stream_context_create(array('http' => array('header' => 'Accept: application/octet-stream')));
$fileContent = file_get_contents($fileURL, false, $context); $fileContent = file_get_contents($fileURL, false, $context);
if ($fileContent === false) { if ($fileContent === false) {
return null; return null;
} }
$structure = array(); $structure = array();
$queries = explode(";", $fileContent); $queries = explode(";", $fileContent);
foreach ($queries as $query) { foreach ($queries as $query) {
$query = trim($query); $query = trim($query);
if (!empty($query)) { if (!empty($query)) {
if (preg_match("/^CREATE TABLE `(.*)` \((.*)\)$/s", $query, $matches)) { if (preg_match("/^CREATE TABLE `(.*)` \((.*)\)$/s", $query, $matches)) {
$tableName = $matches[1]; $tableName = $matches[1];
@@ -83,7 +83,7 @@ function loadTableStructuresFromSQLDumpURL($fileURL) {
} }
} }
} }
return $structure; return $structure;
} }
@@ -91,31 +91,31 @@ function loadTableStructuresFromSQLDumpURL($fileURL) {
function fetchDatabaseStructureFromServer() { function fetchDatabaseStructureFromServer() {
global $mysqli; global $mysqli;
$tables = array(); $tables = array();
// Fetch table names // Fetch table names
$result = $mysqli->query("SHOW TABLES"); $result = $mysqli->query("SHOW TABLES");
if ($result->num_rows > 0) { if ($result->num_rows > 0) {
while ($row = $result->fetch_row()) { while ($row = $result->fetch_row()) {
$tableName = $row[0]; $tableName = $row[0];
$tables[$tableName] = array(); $tables[$tableName] = array();
} }
} }
// Fetch table structures // Fetch table structures
foreach ($tables as $tableName => &$table) { foreach ($tables as $tableName => &$table) {
$result = $mysqli->query("SHOW CREATE TABLE `$tableName`"); $result = $mysqli->query("SHOW CREATE TABLE `$tableName`");
if ($result->num_rows > 0) { if ($result->num_rows > 0) {
$row = $result->fetch_row(); $row = $result->fetch_row();
$table['structure'] = $row[1]; $table['structure'] = $row[1];
} }
} }
//$mysqli->close(); //$mysqli->close();
return $tables; return $tables;
} }
@@ -185,11 +185,12 @@ while ($row = $tablesResult->fetch_row()) {
//Get loaded PHP modules //Get loaded PHP modules
$loadedModules = get_loaded_extensions(); $loadedModules = get_loaded_extensions();
//Get Versions //Get Server Info / Service versions
$phpVersion = phpversion(); $phpVersion = phpversion();
$mysqlVersion = $mysqli->server_version; $mysqlVersion = $mysqli->server_version;
$operatingSystem = shell_exec('uname -a'); $operatingSystem = php_uname();
$webServer = $_SERVER['SERVER_SOFTWARE']; $webServer = $_SERVER['SERVER_SOFTWARE'];
$errorLog = ini_get('error_log');
?> ?>
@@ -198,20 +199,43 @@ $webServer = $_SERVER['SERVER_SOFTWARE'];
<h3 class="card-title"><i class="fas fa-fw fa-bug mr-2"></i>Debug</h3> <h3 class="card-title"><i class="fas fa-fw fa-bug mr-2"></i>Debug</h3>
</div> </div>
<div class="card-body"> <div class="card-body">
<h3>Database Structure Check</h3> <h3>Server Info</h3>
<?php
echo "PHP version: " . $phpVersion . "<br>";
echo "MySQL Version: " . $mysqlVersion . "<br>";
echo "Operating System: " . $operatingSystem . "<br>";
echo "Web Server: " . $webServer . "<br>";
echo "PHP Error Log: " . $errorLog
?>
<hr> <hr>
<h3>File System</h3>
<?php
$result = countFilesInDirectory($folderPath);
$totalFiles = $result['count'];
$totalSizeMB = round($result['size'] / (1024 * 1024), 2);
echo "Total number of files in $folderPath and its subdirectories: " . $totalFiles . "<br>";
echo "Total size of files in $folderPath and its subdirectories: " . $totalSizeMB . " MB";
?>
<hr>
<h3>Database Structure Check</h3>
<h4>Database stats</h4> <h4>Database stats</h4>
<?php <?php
echo "Number of tables: " . $numTables . "<br>"; echo "Number of tables: " . $numTables . "<br>";
echo "Total number of fields: " . $numFields . "<br>"; echo "Total number of fields: " . $numFields . "<br>";
echo "Total number of rows: " . $numRows . "<br>"; echo "Total number of rows: " . $numRows . "<br>";
echo "Current Database Version: " . CURRENT_DATABASE_VERSION . "<br>"; echo "Current Database Version: " . CURRENT_DATABASE_VERSION . "<br>";
?> ?>
<hr> <hr>
<h4>Table Stats</h4> <h4>Table Stats</h4>
@@ -255,34 +279,8 @@ $webServer = $_SERVER['SERVER_SOFTWARE'];
<hr> <hr>
<h3>Versions</h3>
<?php
echo "PHP version: " . $phpVersion . "<br>";
echo "MySQL Version: " . $mysqlVersion . "<br>";
echo "Operating System: " . $operatingSystem . "<br>";
echo "Web Server: " . $webServer;
?>
<hr>
<h3>File System</h3>
<?php
$result = countFilesInDirectory($folderPath);
$totalFiles = $result['count'];
$totalSizeMB = round($result['size'] / (1024 * 1024), 2);
echo "Total number of files in $folderPath and its subdirectories: " . $totalFiles . "<br>";
echo "Total size of files in $folderPath and its subdirectories: " . $totalSizeMB . " MB";
?>
<hr>
<h3>PHP Modules Installed</h3> <h3>PHP Modules Installed</h3>
<?php <?php
foreach ($loadedModules as $module) { foreach ($loadedModules as $module) {
echo $module . "<br>"; echo $module . "<br>";
@@ -311,7 +309,7 @@ $webServer = $_SERVER['SERVER_SOFTWARE'];
//Output the result //Output the result
echo $phpinfo; echo $phpinfo;
?> ?>
<hr> <hr>
</div> </div>
</div> </div>

View File

@@ -30,6 +30,7 @@
<select class="form-control select2" name="type" required> <select class="form-control select2" name="type" required>
<option value="">- Type -</option> <option value="">- Type -</option>
<option value="1">Client Tag</option> <option value="1">Client Tag</option>
<option value="2">Location Tag</option>
</select> </select>
</div> </div>
</div> </div>

View File

@@ -30,6 +30,7 @@
<select class="form-control select2" name="type" required> <select class="form-control select2" name="type" required>
<option value="">- Type -</option> <option value="">- Type -</option>
<option value="1" <?php if ($tag_type == 1) { echo "selected"; } ?>>Client Tag</option> <option value="1" <?php if ($tag_type == 1) { echo "selected"; } ?>>Client Tag</option>
<option value="2" <?php if ($tag_type == 2) { echo "selected"; } ?>>Location Tag</option>
</select> </select>
</div> </div>
</div> </div>

View File

@@ -62,6 +62,13 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$tag_id = intval($row['tag_id']); $tag_id = intval($row['tag_id']);
$tag_name = nullable_htmlentities($row['tag_name']); $tag_name = nullable_htmlentities($row['tag_name']);
$tag_type = intval($row['tag_type']); $tag_type = intval($row['tag_type']);
if ( $tag_type == 1) {
$tag_type_display = "Client Tag";
} elseif ( $tag_type == 2) {
$tag_type_display = "Location Tag";
} else {
$tag_type_display = "Unknown Tag";
}
$tag_color = nullable_htmlentities($row['tag_color']); $tag_color = nullable_htmlentities($row['tag_color']);
$tag_icon = nullable_htmlentities($row['tag_icon']); $tag_icon = nullable_htmlentities($row['tag_icon']);
@@ -72,7 +79,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<span class='badge text-light p-2 mr-1' style="background-color: <?php echo $tag_color; ?>"><i class="fa fa-fw fa-<?php echo $tag_icon; ?> mr-2"></i><?php echo $tag_name; ?></span> <span class='badge text-light p-2 mr-1' style="background-color: <?php echo $tag_color; ?>"><i class="fa fa-fw fa-<?php echo $tag_icon; ?> mr-2"></i><?php echo $tag_name; ?></span>
</a> </a>
</td> </td>
<td><?php echo $tag_type; ?></td> <td><?php echo $tag_type_display; ?></td>
<td> <td>
<div class="dropdown dropleft text-center"> <div class="dropdown dropleft text-center">
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown"> <button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">

View File

@@ -3,19 +3,12 @@ require_once "inc_all_admin.php";
require_once "database_version.php"; require_once "database_version.php";
require_once "config.php";
$updates = fetchUpdates();
// Fetch the latest code changes but don't apply them $latest_version = $updates->latest_version;
exec("git fetch", $output, $result); $current_version = $updates->current_version;
$latest_version = exec("git rev-parse origin/$repo_branch"); $result = $updates->result;
$current_version = exec("git rev-parse HEAD");
if ($current_version == $latest_version) {
$update_message = "No Updates available";
} else {
$update_message = "New Updates are Available [$latest_version]";
}
$git_log = shell_exec("git log $repo_branch..origin/$repo_branch --pretty=format:'<tr><td>%h</td><td>%ar</td><td>%s</td></tr>'"); $git_log = shell_exec("git log $repo_branch..origin/$repo_branch --pretty=format:'<tr><td>%h</td><td>%ar</td><td>%s</td></tr>'");

View File

@@ -55,13 +55,42 @@
</div> </div>
<select class="form-control select2" name="role" required> <select class="form-control select2" name="role" required>
<option value="">- Role -</option> <option value="">- Role -</option>
<option value="3">Administrator</option> <?php
<option value="2">Technician</option> $sql_user_roles = mysqli_query($mysqli, "SELECT * FROM user_roles WHERE user_role_archived_at IS NULL");
<option value="1">Accountant</option> while ($row = mysqli_fetch_array($sql_user_roles)) {
$user_role_id = intval($row['user_role_id']);
$user_role_name = nullable_htmlentities($row['user_role_name']);
?>
<option value="<?php echo $user_role_id; ?>"><?php echo $user_role_name; ?></option>
<?php } ?>
</select> </select>
</div> </div>
</div> </div>
<div class="form-group">
<label>Restrict Client Access</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-users"></i></span>
</div>
<select class="form-control select2" name="clients[]" data-placeholder="Restrict Client Access" multiple>
<?php
$sql_client_select = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql_client_select)) {
$client_id = intval($row['client_id']);
$client_name = nullable_htmlentities($row['client_name']);
?>
<option value="<?php echo $client_id; ?>"><?php echo $client_name; ?></option>
<?php } ?>
</select>
</div>
<small class="text-muted">Leave Blank for Full access to all clients, no affect on users with the admin role.</small>
</div>
<div class="form-group"> <div class="form-group">
<label>Avatar</label> <label>Avatar</label>
<input type="file" class="form-control-file" accept="image/*;capture=camera" name="file"> <input type="file" class="form-control-file" accept="image/*;capture=camera" name="file">

View File

@@ -67,23 +67,43 @@
<span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-user-shield"></i></span>
</div> </div>
<select class="form-control select2" name="role" required> <select class="form-control select2" name="role" required>
<option value="">- Role -</option> <?php
<option <?php if ($user_role == 3) { $sql_user_roles = mysqli_query($mysqli, "SELECT * FROM user_roles WHERE user_role_archived_at IS NULL");
echo "selected"; while ($row = mysqli_fetch_array($sql_user_roles)) {
} ?> value="3">Administrator $user_role_id = intval($row['user_role_id']);
</option> $user_role_name = nullable_htmlentities($row['user_role_name']);
<option <?php if ($user_role == 2) {
echo "selected"; ?>
} ?> value="2">Technician <option <?php if ($user_role == $user_role_id) {echo "selected";} ?> value="<?php echo $user_role_id; ?>"><?php echo $user_role_name; ?></option>
</option> <?php } ?>
<option <?php if ($user_role == 1) {
echo "selected";
} ?> value="1">Accountant
</option>
</select> </select>
</div> </div>
</div> </div>
<div class="form-group">
<label>Restrict Client Access</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-users"></i></span>
</div>
<select class="form-control select2" name="clients[]" data-placeholder="Restrict Client Access" multiple>
<?php
$sql_client_select = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql_client_select)) {
$client_id_select = intval($row['client_id']);
$client_name_select = nullable_htmlentities($row['client_name']);
?>
<option <?php if (in_array($client_id_select, $client_access_array)) { echo "selected"; } ?> value="<?php echo $client_id_select; ?>"><?php echo $client_name_select; ?></option>
<?php } ?>
</select>
</div>
<small class="text-muted">Leave Blank for Full access to all clients, no affect on users with the admin role.</small>
</div>
<div class="form-group"> <div class="form-group">
<label>Avatar</label> <label>Avatar</label>
<input type="file" class="form-control-file" accept="image/*;capture=camera" name="file"> <input type="file" class="form-control-file" accept="image/*;capture=camera" name="file">

View File

@@ -12,8 +12,9 @@ $url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM users, user_settings "SELECT SQL_CALC_FOUND_ROWS * FROM users, user_settings, user_roles
WHERE users.user_id = user_settings.user_id WHERE users.user_id = user_settings.user_id
AND user_settings.user_role = user_roles.user_role_id
AND (user_name LIKE '%$q%' OR user_email LIKE '%$q%') AND (user_name LIKE '%$q%' OR user_email LIKE '%$q%')
AND user_archived_at IS NULL AND user_archived_at IS NULL
ORDER BY $sort $order LIMIT $record_from, $record_to" ORDER BY $sort $order LIMIT $record_from, $record_to"
@@ -98,13 +99,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
} }
$user_config_force_mfa = intval($row['user_config_force_mfa']); $user_config_force_mfa = intval($row['user_config_force_mfa']);
$user_role = $row['user_role']; $user_role = $row['user_role'];
if ($user_role == 3) { $user_role_display = nullable_htmlentities($row['user_role_name']);
$user_role_display = "Administrator";
} elseif ($user_role == 2) {
$user_role_display = "Technician";
} else {
$user_role_display = "Accountant";
}
$user_initials = nullable_htmlentities(initials($user_name)); $user_initials = nullable_htmlentities(initials($user_name));
$sql_last_login = mysqli_query( $sql_last_login = mysqli_query(
@@ -125,9 +120,18 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$last_login = "$log_created_at<small class='text-secondary'><div class='mt-1'>$log_user_os</div><div class='mt-1'>$log_user_browser</div><div class='mt-1'><i class='fa fa-fw fa-globe'></i> $log_ip</div></small>"; $last_login = "$log_created_at<small class='text-secondary'><div class='mt-1'>$log_user_os</div><div class='mt-1'>$log_user_browser</div><div class='mt-1'><i class='fa fa-fw fa-globe'></i> $log_ip</div></small>";
} }
// Get User Client Access Permissions
$user_client_access_sql = mysqli_query($mysqli,"SELECT client_id FROM user_permissions WHERE user_id = $user_id");
$client_access_array = [];
while ($row = mysqli_fetch_assoc($user_client_access_sql)) {
$client_access_array[] = intval($row['client_id']);
}
$sql_remember_tokens = mysqli_query($mysqli, "SELECT * FROM remember_tokens WHERE remember_token_user_id = $user_id"); $sql_remember_tokens = mysqli_query($mysqli, "SELECT * FROM remember_tokens WHERE remember_token_user_id = $user_id");
$remember_token_count = mysqli_num_rows($sql_remember_tokens); $remember_token_count = mysqli_num_rows($sql_remember_tokens);
?> ?>
<tr> <tr>
<td class="text-center"> <td class="text-center">

View File

@@ -19,37 +19,22 @@ require_once "rfc6238.php";
* Fetches SSL certificates from remote hosts & returns the relevant info (issuer, expiry, public key) * Fetches SSL certificates from remote hosts & returns the relevant info (issuer, expiry, public key)
*/ */
if (isset($_GET['certificate_fetch_parse_json_details'])) { if (isset($_GET['certificate_fetch_parse_json_details'])) {
// PHP doesn't appreciate attempting SSL sockets to non-existent domains // PHP doesn't appreciate attempting SSL sockets to non-existent domains
if (empty($_GET['domain'])) { if (empty($_GET['domain'])) {
exit(); exit();
} }
$domain = $_GET['domain'];
// FQDNs in database shouldn't have a URL scheme, adding one $name = $_GET['domain'];
$domain = "https://".$domain;
// Parse host and port // Get SSL cert for domain (if exists)
$url = parse_url($domain, PHP_URL_HOST); $certificate = getSSL($name);
$port = parse_url($domain, PHP_URL_PORT);
// Default port
if (!$port) {
$port = "443";
}
// Get certificate (using verify peer false to allow for self-signed certs) if ($certificate['success'] == "TRUE") {
$socket = "ssl://$url:$port";
$get = stream_context_create(array("ssl" => array("capture_peer_cert" => true, "verify_peer" => false,)));
$read = stream_socket_client($socket, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $get);
$cert = stream_context_get_params($read);
$cert_public_key_obj = openssl_x509_parse($cert['options']['ssl']['peer_certificate']);
openssl_x509_export($cert['options']['ssl']['peer_certificate'], $export);
// Process data
if ($cert_public_key_obj) {
$response['success'] = "TRUE"; $response['success'] = "TRUE";
$response['expire'] = date('Y-m-d', $cert_public_key_obj['validTo_time_t']); $response['expire'] = $certificate['expire'];
$response['issued_by'] = strip_tags($cert_public_key_obj['issuer']['O']); $response['issued_by'] = $certificate['issued_by'];
$response['public_key'] = $export; //nl2br $response['public_key'] = $certificate['public_key'];
} else { } else {
$response['success'] = "FALSE"; $response['success'] = "FALSE";
} }

View File

@@ -74,6 +74,14 @@ if (isset($_POST['contact_auth_method'])) {
$auth_method = ''; $auth_method = '';
} }
if (isset($_POST['contact_primary'])) {
$primary = intval($_POST['contact_primary']);
} elseif ($contact_row) {
$primary = $contact_row['contact_primary'];
} else {
$primary = '0';
}
if (isset($_POST['contact_important'])) { if (isset($_POST['contact_important'])) {
$important = intval($_POST['contact_important']); $important = intval($_POST['contact_important']);
} elseif ($contact_row) { } elseif ($contact_row) {

View File

@@ -20,7 +20,7 @@ if (!empty($name) && !empty($email) && !empty($client_id)) {
if (mysqli_num_rows($email_duplication_sql) == 0) { if (mysqli_num_rows($email_duplication_sql) == 0) {
// Insert contact // Insert contact
$insert_sql = mysqli_query($mysqli, "INSERT INTO contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_auth_method = '$auth_method', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id"); $insert_sql = mysqli_query($mysqli, "INSERT INTO contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_auth_method = '$auth_method', contact_primary = '$primary', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id");
// Check insert & get insert ID // Check insert & get insert ID
if ($insert_sql) { if ($insert_sql) {

View File

@@ -19,7 +19,7 @@ if (!empty($contact_id)) {
require_once 'contact_model.php'; require_once 'contact_model.php';
$update_sql = mysqli_query($mysqli, "UPDATE contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_auth_method = '$auth_method', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id WHERE contact_id = $contact_id LIMIT 1"); $update_sql = mysqli_query($mysqli, "UPDATE contacts SET contact_name = '$name', contact_title = '$title', contact_department = '$department', contact_email = '$email', contact_phone = '$phone', contact_extension = '$extension', contact_mobile = '$mobile', contact_notes = '$notes', contact_auth_method = '$auth_method', contact_primary = '$primary', contact_important = '$important', contact_billing = '$billing', contact_technical = '$technical', contact_location_id = $location_id, contact_client_id = $client_id WHERE contact_id = $contact_id LIMIT 1");
// Check insert & get insert ID // Check insert & get insert ID
if ($update_sql) { if ($update_sql) {

View File

@@ -180,6 +180,29 @@ while ($row = mysqli_fetch_array($sql)) {
echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'ticket.php?ticket_id=$event_id' },"; echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'ticket.php?ticket_id=$event_id' },";
} }
// Recurring Tickets
$sql = mysqli_query($mysqli, "SELECT * FROM clients
LEFT JOIN scheduled_tickets ON client_id = scheduled_ticket_client_id
LEFT JOIN users ON scheduled_ticket_assigned_to = user_id"
);
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['scheduled_ticket_id']);
$client_id = intval($row['client_id']);
$username = $row['user_name'];
$frequency = $row['scheduled_ticket_frequency'];
if (empty($username)) {
$username = "";
} else {
//Limit to characters and add ...
$username = "[". substr($row['user_name'], 0, 9) . "...]";
}
$event_title = json_encode("R Ticket ($frequency) - " . $row['scheduled_ticket_subject'] . " " . $username);
$event_start = json_encode($row['scheduled_ticket_next_run']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'client_recurring_tickets.php?client_id=$client_id' },";
}
//Tickets Scheduled //Tickets Scheduled
$sql = mysqli_query($mysqli, "SELECT * FROM clients $sql = mysqli_query($mysqli, "SELECT * FROM clients
LEFT JOIN tickets ON client_id = ticket_client_id LEFT JOIN tickets ON client_id = ticket_client_id
@@ -238,6 +261,14 @@ while ($row = mysqli_fetch_array($sql)) {
?> ?>
], ],
eventOrder: 'allDay,start,-duration,title', eventOrder: 'allDay,start,-duration,title',
<?php
// User preference for Calendar start day (Sunday/Monday)
// Fetch User Dashboard Settings
$row = mysqli_fetch_array(mysqli_query($mysqli, "SELECT user_config_calendar_first_day FROM user_settings WHERE user_id = $session_user_id"));
$user_config_calendar_first_day = intval($row['user_config_calendar_first_day']);
?>
firstDay: <?php echo $user_config_calendar_first_day ?>,
}); });
calendar.render(); calendar.render();

View File

@@ -10,7 +10,8 @@ if (!isset($_SESSION)) {
session_start(); session_start();
} }
//Check to see if setup is enabled
// Check to see if setup is enabled
if (!isset($config_enable_setup) || $config_enable_setup == 1) { if (!isset($config_enable_setup) || $config_enable_setup == 1) {
header("Location: setup.php"); header("Location: setup.php");
exit; exit;
@@ -18,13 +19,19 @@ if (!isset($config_enable_setup) || $config_enable_setup == 1) {
// Check user is logged in with a valid session // Check user is logged in with a valid session
if (!isset($_SESSION['logged']) || !$_SESSION['logged']) { if (!isset($_SESSION['logged']) || !$_SESSION['logged']) {
header("Location: login.php"); if ($_SERVER["REQUEST_URI"] == "/") {
header("Location: login.php");
} else {
header("Location: login.php?last_visited=" . base64_encode($_SERVER["REQUEST_URI"]) );
}
exit; exit;
} }
// Set Timezone // Set Timezone
require_once "inc_set_timezone.php"; require_once "inc_set_timezone.php";
// User IP & UA // User IP & UA
$session_ip = sanitizeInput(getIP()); $session_ip = sanitizeInput(getIP());
$session_user_agent = sanitizeInput($_SERVER['HTTP_USER_AGENT']); $session_user_agent = sanitizeInput($_SERVER['HTTP_USER_AGENT']);
@@ -56,9 +63,37 @@ $session_company_country = $row['company_country'];
$session_company_locale = $row['company_locale']; $session_company_locale = $row['company_locale'];
$session_company_currency = $row['company_currency']; $session_company_currency = $row['company_currency'];
//Set Currency Format
// Set Currency Format
$currency_format = numfmt_create($session_company_locale, NumberFormatter::CURRENCY); $currency_format = numfmt_create($session_company_locale, NumberFormatter::CURRENCY);
try {
// Get User Client Access Permissions
$user_client_access_sql = "SELECT client_id FROM user_permissions WHERE user_id = $session_user_id";
$user_client_access_result = mysqli_query($mysqli, $user_client_access_sql);
$client_access_array = [];
while ($row = mysqli_fetch_assoc($user_client_access_result)) {
$client_access_array[] = $row['client_id'];
}
$client_access_string = implode(',', $client_access_array);
// Role / Client Access Permission Check
if ($session_user_role < 3 && !empty($client_access_string)) {
$access_permission_query = "AND client_id IN ($client_access_string)";
} else {
$access_permission_query = "";
}
} catch (Exception $e) {
// Handle exception
error_log('MySQL error: ' . $e->getMessage());
$access_permission_query = ""; // Ensure safe default if query fails
}
// Include the settings vars
require_once "get_settings.php"; require_once "get_settings.php";
@@ -73,15 +108,17 @@ if ($iPod || $iPhone || $iPad) {
$session_map_source = "google"; $session_map_source = "google";
} }
//Check if mobile device
// Check if mobile device
$session_mobile = isMobile(); $session_mobile = isMobile();
//Get Notification Count for the badge on the top nav
// Get Notification Count for the badge on the top nav
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('notification_id') AS num FROM notifications WHERE (notification_user_id = $session_user_id OR notification_user_id = 0) AND notification_dismissed_at IS NULL")); $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('notification_id') AS num FROM notifications WHERE (notification_user_id = $session_user_id OR notification_user_id = 0) AND notification_dismissed_at IS NULL"));
$num_notifications = $row['num']; $num_notifications = $row['num'];
// FORCE MFA Setup // FORCE MFA Setup
//if ($session_user_config_force_mfa == 1 && $session_token == NULL) { //if ($session_user_config_force_mfa == 1 && $session_token == NULL) {
// header("Location: force_mfa.php"); // header("Location: force_mfa.php");
//} //}

View File

@@ -33,17 +33,31 @@ if (!empty($_GET['folder_id'])) {
// Set Folder Location Var used when creating folders // Set Folder Location Var used when creating folders
$folder_location = 0; $folder_location = 0;
$sql = mysqli_query( if ($get_folder_id == 0 && $_GET["q"]) {
$mysqli, $sql = mysqli_query(
"SELECT SQL_CALC_FOUND_ROWS * FROM documents $mysqli,
LEFT JOIN users ON document_created_by = user_id "SELECT SQL_CALC_FOUND_ROWS * FROM documents
WHERE document_client_id = $client_id LEFT JOIN users ON document_created_by = user_id
AND document_template = 0 WHERE document_client_id = $client_id
AND document_folder_id = $folder AND document_template = 0
AND document_archived_at IS NULL
$query_snippet AND document_archived_at IS NULL
ORDER BY $sort $order LIMIT $record_from, $record_to" $query_snippet
); ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}else{
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM documents
LEFT JOIN users ON document_created_by = user_id
WHERE document_client_id = $client_id
AND document_template = 0
AND document_folder_id = $folder
AND document_archived_at IS NULL
$query_snippet
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));

View File

@@ -180,6 +180,29 @@ while ($row = mysqli_fetch_array($sql)) {
echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'ticket.php?ticket_id=$event_id' },"; echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'ticket.php?ticket_id=$event_id' },";
} }
// Recurring Tickets
$sql = mysqli_query($mysqli, "SELECT * FROM clients
LEFT JOIN scheduled_tickets ON client_id = scheduled_ticket_client_id
LEFT JOIN users ON scheduled_ticket_assigned_to = user_id"
);
while ($row = mysqli_fetch_array($sql)) {
$event_id = intval($row['scheduled_ticket_id']);
$client_id = intval($row['client_id']);
$username = $row['user_name'];
$frequency = $row['scheduled_ticket_frequency'];
if (empty($username)) {
$username = "";
} else {
//Limit to characters and add ...
$username = "[". substr($row['user_name'], 0, 9) . "...]";
}
$event_title = json_encode("R Ticket ($frequency) - " . $row['scheduled_ticket_subject'] . " " . $username);
$event_start = json_encode($row['scheduled_ticket_next_run']);
echo "{ id: $event_id, title: $event_title, start: $event_start, color: '$event_color', url: 'client_recurring_tickets.php?client_id=$client_id' },";
}
//Tickets Scheduled //Tickets Scheduled
$sql = mysqli_query($mysqli, "SELECT * FROM clients $sql = mysqli_query($mysqli, "SELECT * FROM clients
LEFT JOIN tickets ON client_id = ticket_client_id LEFT JOIN tickets ON client_id = ticket_client_id

View File

@@ -11,7 +11,7 @@
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>"> <input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<div class="modal-body bg-white"> <div class="modal-body bg-white">
<div class="form-group"> <div class="form-group">
<label>Description</label> <label>Description</label>
<div class="input-group"> <div class="input-group">
@@ -47,7 +47,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<input type="file" class="form-control-file" name="file[]" multiple id="fileInput" accept=".jpg, .jpeg, .gif, .png, .webp, .pdf, .txt, .md, .doc, .docx, .odt, .csv, .xls, .xlsx, .ods, .pptx, .odp, .zip, .tar, .gz, .xml, .msg, .json, .wav, .mp3, .ogg, .mov, .mp4, .av1, .ovpn, .cfg, .ps1, .vsdx, .drawio, .pfx"> <input type="file" class="form-control-file" name="file[]" multiple id="fileInput" accept=".jpg, .jpeg, .gif, .png, .webp, .pdf, .txt, .md, .doc, .docx, .odt, .csv, .xls, .xlsx, .ods, .pptx, .odp, .zip, .tar, .gz, .xml, .msg, .json, .wav, .mp3, .ogg, .mov, .mp4, .av1, .ovpn, .cfg, .ps1, .vsdx, .drawio, .pfx, .unf">
</div> </div>
<small class="text-secondary">Up to 20 files can be uploaded at once by holding down CTRL and selecting files</small> <small class="text-secondary">Up to 20 files can be uploaded at once by holding down CTRL and selecting files</small>

View File

@@ -39,16 +39,29 @@ if ($view == 1) {
// Set Folder Location Var used when creating folders // Set Folder Location Var used when creating folders
$folder_location = 1; $folder_location = 1;
$sql = mysqli_query( if ($get_folder_id == 0 && $_GET["q"]) {
$mysqli, $sql = mysqli_query(
"SELECT SQL_CALC_FOUND_ROWS * FROM files $mysqli,
WHERE file_client_id = $client_id "SELECT SQL_CALC_FOUND_ROWS * FROM files
AND file_folder_id = $folder_id WHERE file_client_id = $client_id
AND file_archived_at IS NULL
AND (file_name LIKE '%$q%' OR file_ext LIKE '%$q%' OR file_description LIKE '%$q%') AND file_archived_at IS NULL
$query_images AND (file_name LIKE '%$q%' OR file_ext LIKE '%$q%' OR file_description LIKE '%$q%')
ORDER BY $sort $order LIMIT $record_from, $record_to" $query_images
); ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}else{
$sql = mysqli_query(
$mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM files
WHERE file_client_id = $client_id
AND file_folder_id = $folder_id
AND file_archived_at IS NULL
AND (file_name LIKE '%$q%' OR file_ext LIKE '%$q%' OR file_description LIKE '%$q%')
$query_images
ORDER BY $sort $order LIMIT $record_from, $record_to"
);
}
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));

View File

@@ -168,10 +168,6 @@
</div> </div>
</div> </div>
<div class="form-group">
<textarea class="form-control" rows="6" name="notes" placeholder="Notes, eg Parking Info, Building Access etc"></textarea>
</div>
</div> </div>
<div class="tab-pane fade" id="pills-notes"> <div class="tab-pane fade" id="pills-notes">
@@ -180,6 +176,27 @@
<textarea class="form-control" rows="12" name="notes" placeholder="Notes, eg Parking Info, Building Access etc"></textarea> <textarea class="form-control" rows="12" name="notes" placeholder="Notes, eg Parking Info, Building Access etc"></textarea>
</div> </div>
<div class="form-group">
<label>Tags</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tags"></i></span>
</div>
<select class="form-control select2" name="tags[]" data-placeholder="Add some tags" multiple>
<?php
$sql_tags_select = mysqli_query($mysqli, "SELECT * FROM tags WHERE tag_type = 2 ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_tags_select)) {
$tag_id_select = intval($row['tag_id']);
$tag_name_select = nullable_htmlentities($row['tag_name']);
?>
<option value="<?php echo $tag_id_select; ?>"><?php echo $tag_name_select; ?></option>
<?php } ?>
</select>
</div>
</div>
</div> </div>
</div> </div>

View File

@@ -194,6 +194,27 @@
<textarea class="form-control" rows="12" name="notes" placeholder="Notes, eg Parking Info, Building Access etc"><?php echo $location_notes; ?></textarea> <textarea class="form-control" rows="12" name="notes" placeholder="Notes, eg Parking Info, Building Access etc"><?php echo $location_notes; ?></textarea>
</div> </div>
<div class="form-group">
<label>Tags</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tags"></i></span>
</div>
<select class="form-control select2" name="tags[]" data-placeholder="Add some tags" multiple>
<?php
$sql_tags_select = mysqli_query($mysqli, "SELECT * FROM tags WHERE tag_type = 2 ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_tags_select)) {
$tag_id_select = intval($row['tag_id']);
$tag_name_select = nullable_htmlentities($row['tag_name']);
?>
<option value="<?php echo $tag_id_select; ?>" <?php if (in_array($tag_id_select, $location_tag_id_array)) { echo "selected"; } ?>><?php echo $tag_name_select; ?></option>
<?php } ?>
</select>
</div>
</div>
</div> </div>
</div> </div>

View File

@@ -12,10 +12,13 @@ $url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
"SELECT SQL_CALC_FOUND_ROWS * FROM locations "SELECT SQL_CALC_FOUND_ROWS locations.*, GROUP_CONCAT(tag_name) FROM locations
LEFT JOIN location_tags ON location_tags.location_id = locations.location_id
LEFT JOIN tags ON tags.tag_id = location_tags.tag_id
WHERE location_client_id = $client_id WHERE location_client_id = $client_id
AND location_$archive_query AND location_$archive_query
AND (location_name LIKE '%$q%' OR location_description LIKE '%$q%' OR location_address LIKE '%$q%' OR location_phone LIKE '%$phone_query%') AND (location_name LIKE '%$q%' OR location_description LIKE '%$q%' OR location_address LIKE '%$q%' OR location_phone LIKE '%$phone_query%' OR tag_name LIKE '%$q%')
GROUP BY location_id
ORDER BY location_primary DESC, $sort $order LIMIT $record_from, $record_to" ORDER BY location_primary DESC, $sort $order LIMIT $record_from, $record_to"
); );
@@ -118,6 +121,29 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$location_primary_display = ""; $location_primary_display = "";
} }
// Tags
$location_tag_name_display_array = array();
$location_tag_id_array = array();
$sql_location_tags = mysqli_query($mysqli, "SELECT * FROM location_tags LEFT JOIN tags ON location_tags.tag_id = tags.tag_id WHERE location_tags.location_id = $location_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_location_tags)) {
$location_tag_id = intval($row['tag_id']);
$location_tag_name = nullable_htmlentities($row['tag_name']);
$location_tag_color = nullable_htmlentities($row['tag_color']);
if (empty($location_tag_color)) {
$location_tag_color = "dark";
}
$location_tag_icon = nullable_htmlentities($row['tag_icon']);
if (empty($location_tag_icon)) {
$location_tag_icon = "tag";
}
$location_tag_id_array[] = $location_tag_id;
$location_tag_name_display_array[] = "<a href='client_locations.php?client_id=$client_id&q=$location_tag_name'><span class='badge text-light p-1 mr-1' style='background-color: $location_tag_color;'><i class='fa fa-fw fa-$location_tag_icon mr-2'></i>$location_tag_name</span></a>";
}
$location_tags_display = implode('', $location_tag_name_display_array);
?> ?>
<tr> <tr>
<td> <td>
@@ -128,6 +154,12 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
<div <?php if($location_primary) { echo "class='text-bold'"; } ?>><?php echo $location_name; ?></div> <div <?php if($location_primary) { echo "class='text-bold'"; } ?>><?php echo $location_name; ?></div>
<div><small class="text-secondary"><?php echo $location_description; ?></small></div> <div><small class="text-secondary"><?php echo $location_description; ?></small></div>
<div><?php echo $location_primary_display; ?></div> <div><?php echo $location_primary_display; ?></div>
<?php
if (!empty($location_tags_display)) { ?>
<div class="mt-1">
<?php echo $location_tags_display; ?>
</div>
<?php } ?>
</div> </div>
</div> </div>
</a> </a>

View File

@@ -89,8 +89,8 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$login_uri = nullable_htmlentities($row['login_uri']); $login_uri = nullable_htmlentities($row['login_uri']);
if (empty($login_uri)) { if (empty($login_uri)) {
$login_uri_display = "-"; $login_uri_display = "-";
} else { } else {
$login_uri_display = "$login_uri<button class='btn btn-sm clipboardjs' type='button' data-clipboard-text='$login_uri'><i class='far fa-copy text-secondary'></i></button>"; $login_uri_display = truncate($login_uri,40) . "<button class='btn btn-sm clipboardjs' type='button' data-clipboard-text='$login_uri'><i class='far fa-copy text-secondary'></i></button>";
} }
$login_uri_2 = nullable_htmlentities($row['login_uri_2']); $login_uri_2 = nullable_htmlentities($row['login_uri_2']);
$login_username = nullable_htmlentities(decryptLoginEntry($row['login_username'])); $login_username = nullable_htmlentities(decryptLoginEntry($row['login_username']));

View File

@@ -44,23 +44,24 @@ $url_query_strings_sort = http_build_query($get_copy);
$sql = mysqli_query( $sql = mysqli_query(
$mysqli, $mysqli,
" "
SELECT SQL_CALC_FOUND_ROWS clients.*, contacts.*, locations.*, GROUP_CONCAT(tags.tag_name) AS tag_names SELECT SQL_CALC_FOUND_ROWS clients.*, contacts.*, locations.*, GROUP_CONCAT(tag_name)
FROM clients FROM clients
LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1 LEFT JOIN contacts ON clients.client_id = contacts.contact_client_id AND contact_primary = 1
LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1
LEFT JOIN client_tags ON client_tags.client_tag_client_id = clients.client_id LEFT JOIN client_tags ON client_tags.client_id = clients.client_id
LEFT JOIN tags ON tags.tag_id = client_tags.client_tag_tag_id LEFT JOIN tags ON tags.tag_id = client_tags.tag_id
WHERE (clients.client_name LIKE '%$q%' OR clients.client_type LIKE '%$q%' OR clients.client_referral LIKE '%$q%' WHERE (client_name LIKE '%$q%' OR client_type LIKE '%$q%' OR client_referral LIKE '%$q%'
OR contacts.contact_email LIKE '%$q%' OR contacts.contact_name LIKE '%$q%' OR contacts.contact_phone LIKE '%$phone_query%' OR contact_email LIKE '%$q%' OR contact_name LIKE '%$q%' OR contact_phone LIKE '%$phone_query%'
OR contacts.contact_mobile LIKE '%$phone_query%' OR locations.location_address LIKE '%$q%' OR contact_mobile LIKE '%$phone_query%' OR location_address LIKE '%$q%'
OR locations.location_city LIKE '%$q%' OR locations.location_state LIKE '%$q%' OR locations.location_zip LIKE '%$q%' OR location_city LIKE '%$q%' OR location_state LIKE '%$q%' OR location_zip LIKE '%$q%'
OR tags.tag_name LIKE '%$q%' OR clients.client_tax_id_number LIKE '%$q%') OR tag_name LIKE '%$q%' OR client_tax_id_number LIKE '%$q%')
AND clients.client_$archive_query AND client_$archive_query
AND DATE(clients.client_created_at) BETWEEN '$dtf' AND '$dtt' AND DATE(client_created_at) BETWEEN '$dtf' AND '$dtt'
AND clients.client_lead = $leads AND client_lead = $leads
$access_permission_query
$industry_query $industry_query
$referral_query $referral_query
GROUP BY clients.client_id GROUP BY client_id
ORDER BY $sort $order ORDER BY $sort $order
LIMIT $record_from, $record_to LIMIT $record_from, $record_to
"); ");
@@ -245,7 +246,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
$client_tag_name_display_array = array(); $client_tag_name_display_array = array();
$client_tag_id_array = array(); $client_tag_id_array = array();
$sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.client_tag_tag_id = tags.tag_id WHERE client_tags.client_tag_client_id = $client_id ORDER BY tag_name ASC"); $sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.tag_id = tags.tag_id WHERE client_id = $client_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_client_tags)) { while ($row = mysqli_fetch_array($sql_client_tags)) {
$client_tag_id = intval($row['tag_id']); $client_tag_id = intval($row['tag_id']);

View File

@@ -252,6 +252,7 @@ if (mysqli_num_rows($sql_scheduled_tickets) > 0) {
$details = mysqli_real_escape_string($mysqli, $row['scheduled_ticket_details']); $details = mysqli_real_escape_string($mysqli, $row['scheduled_ticket_details']);
$priority = sanitizeInput($row['scheduled_ticket_priority']); $priority = sanitizeInput($row['scheduled_ticket_priority']);
$frequency = sanitizeInput(strtolower($row['scheduled_ticket_frequency'])); $frequency = sanitizeInput(strtolower($row['scheduled_ticket_frequency']));
$billable = intval($row['scheduled_ticket_billable']);
$created_id = intval($row['scheduled_ticket_created_by']); $created_id = intval($row['scheduled_ticket_created_by']);
$assigned_id = intval($row['scheduled_ticket_assigned_to']); $assigned_id = intval($row['scheduled_ticket_assigned_to']);
$client_id = intval($row['scheduled_ticket_client_id']); $client_id = intval($row['scheduled_ticket_client_id']);
@@ -272,7 +273,7 @@ if (mysqli_num_rows($sql_scheduled_tickets) > 0) {
mysqli_query($mysqli, "UPDATE settings SET config_ticket_next_number = $new_config_ticket_next_number WHERE company_id = 1"); mysqli_query($mysqli, "UPDATE settings SET config_ticket_next_number = $new_config_ticket_next_number WHERE company_id = 1");
// Raise the ticket // Raise the ticket
mysqli_query($mysqli, "INSERT INTO tickets SET ticket_prefix = '$config_ticket_prefix', ticket_number = $ticket_number, ticket_subject = '$subject', ticket_details = '$details', ticket_priority = '$priority', ticket_status = '$ticket_status', ticket_created_by = $created_id, ticket_assigned_to = $assigned_id, ticket_contact_id = $contact_id, ticket_client_id = $client_id, ticket_asset_id = $asset_id"); mysqli_query($mysqli, "INSERT INTO tickets SET ticket_prefix = '$config_ticket_prefix', ticket_number = $ticket_number, ticket_subject = '$subject', ticket_details = '$details', ticket_priority = '$priority', ticket_status = '$ticket_status', ticket_billable = $billable, ticket_created_by = $created_id, ticket_assigned_to = $assigned_id, ticket_contact_id = $contact_id, ticket_client_id = $client_id, ticket_asset_id = $asset_id");
$id = mysqli_insert_id($mysqli); $id = mysqli_insert_id($mysqli);
// Logging // Logging
@@ -733,7 +734,7 @@ while ($row = mysqli_fetch_array($sql_recurring_expenses)) {
// TELEMETRY // TELEMETRY
if ($config_telemetry > 0 OR $config_telemetry = 2) { if ($config_telemetry > 0 OR $config_telemetry == 2) {
$current_version = exec("git rev-parse HEAD"); $current_version = exec("git rev-parse HEAD");
@@ -979,6 +980,19 @@ if ($config_telemetry > 0 OR $config_telemetry = 2) {
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Cron', log_action = 'Telemetry', log_description = 'Cron sent telemetry results to ITFlow Developers'"); mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Cron', log_action = 'Telemetry', log_description = 'Cron sent telemetry results to ITFlow Developers'");
} }
// Fetch Updates
$updates = fetchUpdates();
$update_message = $updates->update_message;
if ($updates->current_version !== $updates->latest_version) {
// Send Alert to inform Updates Available
mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Update', notification = '$update_message', notification_action = 'admin_update.php'");
}
/* /*
* ############################################################################################################### * ###############################################################################################################
* FINISH UP * FINISH UP

View File

@@ -1,13 +0,0 @@
/* Custom CSS Styling for time tracking */
/* Small bit of space between the ticket status and time tracking inputs */
.custom-tt-horizontal-spacing {
width: 20px; /* Adjust the width as needed for smaller spacing */
display: inline-block;
}
/* Adjust Hour, min, and second fields to be close together */
.custom-tt-width {
width: 50px; /* Adjust the width as needed */
padding: 0; /* Remove padding to maintain the desired width */
}

View File

@@ -335,7 +335,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
if (CURRENT_DATABASE_VERSION == '0.2.0') { if (CURRENT_DATABASE_VERSION == '0.2.0') {
//Insert queries here required to update to DB version 0.2.1 //Insert queries here required to update to DB version 0.2.1
mysqli_query($mysqli, "ALTER TABLE `vendors` mysqli_query($mysqli, "ALTER TABLE `vendors`
ADD `vendor_hours` VARCHAR(200) NULL DEFAULT NULL AFTER `vendor_website`, ADD `vendor_hours` VARCHAR(200) NULL DEFAULT NULL AFTER `vendor_website`,
ADD `vendor_sla` VARCHAR(200) NULL DEFAULT NULL AFTER `vendor_hours`, ADD `vendor_sla` VARCHAR(200) NULL DEFAULT NULL AFTER `vendor_hours`,
ADD `vendor_code` VARCHAR(200) NULL DEFAULT NULL AFTER `vendor_sla`, ADD `vendor_code` VARCHAR(200) NULL DEFAULT NULL AFTER `vendor_sla`,
@@ -343,11 +343,11 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
"); ");
mysqli_query($mysqli, "ALTER TABLE `vendors` mysqli_query($mysqli, "ALTER TABLE `vendors`
DROP `vendor_country`, DROP `vendor_country`,
DROP `vendor_address`, DROP `vendor_address`,
DROP `vendor_city`, DROP `vendor_city`,
DROP `vendor_state`, DROP `vendor_state`,
DROP `vendor_zip`, DROP `vendor_zip`,
DROP `vendor_global` DROP `vendor_global`
"); ");
@@ -355,7 +355,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
mysqli_query($mysqli, "CREATE TABLE `vendor_templates` (`vendor_template_id` int(11) AUTO_INCREMENT PRIMARY KEY, mysqli_query($mysqli, "CREATE TABLE `vendor_templates` (`vendor_template_id` int(11) AUTO_INCREMENT PRIMARY KEY,
`vendor_template_name` varchar(200) NOT NULL, `vendor_template_name` varchar(200) NOT NULL,
`vendor_template_description` varchar(200) NULL DEFAULT NULL, `vendor_template_description` varchar(200) NULL DEFAULT NULL,
`vendor_template_phone` varchar(200) NULL DEFAULT NULL, `vendor_template_phone` varchar(200) NULL DEFAULT NULL,
`vendor_template_email` varchar(200) NULL DEFAULT NULL, `vendor_template_email` varchar(200) NULL DEFAULT NULL,
`vendor_template_website` varchar(200) NULL DEFAULT NULL, `vendor_template_website` varchar(200) NULL DEFAULT NULL,
`vendor_template_hours` varchar(200) NULL DEFAULT NULL, `vendor_template_hours` varchar(200) NULL DEFAULT NULL,
@@ -397,7 +397,7 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
mysqli_query($mysqli, "CREATE TABLE `interfaces` (`interface_id` int(11) AUTO_INCREMENT PRIMARY KEY, mysqli_query($mysqli, "CREATE TABLE `interfaces` (`interface_id` int(11) AUTO_INCREMENT PRIMARY KEY,
`interface_number` int(11) NULL DEFAULT NULL, `interface_number` int(11) NULL DEFAULT NULL,
`interface_description` varchar(200) NULL DEFAULT NULL, `interface_description` varchar(200) NULL DEFAULT NULL,
`interface_connected_asset` varchar(200) NULL DEFAULT NULL, `interface_connected_asset` varchar(200) NULL DEFAULT NULL,
`interface_ip` varchar(200) NULL DEFAULT NULL, `interface_ip` varchar(200) NULL DEFAULT NULL,
`interface_created_at` datetime DEFAULT CURRENT_TIMESTAMP, `interface_created_at` datetime DEFAULT CURRENT_TIMESTAMP,
`interface_updated_at` datetime NULL ON UPDATE CURRENT_TIMESTAMP, `interface_updated_at` datetime NULL ON UPDATE CURRENT_TIMESTAMP,
@@ -1802,24 +1802,24 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
mysqli_query($mysqli, "UPDATE ticket_statuses SET ticket_status_color = '#28a745' WHERE ticket_status_id = 3"); // On Hold mysqli_query($mysqli, "UPDATE ticket_statuses SET ticket_status_color = '#28a745' WHERE ticket_status_id = 3"); // On Hold
mysqli_query($mysqli, "UPDATE ticket_statuses SET ticket_status_color = '#343a40' WHERE ticket_status_id = 4"); // Auto Close mysqli_query($mysqli, "UPDATE ticket_statuses SET ticket_status_color = '#343a40' WHERE ticket_status_id = 4"); // Auto Close
mysqli_query($mysqli, "UPDATE ticket_statuses SET ticket_status_color = '#343a40' WHERE ticket_status_id = 5"); // Closed mysqli_query($mysqli, "UPDATE ticket_statuses SET ticket_status_color = '#343a40' WHERE ticket_status_id = 5"); // Closed
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.1.9'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.1.9'");
} }
if (CURRENT_DATABASE_VERSION == '1.1.9') { if (CURRENT_DATABASE_VERSION == '1.1.9') {
mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_login_remember_me_expire` INT(11) NOT NULL DEFAULT 3 AFTER `config_login_key_secret`"); mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_login_remember_me_expire` INT(11) NOT NULL DEFAULT 3 AFTER `config_login_key_secret`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.0'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.0'");
} }
if (CURRENT_DATABASE_VERSION == '1.2.0') { if (CURRENT_DATABASE_VERSION == '1.2.0') {
mysqli_query($mysqli, "ALTER TABLE `ticket_templates` ADD `ticket_template_order` INT(11) NOT NULL DEFAULT 0 AFTER `ticket_template_details`"); mysqli_query($mysqli, "ALTER TABLE `ticket_templates` ADD `ticket_template_order` INT(11) NOT NULL DEFAULT 0 AFTER `ticket_template_details`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.1'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.1'");
} }
if (CURRENT_DATABASE_VERSION == '1.2.1') { if (CURRENT_DATABASE_VERSION == '1.2.1') {
// Ticket Templates can have many project templates and Project Template can have have many ticket template, so instead create a many to many table relationship // Ticket Templates can have many project templates and Project Template can have have many ticket template, so instead create a many to many table relationship
mysqli_query($mysqli, "ALTER TABLE `ticket_templates` DROP `ticket_template_order`"); mysqli_query($mysqli, "ALTER TABLE `ticket_templates` DROP `ticket_template_order`");
mysqli_query($mysqli, "ALTER TABLE `ticket_templates` DROP `ticket_template_project_template_id`"); mysqli_query($mysqli, "ALTER TABLE `ticket_templates` DROP `ticket_template_project_template_id`");
@@ -1831,61 +1831,121 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
`ticket_template_order` INT(11) NOT NULL DEFAULT 0, `ticket_template_order` INT(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`ticket_template_id`,`project_template_id`) PRIMARY KEY (`ticket_template_id`,`project_template_id`)
)"); )");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.2'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.2'");
} }
if (CURRENT_DATABASE_VERSION == '1.2.2') { if (CURRENT_DATABASE_VERSION == '1.2.2') {
mysqli_query($mysqli, "ALTER TABLE `tasks` DROP `task_description`"); mysqli_query($mysqli, "ALTER TABLE `tasks` DROP `task_description`");
mysqli_query($mysqli, "ALTER TABLE `task_templates` DROP `task_template_description`"); mysqli_query($mysqli, "ALTER TABLE `task_templates` DROP `task_template_description`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.3'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.3'");
} }
if (CURRENT_DATABASE_VERSION == '1.2.3') { if (CURRENT_DATABASE_VERSION == '1.2.3') {
mysqli_query($mysqli, "ALTER TABLE `projects` ADD `project_manager` INT(11) NOT NULL DEFAULT 0 AFTER `project_due`"); mysqli_query($mysqli, "ALTER TABLE `projects` ADD `project_manager` INT(11) NOT NULL DEFAULT 0 AFTER `project_due`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.4'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.4'");
} }
if (CURRENT_DATABASE_VERSION == '1.2.4') { if (CURRENT_DATABASE_VERSION == '1.2.4') {
mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_project_prefix` VARCHAR(200) NOT NULL DEFAULT 'PRJ-' AFTER `config_default_hourly_rate`"); mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_project_prefix` VARCHAR(200) NOT NULL DEFAULT 'PRJ-' AFTER `config_default_hourly_rate`");
mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_project_next_number` INT(11) NOT NULL DEFAULT 1 AFTER `config_project_prefix`"); mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_project_next_number` INT(11) NOT NULL DEFAULT 1 AFTER `config_project_prefix`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.5'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.5'");
} }
if (CURRENT_DATABASE_VERSION == '1.2.5') { if (CURRENT_DATABASE_VERSION == '1.2.5') {
mysqli_query($mysqli, "ALTER TABLE `projects` ADD `project_prefix` VARCHAR(200) DEFAULT NULL AFTER `project_id`"); mysqli_query($mysqli, "ALTER TABLE `projects` ADD `project_prefix` VARCHAR(200) DEFAULT NULL AFTER `project_id`");
mysqli_query($mysqli, "ALTER TABLE `projects` ADD `project_number` INT(11) NOT NULL DEFAULT 1 AFTER `project_prefix`"); mysqli_query($mysqli, "ALTER TABLE `projects` ADD `project_number` INT(11) NOT NULL DEFAULT 1 AFTER `project_prefix`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.6'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.6'");
} }
if (CURRENT_DATABASE_VERSION == '1.2.6') { if (CURRENT_DATABASE_VERSION == '1.2.6') {
mysqli_query($mysqli, "ALTER TABLE `domains` ADD `domain_dnshost` INT(11) NOT NULL DEFAULT 0 AFTER `domain_webhost`"); mysqli_query($mysqli, "ALTER TABLE `domains` ADD `domain_dnshost` INT(11) NOT NULL DEFAULT 0 AFTER `domain_webhost`");
mysqli_query($mysqli, "ALTER TABLE `domains` ADD `domain_mailhost` INT(11) NOT NULL DEFAULT 0 AFTER `domain_dnshost`"); mysqli_query($mysqli, "ALTER TABLE `domains` ADD `domain_mailhost` INT(11) NOT NULL DEFAULT 0 AFTER `domain_dnshost`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.7'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.7'");
} }
if (CURRENT_DATABASE_VERSION == '1.2.7') { if (CURRENT_DATABASE_VERSION == '1.2.7') {
mysqli_query($mysqli, "ALTER TABLE `recurring` ADD `recurring_invoice_email_notify` TINYINT(1) NOT NULL DEFAULT 1 AFTER `recurring_note`"); mysqli_query($mysqli, "ALTER TABLE `recurring` ADD `recurring_invoice_email_notify` TINYINT(1) NOT NULL DEFAULT 1 AFTER `recurring_note`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.8'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.8'");
} }
// if (CURRENT_DATABASE_VERSION == '1.2.8') { if (CURRENT_DATABASE_VERSION == '1.2.8') {
// // Insert queries here required to update to DB version 1.2.9
mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_phone_mask` TINYINT(1) NOT NULL DEFAULT 1 AFTER `config_destructive_deletes_enable`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.9'");
}
if (CURRENT_DATABASE_VERSION == '1.2.9') {
mysqli_query($mysqli, "CREATE TABLE `user_permissions` (`user_id` int(11) NOT NULL,`client_id` int(11) NOT NULL, PRIMARY KEY (`user_id`,`client_id`))");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.0'");
}
if (CURRENT_DATABASE_VERSION == '1.3.0') {
mysqli_query($mysqli, "CREATE TABLE `user_roles` (
`user_role_id` INT(11) NOT NULL AUTO_INCREMENT,
`user_role_name` VARCHAR(200) NOT NULL,
`user_role_description` VARCHAR(200) NULL DEFAULT NULL,
`user_role_created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`user_role_updated_at` DATETIME ON UPDATE CURRENT_TIMESTAMP NULL,
`user_role_archived_at` DATETIME NULL,
PRIMARY KEY (`user_role_id`)
)");
mysqli_query($mysqli, "INSERT INTO `user_roles` SET user_role_id = 1, user_role_name = 'Accountant', user_role_description = 'Built-in - Limited access to financial-focused modules'");
mysqli_query($mysqli, "INSERT INTO `user_roles` SET user_role_id = 2, user_role_name = 'Technician', user_role_description = 'Built-in - Limited access to technical-focused modules'");
mysqli_query($mysqli, "INSERT INTO `user_roles` SET user_role_id = 3, user_role_name = 'Administrator', user_role_description = 'Built-in - Full administrative access to all modules (including user management)'");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.1'");
}
if (CURRENT_DATABASE_VERSION == '1.3.1') {
mysqli_query($mysqli, "ALTER TABLE `user_settings` ADD `user_config_calendar_first_day` TINYINT(1) NOT NULL DEFAULT 0 AFTER `user_config_dashboard_technical_enable`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.2'");
}
if (CURRENT_DATABASE_VERSION == '1.3.2') {
mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_ticket_default_billable` TINYINT(1) NOT NULL DEFAULT 0 AFTER `config_ticket_new_ticket_notification_email`");
mysqli_query($mysqli, "ALTER TABLE `scheduled_tickets` ADD `scheduled_ticket_billable` TINYINT(1) NOT NULL DEFAULT 0 AFTER `scheduled_ticket_frequency`");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.3'");
}
if (CURRENT_DATABASE_VERSION == '1.3.3') {
// // Insert queries here required to update to DB version 1.3.3
// // Then, update the database to the next sequential version // // Then, update the database to the next sequential version
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.2.9"); mysqli_query($mysqli, "CREATE TABLE `location_tags` (`location_id` int(11) NOT NULL,`tag_id` int(11) NOT NULL, PRIMARY KEY (`location_id`,`tag_id`))");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.4'");
}
if (CURRENT_DATABASE_VERSION == '1.3.4') {
mysqli_query($mysqli, "ALTER TABLE `client_tags` CHANGE `client_tag_client_id` `client_id` INT(11) NOT NULL");
mysqli_query($mysqli, "ALTER TABLE `client_tags` CHANGE `client_tag_tag_id` `tag_id` INT(11) NOT NULL");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.5'");
}
// if (CURRENT_DATABASE_VERSION == '1.3.5') {
// // Insert queries here required to update to DB version 1.3.6
// // Then, update the database to the next sequential version
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.3.6'");
// } // }
} else { } else {
// Up-to-date // Up-to-date
} }

View File

@@ -5,4 +5,4 @@
* It is used in conjunction with database_updates.php * It is used in conjunction with database_updates.php
*/ */
DEFINE("LATEST_DATABASE_VERSION", "1.2.8"); DEFINE("LATEST_DATABASE_VERSION", "1.3.5");

58
db.sql
View File

@@ -250,9 +250,9 @@ DROP TABLE IF EXISTS `client_tags`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
CREATE TABLE `client_tags` ( CREATE TABLE `client_tags` (
`client_tag_client_id` int(11) NOT NULL, `client_id` int(11) NOT NULL,
`client_tag_tag_id` int(11) NOT NULL, `tag_id` int(11) NOT NULL,
PRIMARY KEY (`client_tag_client_id`,`client_tag_tag_id`) PRIMARY KEY (`client_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@@ -751,6 +751,20 @@ CREATE TABLE `invoices` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `location_tags`
--
DROP TABLE IF EXISTS `location_tags`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `location_tags` (
`location_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
PRIMARY KEY (`location_id`,`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
-- --
-- Table structure for table `locations` -- Table structure for table `locations`
-- --
@@ -1156,6 +1170,7 @@ CREATE TABLE `scheduled_tickets` (
`scheduled_ticket_details` longtext NOT NULL, `scheduled_ticket_details` longtext NOT NULL,
`scheduled_ticket_priority` varchar(200) DEFAULT NULL, `scheduled_ticket_priority` varchar(200) DEFAULT NULL,
`scheduled_ticket_frequency` varchar(10) NOT NULL, `scheduled_ticket_frequency` varchar(10) NOT NULL,
`scheduled_ticket_billable` tinyint(1) NOT NULL DEFAULT 0,
`scheduled_ticket_start_date` date NOT NULL, `scheduled_ticket_start_date` date NOT NULL,
`scheduled_ticket_next_run` date NOT NULL, `scheduled_ticket_next_run` date NOT NULL,
`scheduled_ticket_created_at` datetime NOT NULL DEFAULT current_timestamp(), `scheduled_ticket_created_at` datetime NOT NULL DEFAULT current_timestamp(),
@@ -1341,6 +1356,7 @@ CREATE TABLE `settings` (
`config_ticket_autoclose` tinyint(1) NOT NULL DEFAULT 0, `config_ticket_autoclose` tinyint(1) NOT NULL DEFAULT 0,
`config_ticket_autoclose_hours` int(5) NOT NULL DEFAULT 72, `config_ticket_autoclose_hours` int(5) NOT NULL DEFAULT 72,
`config_ticket_new_ticket_notification_email` varchar(200) DEFAULT NULL, `config_ticket_new_ticket_notification_email` varchar(200) DEFAULT NULL,
`config_ticket_default_billable` tinyint(1) NOT NULL DEFAULT 0,
`config_enable_cron` tinyint(1) NOT NULL DEFAULT 0, `config_enable_cron` tinyint(1) NOT NULL DEFAULT 0,
`config_cron_key` varchar(255) DEFAULT NULL, `config_cron_key` varchar(255) DEFAULT NULL,
`config_recurring_auto_send_invoice` tinyint(1) NOT NULL DEFAULT 1, `config_recurring_auto_send_invoice` tinyint(1) NOT NULL DEFAULT 1,
@@ -1375,6 +1391,7 @@ CREATE TABLE `settings` (
`config_telemetry` tinyint(1) DEFAULT 0, `config_telemetry` tinyint(1) DEFAULT 0,
`config_timezone` varchar(200) NOT NULL DEFAULT 'America/New_York', `config_timezone` varchar(200) NOT NULL DEFAULT 'America/New_York',
`config_destructive_deletes_enable` tinyint(1) NOT NULL DEFAULT 0, `config_destructive_deletes_enable` tinyint(1) NOT NULL DEFAULT 0,
`config_phone_mask` tinyint(1) NOT NULL DEFAULT 1,
PRIMARY KEY (`company_id`) PRIMARY KEY (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@@ -1776,6 +1793,38 @@ CREATE TABLE `trips` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `user_permissions`
--
DROP TABLE IF EXISTS `user_permissions`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `user_permissions` (
`user_id` int(11) NOT NULL,
`client_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`,`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `user_roles`
--
DROP TABLE IF EXISTS `user_roles`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `user_roles` (
`user_role_id` int(11) NOT NULL AUTO_INCREMENT,
`user_role_name` varchar(200) NOT NULL,
`user_role_description` varchar(200) DEFAULT NULL,
`user_role_created_at` datetime NOT NULL DEFAULT current_timestamp(),
`user_role_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
`user_role_archived_at` datetime DEFAULT NULL,
PRIMARY KEY (`user_role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
-- --
-- Table structure for table `user_settings` -- Table structure for table `user_settings`
-- --
@@ -1790,6 +1839,7 @@ CREATE TABLE `user_settings` (
`user_config_records_per_page` int(11) NOT NULL DEFAULT 10, `user_config_records_per_page` int(11) NOT NULL DEFAULT 10,
`user_config_dashboard_financial_enable` tinyint(1) NOT NULL DEFAULT 0, `user_config_dashboard_financial_enable` tinyint(1) NOT NULL DEFAULT 0,
`user_config_dashboard_technical_enable` tinyint(1) NOT NULL DEFAULT 0, `user_config_dashboard_technical_enable` tinyint(1) NOT NULL DEFAULT 0,
`user_config_calendar_first_day` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`user_id`) PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@@ -1902,4 +1952,4 @@ CREATE TABLE `vendors` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2024-04-12 19:37:23 -- Dump completed on 2024-05-31 16:45:46

View File

@@ -36,8 +36,9 @@ require_once "header.php";
if (!empty($session_token)) { if (!empty($session_token)) {
//Generate QR Code based off the generated key // Generate QR Code
print sprintf('<img src="%s"/>', TokenAuth6238::getBarCodeUrl($session_name, ' ', $session_token, $_SERVER['SERVER_NAME'])); $data = "otpauth://totp/ITFlow:$session_email?secret=$session_token";
print "<img src='plugins/barcode/barcode.php?f=png&s=qr&d=$data'>";
echo "<p class='text-secondary'>$session_token</p>"; echo "<p class='text-secondary'>$session_token</p>";
} }

View File

@@ -212,6 +212,16 @@ function truncate($text, $chars)
function formatPhoneNumber($phoneNumber) function formatPhoneNumber($phoneNumber)
{ {
global $mysqli;
// Get Phone Mask Option
$phone_mask = mysqli_fetch_array(mysqli_query($mysqli, "SELECT config_phone_mask FROM settings WHERE company_id = 1"))[0];
if ($phone_mask == 0) {
return $phoneNumber;
}
$phoneNumber = $phoneNumber ? preg_replace('/[^0-9]/', '', $phoneNumber) : ""; $phoneNumber = $phoneNumber ? preg_replace('/[^0-9]/', '', $phoneNumber) : "";
if (strlen($phoneNumber) > 10) { if (strlen($phoneNumber) > 10) {
@@ -427,9 +437,18 @@ function getDomainRecords($name)
// Used to automatically attempt to get SSL certificates as part of adding domains // Used to automatically attempt to get SSL certificates as part of adding domains
// The logic for the fetch (sync) button on the client_certificates page is in ajax.php, and allows ports other than 443 // The logic for the fetch (sync) button on the client_certificates page is in ajax.php, and allows ports other than 443
function getSSL($name) function getSSL($full_name)
{ {
// Parse host and port
$name = parse_url("//$full_name", PHP_URL_HOST);
$port = parse_url("//$full_name", PHP_URL_PORT);
// Default port
if (!$port) {
$port = "443";
}
$certificate = array(); $certificate = array();
$certificate['success'] = false; $certificate['success'] = false;
@@ -442,7 +461,7 @@ function getSSL($name)
} }
// Get SSL/TSL certificate (using verify peer false to allow for self-signed certs) for domain on default port // Get SSL/TSL certificate (using verify peer false to allow for self-signed certs) for domain on default port
$socket = "ssl://$name:443"; $socket = "ssl://$name:$port";
$get = stream_context_create(array("ssl" => array("capture_peer_cert" => true, "verify_peer" => false,))); $get = stream_context_create(array("ssl" => array("capture_peer_cert" => true, "verify_peer" => false,)));
$read = stream_socket_client($socket, $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $get); $read = stream_socket_client($socket, $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $get);
@@ -881,7 +900,7 @@ function getSettingValue($mysqli, $setting_name)
function getMonthlyTax($tax_name, $month, $year, $mysqli) function getMonthlyTax($tax_name, $month, $year, $mysqli)
{ {
// SQL to calculate monthly tax // SQL to calculate monthly tax
$sql = "SELECT SUM(item_tax) AS monthly_tax FROM invoice_items $sql = "SELECT SUM(item_tax) AS monthly_tax FROM invoice_items
LEFT JOIN invoices ON invoice_items.item_invoice_id = invoices.invoice_id LEFT JOIN invoices ON invoice_items.item_invoice_id = invoices.invoice_id
LEFT JOIN payments ON invoices.invoice_id = payments.payment_invoice_id LEFT JOIN payments ON invoices.invoice_id = payments.payment_invoice_id
WHERE YEAR(payments.payment_date) = $year AND MONTH(payments.payment_date) = $month WHERE YEAR(payments.payment_date) = $year AND MONTH(payments.payment_date) = $month
@@ -898,7 +917,7 @@ function getQuarterlyTax($tax_name, $quarter, $year, $mysqli)
$end_month = $start_month + 2; $end_month = $start_month + 2;
// SQL to calculate quarterly tax // SQL to calculate quarterly tax
$sql = "SELECT SUM(item_tax) AS quarterly_tax FROM invoice_items $sql = "SELECT SUM(item_tax) AS quarterly_tax FROM invoice_items
LEFT JOIN invoices ON invoice_items.item_invoice_id = invoices.invoice_id LEFT JOIN invoices ON invoice_items.item_invoice_id = invoices.invoice_id
LEFT JOIN payments ON invoices.invoice_id = payments.payment_invoice_id LEFT JOIN payments ON invoices.invoice_id = payments.payment_invoice_id
WHERE YEAR(payments.payment_date) = $year AND MONTH(payments.payment_date) BETWEEN $start_month AND $end_month WHERE YEAR(payments.payment_date) = $year AND MONTH(payments.payment_date) BETWEEN $start_month AND $end_month
@@ -911,7 +930,7 @@ function getQuarterlyTax($tax_name, $quarter, $year, $mysqli)
function getTotalTax($tax_name, $year, $mysqli) function getTotalTax($tax_name, $year, $mysqli)
{ {
// SQL to calculate total tax // SQL to calculate total tax
$sql = "SELECT SUM(item_tax) AS total_tax FROM invoice_items $sql = "SELECT SUM(item_tax) AS total_tax FROM invoice_items
LEFT JOIN invoices ON invoice_items.item_invoice_id = invoices.invoice_id LEFT JOIN invoices ON invoice_items.item_invoice_id = invoices.invoice_id
LEFT JOIN payments ON invoices.invoice_id = payments.payment_invoice_id LEFT JOIN payments ON invoices.invoice_id = payments.payment_invoice_id
WHERE YEAR(payments.payment_date) = $year WHERE YEAR(payments.payment_date) = $year
@@ -1172,3 +1191,34 @@ function getTicketStatusName($ticket_status) {
return "Unknown"; return "Unknown";
} }
function fetchUpdates() {
global $repo_branch;
// Fetch the latest code changes but don't apply them
exec("git fetch", $output, $result);
$latest_version = exec("git rev-parse origin/$repo_branch");
$current_version = exec("git rev-parse HEAD");
if ($current_version == $latest_version) {
$update_message = "No Updates available";
} else {
$update_message = "New Updates are Available [$latest_version]";
}
$updates = new stdClass();
$updates->output = $output;
$updates->result = $result;
$updates->current_version = $current_version;
$updates->latest_version = $latest_version;
$updates->update_message = $update_message;
return $updates;
}

View File

@@ -72,6 +72,7 @@ $config_ticket_client_general_notifications = intval($row['config_ticket_client_
$config_ticket_autoclose = intval($row['config_ticket_autoclose']); $config_ticket_autoclose = intval($row['config_ticket_autoclose']);
$config_ticket_autoclose_hours = intval($row['config_ticket_autoclose_hours']); $config_ticket_autoclose_hours = intval($row['config_ticket_autoclose_hours']);
$config_ticket_new_ticket_notification_email = $row['config_ticket_new_ticket_notification_email']; $config_ticket_new_ticket_notification_email = $row['config_ticket_new_ticket_notification_email'];
$config_ticket_default_billable = intval($row['config_ticket_default_billable']);
// Cron // Cron
$config_enable_cron = intval($row['config_enable_cron']); $config_enable_cron = intval($row['config_enable_cron']);

View File

@@ -24,6 +24,7 @@ if (isset($_GET['query'])) {
LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1 LEFT JOIN locations ON clients.client_id = locations.location_client_id AND location_primary = 1
WHERE client_archived_at IS NULL WHERE client_archived_at IS NULL
AND client_name LIKE '%$query%' AND client_name LIKE '%$query%'
$access_permission_query
ORDER BY client_id DESC LIMIT 5" ORDER BY client_id DESC LIMIT 5"
); );
@@ -35,6 +36,7 @@ if (isset($_GET['query'])) {
OR contact_email LIKE '%$query%' OR contact_email LIKE '%$query%'
OR contact_phone LIKE '%$phone_query%' OR contact_phone LIKE '%$phone_query%'
OR contact_mobile LIKE '%$phone_query%') OR contact_mobile LIKE '%$phone_query%')
$access_permission_query
ORDER BY contact_id DESC LIMIT 5" ORDER BY contact_id DESC LIMIT 5"
); );
@@ -43,6 +45,7 @@ if (isset($_GET['query'])) {
WHERE vendor_archived_at IS NULL WHERE vendor_archived_at IS NULL
AND vendor_template = 0 AND vendor_template = 0
AND (vendor_name LIKE '%$query%' OR vendor_phone LIKE '%$phone_query%') AND (vendor_name LIKE '%$query%' OR vendor_phone LIKE '%$phone_query%')
$access_permission_query
ORDER BY vendor_id DESC LIMIT 5" ORDER BY vendor_id DESC LIMIT 5"
); );
@@ -50,6 +53,7 @@ if (isset($_GET['query'])) {
LEFT JOIN clients ON domain_client_id = client_id LEFT JOIN clients ON domain_client_id = client_id
WHERE domain_archived_at IS NULL WHERE domain_archived_at IS NULL
AND domain_name LIKE '%$query%' AND domain_name LIKE '%$query%'
$access_permission_query
ORDER BY domain_id DESC LIMIT 5" ORDER BY domain_id DESC LIMIT 5"
); );
@@ -63,6 +67,7 @@ if (isset($_GET['query'])) {
LEFT JOIN clients on document_client_id = clients.client_id LEFT JOIN clients on document_client_id = clients.client_id
WHERE document_archived_at IS NULL WHERE document_archived_at IS NULL
AND MATCH(document_content_raw) AGAINST ('$query') AND MATCH(document_content_raw) AGAINST ('$query')
$access_permission_query
ORDER BY document_id DESC LIMIT 5" ORDER BY document_id DESC LIMIT 5"
); );
@@ -72,6 +77,7 @@ if (isset($_GET['query'])) {
WHERE file_archived_at IS NULL WHERE file_archived_at IS NULL
AND (file_name LIKE '%$query%' AND (file_name LIKE '%$query%'
OR file_description LIKE '%$query%') OR file_description LIKE '%$query%')
$access_permission_query
ORDER BY file_id DESC LIMIT 5" ORDER BY file_id DESC LIMIT 5"
); );
@@ -81,6 +87,7 @@ if (isset($_GET['query'])) {
WHERE ticket_archived_at IS NULL WHERE ticket_archived_at IS NULL
AND (ticket_subject LIKE '%$query%' AND (ticket_subject LIKE '%$query%'
OR ticket_number = '$ticket_num_query') OR ticket_number = '$ticket_num_query')
$access_permission_query
ORDER BY ticket_id DESC LIMIT 5" ORDER BY ticket_id DESC LIMIT 5"
); );
@@ -88,6 +95,7 @@ if (isset($_GET['query'])) {
LEFT JOIN clients ON scheduled_ticket_client_id = client_id LEFT JOIN clients ON scheduled_ticket_client_id = client_id
WHERE scheduled_ticket_subject LIKE '%$query%' WHERE scheduled_ticket_subject LIKE '%$query%'
OR scheduled_ticket_details LIKE '%$query%' OR scheduled_ticket_details LIKE '%$query%'
$access_permission_query
ORDER BY scheduled_ticket_id DESC LIMIT 5" ORDER BY scheduled_ticket_id DESC LIMIT 5"
); );
@@ -96,6 +104,7 @@ if (isset($_GET['query'])) {
LEFT JOIN clients ON login_client_id = client_id LEFT JOIN clients ON login_client_id = client_id
WHERE login_archived_at IS NULL WHERE login_archived_at IS NULL
AND (login_name LIKE '%$query%' OR login_description LIKE '%$query%') AND (login_name LIKE '%$query%' OR login_description LIKE '%$query%')
$access_permission_query
ORDER BY login_id DESC LIMIT 5" ORDER BY login_id DESC LIMIT 5"
); );
@@ -104,6 +113,7 @@ if (isset($_GET['query'])) {
LEFT JOIN categories ON invoice_category_id = category_id LEFT JOIN categories ON invoice_category_id = category_id
WHERE invoice_archived_at IS NULL WHERE invoice_archived_at IS NULL
AND (CONCAT(invoice_prefix,invoice_number) LIKE '%$query%' OR invoice_scope LIKE '%$query%') AND (CONCAT(invoice_prefix,invoice_number) LIKE '%$query%' OR invoice_scope LIKE '%$query%')
$access_permission_query
ORDER BY invoice_number DESC LIMIT 5" ORDER BY invoice_number DESC LIMIT 5"
); );
@@ -113,6 +123,7 @@ if (isset($_GET['query'])) {
LEFT JOIN clients ON asset_client_id = client_id LEFT JOIN clients ON asset_client_id = client_id
WHERE asset_archived_at IS NULL WHERE asset_archived_at IS NULL
AND (asset_name LIKE '%$query%' OR asset_description LIKE '%$query%' OR asset_type LIKE '%$query%' OR asset_make LIKE '%$query%' OR asset_model LIKE '%$query%' OR asset_serial LIKE '%$query%' OR asset_os LIKE '%$query%' OR asset_ip LIKE '%$query%' OR asset_nat_ip LIKE '%$query%' OR asset_mac LIKE '%$query%' OR asset_status LIKE '%$query%') AND (asset_name LIKE '%$query%' OR asset_description LIKE '%$query%' OR asset_type LIKE '%$query%' OR asset_make LIKE '%$query%' OR asset_model LIKE '%$query%' OR asset_serial LIKE '%$query%' OR asset_os LIKE '%$query%' OR asset_ip LIKE '%$query%' OR asset_nat_ip LIKE '%$query%' OR asset_mac LIKE '%$query%' OR asset_status LIKE '%$query%')
$access_permission_query
ORDER BY asset_name DESC LIMIT 5" ORDER BY asset_name DESC LIMIT 5"
); );
@@ -121,6 +132,7 @@ if (isset($_GET['query'])) {
LEFT JOIN clients ON ticket_client_id = client_id LEFT JOIN clients ON ticket_client_id = client_id
WHERE ticket_reply_archived_at IS NULL WHERE ticket_reply_archived_at IS NULL
AND (ticket_reply LIKE '%$query%') AND (ticket_reply LIKE '%$query%')
$access_permission_query
ORDER BY ticket_id DESC, ticket_reply_id ASC LIMIT 20" ORDER BY ticket_id DESC, ticket_reply_id ASC LIMIT 20"
); );

View File

@@ -15,6 +15,12 @@ $user_agent = sanitizeInput($_SERVER['HTTP_USER_AGENT']);
$os = sanitizeInput(getOS($user_agent)); $os = sanitizeInput(getOS($user_agent));
$browser = sanitizeInput(getWebBrowser($user_agent)); $browser = sanitizeInput(getWebBrowser($user_agent));
// Get Company Name
$sql = mysqli_query($mysqli, "SELECT company_name FROM companies WHERE company_id = 1");
$row = mysqli_fetch_array($sql);
$session_company_name = $row['company_name'];
?> ?>
<!DOCTYPE html> <!DOCTYPE html>
@@ -25,7 +31,7 @@ $browser = sanitizeInput(getWebBrowser($user_agent));
<meta http-equiv="x-ua-compatible" content="ie=edge"> <meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="robots" content="noindex"> <meta name="robots" content="noindex">
<title><?php echo nullable_htmlentities($config_app_name); ?></title> <title><?php echo nullable_htmlentities($session_company_name); ?></title>
<!-- <!--
Favicon Favicon

View File

@@ -12,6 +12,10 @@ require_once "top_nav.php";
// Get Main Side Bar Badge Counts // Get Main Side Bar Badge Counts
// Active Clients Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('client_id') AS num FROM clients WHERE client_archived_at IS NULL"));
$num_active_clients = $row['num'];
// Active Ticket Count // Active Ticket Count
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS num FROM tickets WHERE ticket_archived_at IS NULL AND ticket_closed_at IS NULL AND ticket_status != 4")); $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('ticket_id') AS num FROM tickets WHERE ticket_archived_at IS NULL AND ticket_closed_at IS NULL AND ticket_status != 4"));
$num_active_tickets = $row['num']; $num_active_tickets = $row['num'];

View File

@@ -6,14 +6,22 @@ require_once "functions.php";
require_once "check_login.php"; require_once "check_login.php";
require_once "header.php";
require_once "top_nav.php";
if (isset($_GET['client_id'])) { if (isset($_GET['client_id'])) {
$client_id = intval($_GET['client_id']); $client_id = intval($_GET['client_id']);
// Check to see if the logged in user has permission to access this client (Admins have access to all no matter what perms are set)
if(!in_array($client_id, $client_access_array) AND !empty($client_access_string) AND $session_user_role < 3) {
// Logging
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Client', log_action = 'Access', log_description = '$session_name was denied permission from accessing client', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $client_id");
$_SESSION['alert_type'] = "error";
$_SESSION['alert_message'] = "Access Denied - You do not have permission to access that client!";
echo "<script>window.history.back();</script>";
exit();
}
$sql = mysqli_query($mysqli, "UPDATE clients SET client_accessed_at = NOW() WHERE client_id = $client_id"); $sql = mysqli_query($mysqli, "UPDATE clients SET client_accessed_at = NOW() WHERE client_id = $client_id");
$sql = mysqli_query( $sql = mysqli_query(
@@ -69,7 +77,7 @@ if (isset($_GET['client_id'])) {
$client_tag_name_display_array = array(); $client_tag_name_display_array = array();
$client_tag_id_array = array(); $client_tag_id_array = array();
$sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.client_tag_tag_id = tags.tag_id WHERE client_tags.client_tag_client_id = $client_id ORDER BY tag_name ASC"); $sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.tag_id = tags.tag_id WHERE client_id = $client_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_client_tags)) { while ($row = mysqli_fetch_array($sql_client_tags)) {
$client_tag_id = intval($row['tag_id']); $client_tag_id = intval($row['tag_id']);
@@ -231,6 +239,10 @@ if (isset($_GET['client_id'])) {
} }
} }
require_once "header.php";
require_once "top_nav.php";
require_once "client_side_nav.php"; require_once "client_side_nav.php";
require_once "inc_wrapper.php"; require_once "inc_wrapper.php";

View File

@@ -1,147 +0,0 @@
// ticketCounter.js
(function() {
function getRunningTicketCount() {
let count = 0;
for (let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
if (key.includes("ticket-timer-running")) {
let isRunning = JSON.parse(localStorage.getItem(key));
if (isRunning) {
count++;
}
}
}
return count;
}
function updateTicketCountDisplay() {
let count = getRunningTicketCount();
let countDisplay = document.getElementById("runningTicketsCount");
if (countDisplay) {
countDisplay.innerText = count;
}
if (count == 0) {
countDisplay.classList.remove('badge-danger');
} else {
//check to see if more than one ticket
if (count > 1) {
countDisplay.classList.add('badge-danger');
}
//if count is one, check to see if its open in the current window by looking at the post variable ticket_id in url
if (count == 1) {
let urlParams = new URLSearchParams(window.location.search);
let ticketID = urlParams.get('ticket_id');
console.log(ticketID);
// If ticket number equals one in local storage, then add badge-danger class
if (localStorage.getItem("ticket-timer-running-") == ticketID) {
countDisplay.classList.add('badge-danger');
} else {
countDisplay.classList.remove('badge-danger');
}
}
}
}
function getElapsedSeconds(ticketID) {
let storedStartTime = parseInt(localStorage.getItem(ticketID + "-startTime") || "0");
let pausedTime = parseInt(localStorage.getItem(ticketID + "-pausedTime") || "0");
if (!storedStartTime) return pausedTime;
let timeSinceStart = Math.floor((Date.now() - storedStartTime) / 1000);
return pausedTime + timeSinceStart;
}
function formatTime(seconds) {
let hours = Math.floor(seconds / 3600);
let minutes = Math.floor((seconds % 3600) / 60);
let secs = seconds % 60;
return `${hours}h ${minutes}m ${secs}s`;
}
function loadOpenTickets() {
let openTicketsContainer = document.getElementById('openTicketsContainer');
openTicketsContainer.innerHTML = ''; // Clear existing content
for (let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
if (key.startsWith("ticket-timer-running-")) {
let ticketID = key.replace("ticket-timer-running-", "");
let isRunning = JSON.parse(localStorage.getItem(key));
let ticketDiv = document.createElement('div');
ticketDiv.classList.add('card', 'card-outline', 'mb-3');
// Add class based on ticket status
ticketDiv.classList.add(isRunning ? 'card-info' : 'card-warning');
ticketDiv.id = 'ticket-' + ticketID;
let elapsedSecs = getElapsedSeconds(ticketID);
let timeString = formatTime(elapsedSecs);
ticketDiv.innerHTML = `
<div class="card-header">
<h3 class="card-title">Ticket ID: ${ticketID}</h3>
<a href="/ticket.php?ticket_id=${ticketID}" class="btn btn-primary float-right">View Ticket</a>
</div>
<div class="card-body">
<p id="time-${ticketID}">Total Time: ${timeString}</p>
</div>
`;
openTicketsContainer.appendChild(ticketDiv);
}
}
requestAnimationFrame(() => updateRunningTickets());
}
function updateRunningTickets() {
let runningTickets = document.querySelectorAll('[id^="ticket-"]');
runningTickets.forEach(ticket => {
let ticketID = ticket.id.replace("ticket-", "");
let isRunning = JSON.parse(localStorage.getItem("ticket-timer-running-" + ticketID));
if (isRunning) {
let updatedTime = formatTime(getElapsedSeconds(ticketID));
document.getElementById('time-' + ticketID).innerText = 'Total Time: ' + updatedTime;
}
});
requestAnimationFrame(updateRunningTickets);
}
function clearAllTimers() {
// Collect keys to be removed
let keysToRemove = [];
for (let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
if (key.startsWith("ticket-timer-running-") || key.endsWith("-startTime") || key.endsWith("-pausedTime")) {
keysToRemove.push(key);
}
}
// Remove collected keys
keysToRemove.forEach(key => localStorage.removeItem(key));
// Update the display and redirect
updateTicketCountDisplay();
window.location.href = "/tickets.php";
}
// Initial update on script load
updateTicketCountDisplay();
// update every 10 seconds
setInterval(updateTicketCountDisplay, 10000);
// Add event listener to modal
document.addEventListener('DOMContentLoaded', function() {
let modal = document.getElementById('openTicketsModal');
if (modal) {
$('#openTicketsModal').on('show.bs.modal', loadOpenTickets);
}
});
// Add event listener to clear all timers button
document.getElementById('clearAllTimers').addEventListener('click', clearAllTimers);
})();

View File

@@ -19,6 +19,7 @@ function populateRecurringTicketEditModal(client_id, ticket_id) {
document.getElementById("editHeader").innerText = " Edit Recurring ticket: " + ticket.scheduled_ticket_subject; document.getElementById("editHeader").innerText = " Edit Recurring ticket: " + ticket.scheduled_ticket_subject;
document.getElementById("editTicketId").value = ticket_id; document.getElementById("editTicketId").value = ticket_id;
document.getElementById("editClientId").value = client_id; document.getElementById("editClientId").value = client_id;
document.getElementById("editTicketBillable").value = ticket.scheduled_ticket_billable;
document.getElementById("editTicketSubject").value = ticket.scheduled_ticket_subject; document.getElementById("editTicketSubject").value = ticket.scheduled_ticket_subject;
document.getElementById("editTicketNextRun").value = ticket.scheduled_ticket_next_run; document.getElementById("editTicketNextRun").value = ticket.scheduled_ticket_next_run;
tinyMCE.get('editTicketDetails').setContent(ticket.scheduled_ticket_details); tinyMCE.get('editTicketDetails').setContent(ticket.scheduled_ticket_details);

View File

@@ -1,19 +0,0 @@
// Ticket.php - Changes the wording of the "Respond" button to "Add note" if reply is not a public update (based on checkbox)
// Get Internal/Public Checkbox
let checkbox = document.getElementById('ticket_reply_type_checkbox');
// Get Respond button
let respond = document.getElementById('ticket_add_reply');
// When checkbox is checked/unchecked, update button wording
checkbox.addEventListener('change', e => {
if (e.target.checked) {
// Public reply
respond.innerHTML = "<i class=\"fas fa-paper-plane mr-2\"></i>Respond";
} else {
// Internal note
respond.innerHTML = "<i class=\"fas fa-sticky-note mr-2\"></i>Add note";
}
});

View File

@@ -8,8 +8,6 @@
var ticketID = getCurrentTicketID(); var ticketID = getCurrentTicketID();
var elapsedSecs = getElapsedSeconds(); var elapsedSecs = getElapsedSeconds();
updateRunningTicketsCount();
function getCurrentTicketID() { function getCurrentTicketID() {
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
return urlParams.get('ticket_id'); return urlParams.get('ticket_id');
@@ -55,7 +53,6 @@
timerInterval = setInterval(countTime, 1000); timerInterval = setInterval(countTime, 1000);
isPaused = false; isPaused = false;
document.getElementById("startStopTimer").innerText = "Pause"; document.getElementById("startStopTimer").innerText = "Pause";
updateRunningTicketsCount();
localStorage.setItem("ticket-timer-running-" + ticketID, "true"); localStorage.setItem("ticket-timer-running-" + ticketID, "true");
} }
@@ -70,7 +67,6 @@
localStorage.removeItem(getLocalStorageKey("startTime")); localStorage.removeItem(getLocalStorageKey("startTime"));
isPaused = true; isPaused = true;
document.getElementById("startStopTimer").innerText = "Start"; document.getElementById("startStopTimer").innerText = "Start";
updateRunningTicketsCount();
localStorage.setItem("ticket-timer-running-" + ticketID, "false"); localStorage.setItem("ticket-timer-running-" + ticketID, "false");
} }
@@ -91,7 +87,6 @@
document.getElementById("startStopTimer").innerText = "Start"; document.getElementById("startStopTimer").innerText = "Start";
} }
localStorage.setItem("ticket-timer-running-" + ticketID, "false"); localStorage.setItem("ticket-timer-running-" + ticketID, "false");
updateRunningTicketsCount();
} }
function forceResetTimer() { function forceResetTimer() {
@@ -102,7 +97,7 @@
displayTime(); displayTime();
document.getElementById("startStopTimer").innerText = "Start"; document.getElementById("startStopTimer").innerText = "Start";
} }
function handleInputFocus() { function handleInputFocus() {
if (!isPaused) { if (!isPaused) {
pauseTimer(); pauseTimer();
@@ -114,7 +109,7 @@
const minutes = parseInt(document.getElementById("minutes").value, 10) || 0; const minutes = parseInt(document.getElementById("minutes").value, 10) || 0;
const seconds = parseInt(document.getElementById("seconds").value, 10) || 0; const seconds = parseInt(document.getElementById("seconds").value, 10) || 0;
elapsedSecs = (hours * 3600) + (minutes * 60) + seconds; elapsedSecs = (hours * 3600) + (minutes * 60) + seconds;
// Update local storage so the manually entered time is retained even if the page is reloaded. // Update local storage so the manually entered time is retained even if the page is reloaded.
if (!timerInterval) { if (!timerInterval) {
localStorage.setItem(getLocalStorageKey("pausedTime"), elapsedSecs.toString()); localStorage.setItem(getLocalStorageKey("pausedTime"), elapsedSecs.toString());
@@ -125,18 +120,6 @@
} }
} }
function updateRunningTicketsCount() {
let runningTickets = parseInt(document.getElementById('runningTicketsCount').innerText, 10);
if (!isPaused && timerInterval) {
runningTickets += 1;
} else {
runningTickets = Math.max(0, runningTickets - 1);
}
document.getElementById('runningTicketsCount').innerText = runningTickets.toString();
}
// Function to check status and pause timer // Function to check status and pause timer
function checkStatusAndPauseTimer() { function checkStatusAndPauseTimer() {
var status = document.querySelector('select[name="status"]').value; var status = document.querySelector('select[name="status"]').value;
@@ -148,7 +131,7 @@
document.getElementById("hours").addEventListener('change', updateTimeFromInput); document.getElementById("hours").addEventListener('change', updateTimeFromInput);
document.getElementById("minutes").addEventListener('change', updateTimeFromInput); document.getElementById("minutes").addEventListener('change', updateTimeFromInput);
document.getElementById("seconds").addEventListener('change', updateTimeFromInput); document.getElementById("seconds").addEventListener('change', updateTimeFromInput);
document.getElementById("hours").addEventListener('focus', handleInputFocus); document.getElementById("hours").addEventListener('focus', handleInputFocus);
document.getElementById("minutes").addEventListener('focus', handleInputFocus); document.getElementById("minutes").addEventListener('focus', handleInputFocus);
document.getElementById("seconds").addEventListener('focus', handleInputFocus); document.getElementById("seconds").addEventListener('focus', handleInputFocus);
@@ -184,11 +167,11 @@
} else if (localStorage.getItem(getLocalStorageKey("startTime"))) { } else if (localStorage.getItem(getLocalStorageKey("startTime"))) {
startTimer(); startTimer();
} }
// Check and pause timer if status is pending // Check and pause timer if status is pending
checkStatusAndPauseTimer(); checkStatusAndPauseTimer();
} catch (error) { } catch (error) {
console.error("There was an issue initializing the timer:", error); console.error("There was an issue initializing the timer:", error);
} }
}); });
})(); })();

View File

@@ -159,7 +159,7 @@ if (isset($_POST['login'])) {
if (isset($_POST['remember_me'])) { if (isset($_POST['remember_me'])) {
// TODO: Record the UA and IP a token is generated from so that can be shown later on // TODO: Record the UA and IP a token is generated from so that can be shown later on
$newRememberToken = bin2hex(random_bytes(64)); $newRememberToken = bin2hex(random_bytes(64));
setcookie('rememberme', $newRememberToken, time() + 86400*2, "/", null, true, true); setcookie('rememberme', $newRememberToken, time() + 86400*$config_login_remember_me_expire, "/", null, true, true);
mysqli_query($mysqli, "INSERT INTO remember_tokens SET remember_token_user_id = $user_id, remember_token_token = '$newRememberToken'"); mysqli_query($mysqli, "INSERT INTO remember_tokens SET remember_token_user_id = $user_id, remember_token_token = '$newRememberToken'");
$extended_log .= ", generated a new remember-me token"; $extended_log .= ", generated a new remember-me token";
@@ -218,9 +218,11 @@ if (isset($_POST['login'])) {
//} //}
} }
if ($_GET['last_visited']) {
header("Location: $config_start_page"); header("Location: ".$_SERVER["REQUEST_SCHEME"] . "://" . $config_base_url . base64_decode($_GET['last_visited']) );
} else {
header("Location: $config_start_page");
}
} else { } else {
// MFA is configured and needs to be confirmed, or was unsuccessful // MFA is configured and needs to be confirmed, or was unsuccessful

3352
plugins/barcode/barcode.php Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@ if (isset($_GET['ai_reword'])) {
$inputJSON = file_get_contents('php://input'); $inputJSON = file_get_contents('php://input');
$input = json_decode($inputJSON, TRUE); // Convert JSON into array. $input = json_decode($inputJSON, TRUE); // Convert JSON into array.
$promptText = "You are an experienced technician at a help desk, training a new technician. You are helping rewrite response for clarity and professionalism, but dont make it too wordy."; $promptText = "reword with html format";
$userText = $input['text']; $userText = $input['text'];
// Preparing the data for the OpenAI Chat API request. // Preparing the data for the OpenAI Chat API request.

View File

@@ -65,7 +65,7 @@ if (isset($_POST['add_client'])) {
if (isset($_POST['tags'])) { if (isset($_POST['tags'])) {
foreach($_POST['tags'] as $tag) { foreach($_POST['tags'] as $tag) {
$tag = intval($tag); $tag = intval($tag);
mysqli_query($mysqli, "INSERT INTO client_tags SET client_tag_client_id = $client_id, client_tag_tag_id = $tag"); mysqli_query($mysqli, "INSERT INTO client_tags SET client_id = $client_id, tag_id = $tag");
} }
} }
@@ -135,12 +135,12 @@ if (isset($_POST['edit_client'])) {
// Tags // Tags
// Delete existing tags // Delete existing tags
mysqli_query($mysqli, "DELETE FROM client_tags WHERE client_tag_client_id = $client_id"); mysqli_query($mysqli, "DELETE FROM client_tags WHERE client_id = $client_id");
// Add new tags // Add new tags
foreach($_POST['tags'] as $tag) { foreach($_POST['tags'] as $tag) {
$tag = intval($tag); $tag = intval($tag);
mysqli_query($mysqli, "INSERT INTO client_tags SET client_tag_client_id = $client_id, client_tag_tag_id = $tag"); mysqli_query($mysqli, "INSERT INTO client_tags SET client_id = $client_id, tag_id = $tag");
} }
// Logging // Logging
@@ -297,6 +297,9 @@ if (isset($_GET['delete_client'])) {
mysqli_query($mysqli, "DELETE FROM trips WHERE trip_client_id = $client_id"); mysqli_query($mysqli, "DELETE FROM trips WHERE trip_client_id = $client_id");
mysqli_query($mysqli, "DELETE FROM vendors WHERE vendor_client_id = $client_id"); mysqli_query($mysqli, "DELETE FROM vendors WHERE vendor_client_id = $client_id");
// Delete tags
mysqli_query($mysqli, "DELETE FROM client_tags WHERE client_id = $client_id");
//Delete Client Files //Delete Client Files
removeDirectory('uploads/clients/$client_id'); removeDirectory('uploads/clients/$client_id');

View File

@@ -23,7 +23,7 @@ if (isset($_POST['upload_files'])) {
'size' => $_FILES['file']['size'][$i] 'size' => $_FILES['file']['size'][$i]
]; ];
if ($file_reference_name = checkFileUpload($single_file, array('jpg', 'jpeg', 'gif', 'png', 'webp', 'pdf', 'txt', 'md', 'doc', 'docx', 'odt', 'csv', 'xls', 'xlsx', 'ods', 'pptx', 'odp', 'zip', 'tar', 'gz', 'xml', 'msg', 'json', 'wav', 'mp3', 'ogg', 'mov', 'mp4', 'av1', 'ovpn', 'cfg', 'ps1', 'vsdx', 'drawio', 'pfx', 'pages', 'numbers'))) { if ($file_reference_name = checkFileUpload($single_file, array('jpg', 'jpeg', 'gif', 'png', 'webp', 'pdf', 'txt', 'md', 'doc', 'docx', 'odt', 'csv', 'xls', 'xlsx', 'ods', 'pptx', 'odp', 'zip', 'tar', 'gz', 'xml', 'msg', 'json', 'wav', 'mp3', 'ogg', 'mov', 'mp4', 'av1', 'ovpn', 'cfg', 'ps1', 'vsdx', 'drawio', 'pfx', 'pages', 'numbers', 'unf'))) {
$file_tmp_path = $_FILES['file']['tmp_name'][$i]; $file_tmp_path = $_FILES['file']['tmp_name'][$i];

View File

@@ -19,6 +19,14 @@ if(isset($_POST['add_location'])){
$location_id = mysqli_insert_id($mysqli); $location_id = mysqli_insert_id($mysqli);
// Add Tags
if (isset($_POST['tags'])) {
foreach($_POST['tags'] as $tag) {
$tag = intval($tag);
mysqli_query($mysqli, "INSERT INTO location_tags SET location_id = $location_id, tag_id = $tag");
}
}
// Update Primay location in clients if primary location is checked // Update Primay location in clients if primary location is checked
if ($location_primary == 1) { if ($location_primary == 1) {
mysqli_query($mysqli,"UPDATE locations SET location_primary = 0 WHERE location_client_id = $client_id"); mysqli_query($mysqli,"UPDATE locations SET location_primary = 0 WHERE location_client_id = $client_id");
@@ -82,6 +90,16 @@ if(isset($_POST['edit_location'])){
mysqli_query($mysqli,"UPDATE locations SET location_primary = 1 WHERE location_id = $location_id"); mysqli_query($mysqli,"UPDATE locations SET location_primary = 1 WHERE location_id = $location_id");
} }
// Tags
// Delete existing tags
mysqli_query($mysqli, "DELETE FROM location_tags WHERE location_id = $location_id");
// Add new tags
foreach($_POST['tags'] as $tag) {
$tag = intval($tag);
mysqli_query($mysqli, "INSERT INTO location_tags SET location_id = $location_id, tag_id = $tag");
}
//Check to see if a file is attached //Check to see if a file is attached
if($_FILES['file']['tmp_name'] != ''){ if($_FILES['file']['tmp_name'] != ''){
@@ -174,6 +192,10 @@ if(isset($_GET['delete_location'])){
mysqli_query($mysqli,"DELETE FROM locations WHERE location_id = $location_id"); mysqli_query($mysqli,"DELETE FROM locations WHERE location_id = $location_id");
// Tags
// Delete existing tags
mysqli_query($mysqli, "DELETE FROM location_tags WHERE location_id = $location_id");
//Logging //Logging
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Location', log_action = 'Delete', log_description = '$session_name deleted location $location_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $location_id"); mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Location', log_action = 'Delete', log_description = '$session_name deleted location $location_name', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $location_id");

View File

@@ -144,11 +144,18 @@ if (isset($_POST['edit_your_user_password'])) {
header('Location: post.php?logout'); header('Location: post.php?logout');
} }
if (isset($_POST['edit_your_user_browser_extention'])) { if (isset($_POST['edit_your_user_preferences'])) {
// CSRF Check // CSRF Check
validateCSRFToken($_POST['csrf_token']); validateCSRFToken($_POST['csrf_token']);
$calendar_first_day = intval($_POST['calendar_first_day']);
// Calendar
if (isset($calendar_first_day)) {
mysqli_query($mysqli, "UPDATE user_settings SET user_config_calendar_first_day = $calendar_first_day WHERE user_id = $session_user_id");
}
// Enable extension access, only if it isn't already setup (user doesn't have cookie) // Enable extension access, only if it isn't already setup (user doesn't have cookie)
if (isset($_POST['extension']) && $_POST['extension'] == 'Yes') { if (isset($_POST['extension']) && $_POST['extension'] == 'Yes') {
if (!isset($_COOKIE['user_extension_key'])) { if (!isset($_COOKIE['user_extension_key'])) {

View File

@@ -36,6 +36,7 @@ if (isset($_POST['add_quote'])) {
if (isset($_POST['add_quote_copy'])) { if (isset($_POST['add_quote_copy'])) {
$quote_id = intval($_POST['quote_id']); $quote_id = intval($_POST['quote_id']);
$client_id = intval($_POST['client']);
$date = sanitizeInput($_POST['date']); $date = sanitizeInput($_POST['date']);
$expire = sanitizeInput($_POST['expire']); $expire = sanitizeInput($_POST['expire']);
@@ -51,7 +52,6 @@ if (isset($_POST['add_quote_copy'])) {
$quote_currency_code = sanitizeInput($row['quote_currency_code']); $quote_currency_code = sanitizeInput($row['quote_currency_code']);
$quote_scope = sanitizeInput($row['quote_scope']); $quote_scope = sanitizeInput($row['quote_scope']);
$quote_note = sanitizeInput($row['quote_note']); $quote_note = sanitizeInput($row['quote_note']);
$client_id = intval($row['quote_client_id']);
$category_id = intval($row['quote_category_id']); $category_id = intval($row['quote_category_id']);
//Generate a unique URL key for clients to access //Generate a unique URL key for clients to access
@@ -80,7 +80,7 @@ if (isset($_POST['add_quote_copy'])) {
} }
//Logging //Logging
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Quote', log_action = 'Create', log_description = 'Copied Quote', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Quote', log_action = 'Create', log_description = 'Copied Quote', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id");
$_SESSION['alert_message'] = "Quote copied"; $_SESSION['alert_message'] = "Quote copied";

View File

@@ -5,6 +5,7 @@ $subject = sanitizeInput($_POST['subject']);
$priority = sanitizeInput($_POST['priority']); $priority = sanitizeInput($_POST['priority']);
$details = mysqli_real_escape_string($mysqli, $_POST['details']); $details = mysqli_real_escape_string($mysqli, $_POST['details']);
$frequency = sanitizeInput($_POST['frequency']); $frequency = sanitizeInput($_POST['frequency']);
$billable = intval($_POST['billable']);
$asset_id = "0"; $asset_id = "0";
if (isset($_POST['asset'])) { if (isset($_POST['asset'])) {

View File

@@ -286,11 +286,12 @@ if (isset($_POST['edit_ticket_settings'])) {
$config_ticket_prefix = sanitizeInput($_POST['config_ticket_prefix']); $config_ticket_prefix = sanitizeInput($_POST['config_ticket_prefix']);
$config_ticket_next_number = intval($_POST['config_ticket_next_number']); $config_ticket_next_number = intval($_POST['config_ticket_next_number']);
$config_ticket_email_parse = intval($_POST['config_ticket_email_parse']); $config_ticket_email_parse = intval($_POST['config_ticket_email_parse']);
$config_ticket_default_billable = intval($_POST['config_ticket_default_billable']);
$config_ticket_autoclose = intval($_POST['config_ticket_autoclose']); $config_ticket_autoclose = intval($_POST['config_ticket_autoclose']);
$config_ticket_autoclose_hours = intval($_POST['config_ticket_autoclose_hours']); $config_ticket_autoclose_hours = intval($_POST['config_ticket_autoclose_hours']);
$config_ticket_new_ticket_notification_email = sanitizeInput($_POST['config_ticket_new_ticket_notification_email']); $config_ticket_new_ticket_notification_email = sanitizeInput($_POST['config_ticket_new_ticket_notification_email']);
mysqli_query($mysqli,"UPDATE settings SET config_ticket_prefix = '$config_ticket_prefix', config_ticket_next_number = $config_ticket_next_number, config_ticket_email_parse = $config_ticket_email_parse, config_ticket_autoclose = $config_ticket_autoclose, config_ticket_autoclose_hours = $config_ticket_autoclose_hours, config_ticket_new_ticket_notification_email = '$config_ticket_new_ticket_notification_email' WHERE company_id = 1"); mysqli_query($mysqli,"UPDATE settings SET config_ticket_prefix = '$config_ticket_prefix', config_ticket_next_number = $config_ticket_next_number, config_ticket_email_parse = $config_ticket_email_parse, config_ticket_autoclose = $config_ticket_autoclose, config_ticket_autoclose_hours = $config_ticket_autoclose_hours, config_ticket_new_ticket_notification_email = '$config_ticket_new_ticket_notification_email', config_ticket_default_billable = $config_ticket_default_billable WHERE company_id = 1");
//Logging //Logging
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Settings', log_action = 'Modify', log_description = '$session_name modified ticket settings', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Settings', log_action = 'Modify', log_description = '$session_name modified ticket settings', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id");
@@ -316,8 +317,9 @@ if (isset($_POST['edit_default_settings'])) {
$calendar = intval($_POST['calendar']); $calendar = intval($_POST['calendar']);
$net_terms = intval($_POST['net_terms']); $net_terms = intval($_POST['net_terms']);
$hourly_rate = floatval($_POST['hourly_rate']); $hourly_rate = floatval($_POST['hourly_rate']);
$phone_mask = intval($_POST['phone_mask']);
mysqli_query($mysqli,"UPDATE settings SET config_start_page = '$start_page', config_default_expense_account = $expense_account, config_default_payment_account = $payment_account, config_default_payment_method = '$payment_method', config_default_expense_payment_method = '$expense_payment_method', config_default_transfer_from_account = $transfer_from_account, config_default_transfer_to_account = $transfer_to_account, config_default_calendar = $calendar, config_default_net_terms = $net_terms, config_default_hourly_rate = $hourly_rate WHERE company_id = 1"); mysqli_query($mysqli,"UPDATE settings SET config_start_page = '$start_page', config_default_expense_account = $expense_account, config_default_payment_account = $payment_account, config_default_payment_method = '$payment_method', config_default_expense_payment_method = '$expense_payment_method', config_default_transfer_from_account = $transfer_from_account, config_default_transfer_to_account = $transfer_to_account, config_default_calendar = $calendar, config_default_net_terms = $net_terms, config_default_hourly_rate = $hourly_rate, config_phone_mask = $phone_mask WHERE company_id = 1");
//Logging //Logging
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Settings', log_action = 'Modify', log_description = '$session_name modified default settings', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id"); mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Settings', log_action = 'Modify', log_description = '$session_name modified default settings', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id");

View File

@@ -188,6 +188,7 @@ if (isset($_POST['edit_ticket'])) {
$ticket_id = intval($_POST['ticket_id']); $ticket_id = intval($_POST['ticket_id']);
$contact_id = intval($_POST['contact']); $contact_id = intval($_POST['contact']);
$notify = intval($_POST['contact_notify']); $notify = intval($_POST['contact_notify']);
$category = intval($_POST['category']);
$subject = sanitizeInput($_POST['subject']); $subject = sanitizeInput($_POST['subject']);
$billable = intval($_POST['billable']); $billable = intval($_POST['billable']);
$priority = sanitizeInput($_POST['priority']); $priority = sanitizeInput($_POST['priority']);
@@ -200,7 +201,7 @@ if (isset($_POST['edit_ticket'])) {
$client_id = intval($_POST['client_id']); $client_id = intval($_POST['client_id']);
$ticket_number = sanitizeInput($_POST['ticket_number']); $ticket_number = sanitizeInput($_POST['ticket_number']);
mysqli_query($mysqli, "UPDATE tickets SET ticket_subject = '$subject', ticket_priority = '$priority', ticket_billable = $billable, ticket_details = '$details', ticket_vendor_ticket_number = '$vendor_ticket_number', ticket_contact_id = $contact_id, ticket_vendor_id = $vendor_id, ticket_location_id = $location_id, ticket_asset_id = $asset_id, ticket_project_id = $project_id WHERE ticket_id = $ticket_id"); mysqli_query($mysqli, "UPDATE tickets SET ticket_category = $category, ticket_subject = '$subject', ticket_priority = '$priority', ticket_billable = $billable, ticket_details = '$details', ticket_vendor_ticket_number = '$vendor_ticket_number', ticket_contact_id = $contact_id, ticket_vendor_id = $vendor_id, ticket_location_id = $location_id, ticket_asset_id = $asset_id, ticket_project_id = $project_id WHERE ticket_id = $ticket_id");
// Notify new contact if selected // Notify new contact if selected
if ($notify && !empty($config_smtp_host)) { if ($notify && !empty($config_smtp_host)) {
@@ -1104,9 +1105,14 @@ if (isset($_POST['add_ticket_reply'])) {
$client_id = intval($_POST['client_id']); $client_id = intval($_POST['client_id']);
if (isset($_POST['public_reply_type'])) { $send_email = 0;
if ($_POST['public_reply_type'] == 1 ){
$ticket_reply_type = 'Public'; $ticket_reply_type = 'Public';
} else { } elseif ($_POST['public_reply_type'] == 2 ) {
$ticket_reply_type = 'Public';
$send_email = 1;
} else {
$ticket_reply_type = 'Internal'; $ticket_reply_type = 'Internal';
} }
@@ -1156,7 +1162,7 @@ if (isset($_POST['add_ticket_reply'])) {
$company_phone = sanitizeInput(formatPhoneNumber($row['company_phone'])); $company_phone = sanitizeInput(formatPhoneNumber($row['company_phone']));
// Send e-mail to client if public update & email is set up // Send e-mail to client if public update & email is set up
if ($ticket_reply_type == 'Public' && !empty($config_smtp_host)) { if ($ticket_reply_type == 'Public' && $send_email == 1 && !empty($config_smtp_host)) {
if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) { if (filter_var($contact_email, FILTER_VALIDATE_EMAIL)) {
@@ -1596,7 +1602,7 @@ if (isset($_POST['add_recurring_ticket'])) {
} }
// Add scheduled ticket // Add scheduled ticket
mysqli_query($mysqli, "INSERT INTO scheduled_tickets SET scheduled_ticket_subject = '$subject', scheduled_ticket_details = '$details', scheduled_ticket_priority = '$priority', scheduled_ticket_frequency = '$frequency', scheduled_ticket_start_date = '$start_date', scheduled_ticket_next_run = '$start_date', scheduled_ticket_assigned_to = $assigned_to, scheduled_ticket_created_by = $session_user_id, scheduled_ticket_client_id = $client_id, scheduled_ticket_contact_id = $contact_id, scheduled_ticket_asset_id = $asset_id"); mysqli_query($mysqli, "INSERT INTO scheduled_tickets SET scheduled_ticket_subject = '$subject', scheduled_ticket_details = '$details', scheduled_ticket_priority = '$priority', scheduled_ticket_frequency = '$frequency', scheduled_ticket_billable = $billable, scheduled_ticket_start_date = '$start_date', scheduled_ticket_next_run = '$start_date', scheduled_ticket_assigned_to = $assigned_to, scheduled_ticket_created_by = $session_user_id, scheduled_ticket_client_id = $client_id, scheduled_ticket_contact_id = $contact_id, scheduled_ticket_asset_id = $asset_id");
$scheduled_ticket_id = mysqli_insert_id($mysqli); $scheduled_ticket_id = mysqli_insert_id($mysqli);
@@ -1625,7 +1631,7 @@ if (isset($_POST['edit_recurring_ticket'])) {
} }
// Edit scheduled ticket // Edit scheduled ticket
mysqli_query($mysqli, "UPDATE scheduled_tickets SET scheduled_ticket_subject = '$subject', scheduled_ticket_details = '$details', scheduled_ticket_priority = '$priority', scheduled_ticket_frequency = '$frequency', scheduled_ticket_next_run = '$next_run_date', scheduled_ticket_assigned_to = $assigned_to, scheduled_ticket_asset_id = $asset_id, scheduled_ticket_contact_id = $contact_id WHERE scheduled_ticket_id = $scheduled_ticket_id"); mysqli_query($mysqli, "UPDATE scheduled_tickets SET scheduled_ticket_subject = '$subject', scheduled_ticket_details = '$details', scheduled_ticket_priority = '$priority', scheduled_ticket_frequency = '$frequency', scheduled_ticket_billable = $billable, scheduled_ticket_next_run = '$next_run_date', scheduled_ticket_assigned_to = $assigned_to, scheduled_ticket_asset_id = $asset_id, scheduled_ticket_contact_id = $contact_id WHERE scheduled_ticket_id = $scheduled_ticket_id");
// Logging // Logging
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Recurring Ticket', log_action = 'Modify', log_description = '$session_name modified recurring ticket for $subject - $frequency', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $scheduled_ticket_id"); mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Recurring Ticket', log_action = 'Modify', log_description = '$session_name modified recurring ticket for $subject - $frequency', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_client_id = $client_id, log_user_id = $session_user_id, log_entity_id = $scheduled_ticket_id");

View File

@@ -18,6 +18,14 @@ if (isset($_POST['add_user'])) {
$user_id = mysqli_insert_id($mysqli); $user_id = mysqli_insert_id($mysqli);
// Add Client Access Permissions if set
if (!empty($_POST['clients'])) {
foreach($_POST['clients'] as $client_id) {
$client_id = intval($client_id);
mysqli_query($mysqli,"INSERT INTO user_permissions SET user_id = $user_id, client_id = $client_id");
}
}
if (!file_exists("uploads/users/$user_id/")) { if (!file_exists("uploads/users/$user_id/")) {
mkdir("uploads/users/$user_id"); mkdir("uploads/users/$user_id");
} }
@@ -105,6 +113,15 @@ if (isset($_POST['edit_user'])) {
$user_id = intval($_POST['user_id']); $user_id = intval($_POST['user_id']);
$new_password = trim($_POST['new_password']); $new_password = trim($_POST['new_password']);
// Update Client Access
mysqli_query($mysqli,"DELETE FROM user_permissions WHERE user_id = $user_id");
if (!empty($_POST['clients'])) {
foreach($_POST['clients'] as $client_id) {
$client_id = intval($client_id);
mysqli_query($mysqli,"INSERT INTO user_permissions SET user_id = $user_id, client_id = $client_id");
}
}
// Get current Avatar // Get current Avatar
$sql = mysqli_query($mysqli, "SELECT user_avatar FROM users WHERE user_id = $user_id"); $sql = mysqli_query($mysqli, "SELECT user_avatar FROM users WHERE user_id = $user_id");
$row = mysqli_fetch_array($sql); $row = mysqli_fetch_array($sql);

View File

@@ -11,6 +11,28 @@
<input type="hidden" name="quote_id" value="<?php echo $quote_id; ?>"> <input type="hidden" name="quote_id" value="<?php echo $quote_id; ?>">
<div class="modal-body bg-white"> <div class="modal-body bg-white">
<div class="form-group">
<label>Client <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-users"></i></span>
</div>
<select class="form-control select2" name="client" required>
<?php
$sql_client_select = mysqli_query($mysqli, "SELECT * FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
while ($row = mysqli_fetch_array($sql_client_select)) {
$client_id_select = intval($row['client_id']);
$client_name_select = nullable_htmlentities($row['client_name']);
?>
<option <?php if ($client_id == $client_id_select) { echo "selected"; } ?> value="<?php echo $client_id_select; ?>"><?php echo $client_name_select; ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label>Set Date for New Quote <strong class="text-danger">*</strong></label> <label>Set Date for New Quote <strong class="text-danger">*</strong></label>
<div class="input-group"> <div class="input-group">

View File

@@ -11,6 +11,7 @@
<?php if (isset($client_id)) { ?> <?php if (isset($client_id)) { ?>
<input type="hidden" name="client" value="<?php echo $client_id; ?>>"> <input type="hidden" name="client" value="<?php echo $client_id; ?>>">
<?php } ?> <?php } ?>
<input type="hidden" name="billable" value="0">
<div class="modal-body bg-white"> <div class="modal-body bg-white">
@@ -86,6 +87,15 @@
</div> </div>
</div> </div>
<?php if ($config_module_enable_accounting) { ?>
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" name="billable" <?php if ($config_ticket_default_billable == 1) { echo "checked"; } ?> value="1" id="billable">
<label class="custom-control-label" for="billable">Mark Billable</label>
</div>
</div>
<?php } ?>
</div> </div>

View File

@@ -10,6 +10,7 @@
<form action="post.php" method="post" autocomplete="off"> <form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="scheduled_ticket_id" id="editTicketId"> <input type="hidden" name="scheduled_ticket_id" id="editTicketId">
<input type="hidden" name="client" id="editClientId"> <input type="hidden" name="client" id="editClientId">
<input type="hidden" name="billable" value="0">
<div class="modal-body bg-white"> <div class="modal-body bg-white">
@@ -73,6 +74,15 @@
</div> </div>
</div> </div>
<?php if ($config_module_enable_accounting) { ?>
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" name="billable" id="editTicketBillable" value="1">
<label class="custom-control-label" for="editTicketBillable">Mark Billable</label>
</div>
</div>
<?php } ?>
</div> </div>
<div class="tab-pane fade" id="pills-edit-contacts"> <div class="tab-pane fade" id="pills-edit-contacts">

View File

@@ -50,7 +50,7 @@ if (isset($_GET['year'])) {
$sql_ticket_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(ticket_created_at) AS ticket_year FROM tickets ORDER BY ticket_year DESC"); $sql_ticket_years = mysqli_query($mysqli, "SELECT DISTINCT YEAR(ticket_created_at) AS ticket_year FROM tickets ORDER BY ticket_year DESC");
$sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients ORDER BY client_name ASC"); $sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
?> ?>
@@ -79,6 +79,7 @@ $sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients
<th>Client</th> <th>Client</th>
<th class="text-right">Tickets raised</th> <th class="text-right">Tickets raised</th>
<th class="text-right">Tickets closed</th> <th class="text-right">Tickets closed</th>
<th class="text-right">Time worked <i>(H:M:S)</i></th>
<th class="text-right">Avg time to close</th> <th class="text-right">Avg time to close</th>
</tr> </tr>
</thead> </thead>
@@ -101,6 +102,11 @@ $sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients
// Used to calculate average time to close tickets that were raised in period specified // Used to calculate average time to close tickets that were raised in period specified
$sql_tickets = mysqli_query($mysqli, "SELECT ticket_created_at, ticket_closed_at FROM tickets WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id AND ticket_closed_at IS NOT NULL"); $sql_tickets = mysqli_query($mysqli, "SELECT ticket_created_at, ticket_closed_at FROM tickets WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id AND ticket_closed_at IS NOT NULL");
// Calculate total time tracked towards tickets in the period
$sql_time = mysqli_query($mysqli, "SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(ticket_reply_time_worked))) as total_time FROM ticket_replies LEFT JOIN tickets ON tickets.ticket_id = ticket_replies.ticket_reply_ticket_id WHERE YEAR(ticket_created_at) = $year AND ticket_client_id = $client_id AND ticket_reply_time_worked IS NOT NULL");
$row = mysqli_fetch_array($sql_time);
$ticket_total_time_worked = nullable_htmlentities($row['total_time']);
if ($ticket_raised_count > 0) { if ($ticket_raised_count > 0) {
// Calculate average time to solve // Calculate average time to solve
@@ -120,6 +126,7 @@ $sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients
<td><?php echo $client_name; ?></td> <td><?php echo $client_name; ?></td>
<td class="text-right"><?php echo $ticket_raised_count; ?></td> <td class="text-right"><?php echo $ticket_raised_count; ?></td>
<td class="text-right"><?php echo $ticket_closed_count; ?></td> <td class="text-right"><?php echo $ticket_closed_count; ?></td>
<td class="text-right"><?php echo $ticket_total_time_worked; ?></td>
<td class="text-right"><?php echo secondsToTime($total); ?></td> <td class="text-right"><?php echo secondsToTime($total); ?></td>
</tr> </tr>
<?php <?php

View File

@@ -58,14 +58,6 @@ class TokenAuth6238 {
return $result; return $result;
} }
public static function getBarCodeUrl($username, $domain, $secretkey, $issuer) {
$url = "https://chart.apis.google.com/chart";
$url = $url."?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/";
$url = $url.$username . "@" . $domain . "%3Fsecret%3D" . $secretkey . '%26issuer%3D' . rawurlencode($issuer);
return $url;
}
private static function oath_hotp ($key, $counter, $debug=false) { private static function oath_hotp ($key, $counter, $debug=false) {
$result = ""; $result = "";
$orgcounter = $counter; $orgcounter = $counter;

View File

@@ -218,6 +218,28 @@ require_once "inc_all_admin.php";
</div> </div>
</div> </div>
<div class="form-group">
<label>Phone Mask</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-phone"></i></span>
</div>
<select class="form-control select2" name="phone_mask">
<?php
$sql = mysqli_query($mysqli, "SELECT config_phone_mask FROM settings WHERE company_id = 1");
while ($row = mysqli_fetch_array($sql)) {
$phone_mask = intval($row['config_phone_mask']);
} ?>
<option <?php if ($phone_mask == 1) {
echo "selected";
}?> value=1>Enable</option>
<option <?php if ($phone_mask == 0) {
echo "selected";
}?> value=0>Disabled</option>
</select>
</div>
</div>
<hr> <hr>
<button type="submit" name="edit_default_settings" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Save</button> <button type="submit" name="edit_default_settings" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Save</button>
@@ -228,4 +250,3 @@ require_once "inc_all_admin.php";
<?php <?php
require_once "footer.php"; require_once "footer.php";

View File

@@ -11,6 +11,7 @@ require_once "inc_all_admin.php";
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>"> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<input type="hidden" name="config_ticket_email_parse" value="0"> <input type="hidden" name="config_ticket_email_parse" value="0">
<input type="hidden" name="config_ticket_autoclose" value="0"> <input type="hidden" name="config_ticket_autoclose" value="0">
<input type="hidden" name="config_ticket_default_billable" value="0">
<div class="form-group"> <div class="form-group">
<label>Ticket Prefix</label> <label>Ticket Prefix</label>
@@ -39,6 +40,15 @@ require_once "inc_all_admin.php";
</div> </div>
</div> </div>
<?php if ($config_module_enable_accounting) { ?>
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" name="config_ticket_default_billable" <?php if ($config_ticket_default_billable == 1) { echo "checked"; } ?> value="1" id="ticketBillableSwitch<?php echo $ticket_id; ?>">
<label class="custom-control-label" for="ticketBillableSwitch<?php echo $ticket_id; ?>">Default to Billable <small class="text-secondary">(This will check the billable box on all new tickets)</small></label>
</div>
</div>
<?php } ?>
<div class="form-group"> <div class="form-group">
<div class="custom-control custom-switch"> <div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" name="config_ticket_autoclose" <?php if($config_ticket_autoclose == 1){ echo "checked"; } ?> value="1" id="ticketAutoCloseSwitch"> <input type="checkbox" class="custom-control-input" name="config_ticket_autoclose" <?php if($config_ticket_autoclose == 1){ echo "checked"; } ?> value="1" id="ticketAutoCloseSwitch">

View File

@@ -302,6 +302,11 @@ if (isset($_POST['add_company_settings'])) {
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Auto Close', ticket_status_color = '#343a40'"); // 4 mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Auto Close', ticket_status_color = '#343a40'"); // 4
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Closed', ticket_status_color = '#343a40'"); // 5 mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Closed', ticket_status_color = '#343a40'"); // 5
// Add default roles
mysqli_query($mysqli, "INSERT INTO `user_roles` SET user_role_id = 1, user_role_name = 'Accountant', user_role_description = 'Built-in - Limited access to financial-focused modules'");
mysqli_query($mysqli, "INSERT INTO `user_roles` SET user_role_id = 2, user_role_name = 'Technician', user_role_description = 'Built-in - Limited access to technical-focused modules'");
mysqli_query($mysqli, "INSERT INTO `user_roles` SET user_role_id = 3, user_role_name = 'Administrator', user_role_description = 'Built-in - Full administrative access to all modules (including user management)'");
$_SESSION['alert_message'] = "Company <strong>$name</strong> created!"; $_SESSION['alert_message'] = "Company <strong>$name</strong> created!";
@@ -843,8 +848,9 @@ if (isset($_POST['add_telemetry'])) {
<ul> <ul>
<li>Please take a look over the install <a href="https://docs.itflow.org/installation">docs</a>, if you haven't already</li> <li>Please take a look over the install <a href="https://docs.itflow.org/installation">docs</a>, if you haven't already</li>
<li>Don't hesitate to reach out on the <a href="https://forum.itflow.org/t/support" target="_blank">forums</a> if you need any assistance</li> <li>Don't hesitate to reach out on the <a href="https://forum.itflow.org/t/support" target="_blank">forums</a> if you need any assistance</li>
<li><i>Your PHP Error log is at: <?php echo ini_get('error_log') ?></i></li>
</ul> </ul>
<br><p>A database must be created before proceeding - click on the button below to get started</p> <br><p>A database must be created before proceeding - click on the button below to get started.</p>
<br><hr> <br><hr>
<p class="text-muted">ITFlow is <b>free software</b>: you can redistribute and/or modify it under the terms of the <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GNU General Public License</a>. <br> It is distributed in the hope that it will be useful, but <b>without any warranty</b>; without even the implied warranty of merchantability or fitness for a particular purpose.</p> <p class="text-muted">ITFlow is <b>free software</b>: you can redistribute and/or modify it under the terms of the <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GNU General Public License</a>. <br> It is distributed in the hope that it will be useful, but <b>without any warranty</b>; without even the implied warranty of merchantability or fitness for a particular purpose.</p>
<?php <?php

View File

@@ -20,7 +20,12 @@
<li class="nav-item"> <li class="nav-item">
<a href="clients.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "clients.php") { echo "active"; } ?>"> <a href="clients.php" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "clients.php") { echo "active"; } ?>">
<i class="nav-icon fas fa-user-friends"></i> <i class="nav-icon fas fa-user-friends"></i>
<p>Clients</p> <p>
Clients
<?php if ($num_active_clients) { ?>
<span class="right badge text-light"><?php echo $num_active_clients; ?></span>
<?php } ?>
</p>
</a> </a>
</li> </li>
<?php if ($session_user_role >= 2 && $config_module_enable_ticketing == 1) { ?> <?php if ($session_user_role >= 2 && $config_module_enable_ticketing == 1) { ?>

View File

@@ -1,13 +1,6 @@
<?php <?php
require_once "inc_all.php"; require_once "inc_all.php";
?>
<!-- Custom styling of time tracking elements -->
<link rel="stylesheet" type="text/css" href="css/ticket_time_tracking.css">
<?php
// Initialize the HTML Purifier to prevent XSS // Initialize the HTML Purifier to prevent XSS
require "plugins/htmlpurifier/HTMLPurifier.standalone.php"; require "plugins/htmlpurifier/HTMLPurifier.standalone.php";
@@ -30,6 +23,7 @@ if (isset($_GET['ticket_id'])) {
LEFT JOIN projects ON ticket_project_id = project_id LEFT JOIN projects ON ticket_project_id = project_id
LEFT JOIN invoices ON ticket_invoice_id = invoice_id LEFT JOIN invoices ON ticket_invoice_id = invoice_id
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
LEFT JOIN categories ON ticket_category = category_id
WHERE ticket_id = $ticket_id LIMIT 1" WHERE ticket_id = $ticket_id LIMIT 1"
); );
@@ -54,7 +48,8 @@ if (isset($_GET['ticket_id'])) {
$ticket_prefix = nullable_htmlentities($row['ticket_prefix']); $ticket_prefix = nullable_htmlentities($row['ticket_prefix']);
$ticket_number = intval($row['ticket_number']); $ticket_number = intval($row['ticket_number']);
$ticket_category = nullable_htmlentities($row['ticket_category']); $ticket_category = intval($row['ticket_category']);
$ticket_category_display = htmlentities($row['category_name']);
$ticket_subject = nullable_htmlentities($row['ticket_subject']); $ticket_subject = nullable_htmlentities($row['ticket_subject']);
$ticket_details = $purifier->purify($row['ticket_details']); $ticket_details = $purifier->purify($row['ticket_details']);
$ticket_priority = nullable_htmlentities($row['ticket_priority']); $ticket_priority = nullable_htmlentities($row['ticket_priority']);
@@ -181,7 +176,7 @@ if (isset($_GET['ticket_id'])) {
// Client Tags // Client Tags
$client_tag_name_display_array = array(); $client_tag_name_display_array = array();
$client_tag_id_array = array(); $client_tag_id_array = array();
$sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.client_tag_tag_id = tags.tag_id WHERE client_tags.client_tag_client_id = $client_id ORDER BY tag_name ASC"); $sql_client_tags = mysqli_query($mysqli, "SELECT * FROM client_tags LEFT JOIN tags ON client_tags.tag_id = tags.tag_id WHERE client_id = $client_id ORDER BY tag_name ASC");
while ($row = mysqli_fetch_array($sql_client_tags)) { while ($row = mysqli_fetch_array($sql_client_tags)) {
$client_tag_id = intval($row['tag_id']); $client_tag_id = intval($row['tag_id']);
@@ -206,6 +201,22 @@ if (isset($_GET['ticket_id'])) {
$row = mysqli_fetch_array($ticket_responses_sql); $row = mysqli_fetch_array($ticket_responses_sql);
$ticket_responses = intval($row['ticket_responses']); $ticket_responses = intval($row['ticket_responses']);
$ticket_all_comments_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_all_comments_count FROM ticket_replies WHERE ticket_reply_archived_at IS NULL AND ticket_reply_ticket_id = $ticket_id");
$row = mysqli_fetch_array($ticket_all_comments_sql);
$ticket_all_comments_count = intval($row['ticket_all_comments_count']);
$ticket_internal_notes_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_internal_notes_count FROM ticket_replies WHERE ticket_reply_archived_at IS NULL AND ticket_reply_type = 'Internal' AND ticket_reply_ticket_id = $ticket_id");
$row = mysqli_fetch_array($ticket_internal_notes_sql);
$ticket_internal_notes_count = intval($row['ticket_internal_notes_count']);
$ticket_public_comments_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_public_comments_count FROM ticket_replies WHERE ticket_reply_archived_at IS NULL AND (ticket_reply_type = 'Public' OR ticket_reply_type = 'Client') AND ticket_reply_ticket_id = $ticket_id");
$row = mysqli_fetch_array($ticket_public_comments_sql);
$ticket_public_comments_count = intval($row['ticket_public_comments_count']);
$ticket_events_sql = mysqli_query($mysqli, "SELECT COUNT(ticket_reply_id) AS ticket_events_count FROM ticket_replies WHERE ticket_reply_archived_at IS NULL AND ticket_reply_type = 'Event' AND ticket_reply_ticket_id = $ticket_id");
$row = mysqli_fetch_array($ticket_events_sql);
$ticket_events_count = intval($row['ticket_events_count']);
// Get & format asset warranty expiry // Get & format asset warranty expiry
$date = date('Y-m-d H:i:s'); $date = date('Y-m-d H:i:s');
@@ -371,13 +382,6 @@ if (isset($_GET['ticket_id'])) {
</div> </div>
<?php } <?php }
// Time tracking
if ($ticket_total_reply_time) { ?>
<div class="mt-1">
<i class="far fa-fw fa-clock text-secondary mr-2"></i>Total time worked: <?php echo $ticket_total_reply_time; ?>
</div>
<?php }
// Billable // Billable
if ($config_module_enable_accounting) { ?> if ($config_module_enable_accounting) { ?>
<?php if($invoice_id) { ?> <?php if($invoice_id) { ?>
@@ -404,18 +408,33 @@ if (isset($_GET['ticket_id'])) {
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">
<?php if($task_count) { ?> <?php if ($task_count) { ?>
Tasks Completed<span class="float-right text-bold"><?php echo $tasks_completed_percent; ?>%</span> Tasks Completed<span class="float-right text-bold"><?php echo $tasks_completed_percent; ?>%</span>
<div class="progress mt-2" style="height: 20px;"> <div class="progress mt-2" style="height: 20px;">
<div class="progress-bar" style="width: <?php echo $tasks_completed_percent; ?>%;"><?php echo $completed_task_count; ?> / <?php echo $task_count; ?></div> <div class="progress-bar" style="width: <?php echo $tasks_completed_percent; ?>%;"><?php echo $completed_task_count; ?> / <?php echo $task_count; ?></div>
</div> </div>
<?php } ?> <?php } ?>
<?php if($ticket_collaborators) { ?> <?php
// Time tracking
if ($ticket_total_reply_time) { ?>
<div class="mt-1">
<i class="far fa-fw fa-clock text-secondary mr-2"></i>Total time worked: <?php echo $ticket_total_reply_time; ?>
</div>
<?php } ?>
<?php if ($ticket_collaborators) { ?>
<div class="mt-2"> <div class="mt-2">
<i class="fas fa-fw fa-users mr-2 text-secondary"></i><?php echo $ticket_collaborators; ?> <i class="fas fa-fw fa-users mr-2 text-secondary"></i><?php echo $ticket_collaborators; ?>
</div> </div>
<?php } ?> <?php } ?>
<?php if ($ticket_category > 0) { ?>
<div class="mt-2">
<i class="fas fa-fw fa-layer-group mr-2 text-secondary"></i><?php echo $ticket_category_display; ?>
</div>
<?php } ?>
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">
@@ -451,7 +470,7 @@ if (isset($_GET['ticket_id'])) {
<?php } <?php }
if (empty($ticket_closed_at)) { ?> if (empty($ticket_closed_at)) { ?>
<?php if($task_count == $completed_task_count) { ?> <?php if ($task_count == $completed_task_count) { ?>
<a href="post.php?close_ticket=<?php echo $ticket_id; ?>" class="btn btn-dark btn-sm confirm-link" id="ticket_close"> <a href="post.php?close_ticket=<?php echo $ticket_id; ?>" class="btn btn-dark btn-sm confirm-link" id="ticket_close">
<i class="fas fa-fw fa-gavel mr-2"></i>Close <i class="fas fa-fw fa-gavel mr-2"></i>Close
</a> </a>
@@ -513,28 +532,39 @@ if (isset($_GET['ticket_id'])) {
<!-- Only show ticket reply modal if status is not closed --> <!-- Only show ticket reply modal if status is not closed -->
<?php if (empty($ticket_closed_at)) { ?> <?php if (empty($ticket_closed_at)) { ?>
<form class="mb-3 d-print-none" action="post.php" method="post" autocomplete="off"> <form class="mb-3 d-print-none" action="post.php" method="post" autocomplete="off">
<input type="hidden" name="ticket_id" id="ticket_id" value="<?php echo $ticket_id; ?>"> <input type="hidden" name="ticket_id" id="ticket_id" value="<?php echo $ticket_id; ?>">
<input type="hidden" name="client_id" id="client_id" value="<?php echo $client_id; ?>"> <input type="hidden" name="client_id" id="client_id" value="<?php echo $client_id; ?>">
<div class="form-group"> <div class="form-group">
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<label class="btn btn-light active">
<input type="radio" name="public_reply_type" value="2" checked>Public Comment & Email
</label>
<label class="btn btn-light">
<input type="radio" name="public_reply_type" value="1">Public Comment
</label>
<label class="btn btn-light">
<input type="radio" name="public_reply_type" value="0">Internal Note
</label>
</div>
<?php if ($config_ai_enable) { ?> <?php if ($config_ai_enable) { ?>
<div class="form-group"> <div class="float-right">
<textarea class="form-control tinymceai" id="textInput" name="ticket_reply" placeholder="Type a response"></textarea> <button id="rewordButton" class="btn btn-secondary" type="button"><i class="fas fa-fw fa-robot mr-2"></i>AI Reword</button>
</div> <button id="undoButton" class="btn btn-secondary" type="button" style="display:none;"><i class="fas fa-fw fa-redo-alt mr-2"></i>Undo</button>
</div>
<div class="mb-3">
<button id="rewordButton" class="btn btn-secondary" type="button"><i class="fas fa-fw fa-robot mr-2"></i>AI Reword</button>
<button id="undoButton" class="btn btn-secondary" type="button" style="display:none;"><i class="fas fa-fw fa-redo-alt mr-2"></i>Undo</button>
</div>
<?php } else { ?>
<div class="form-group">
<textarea class="form-control tinymce" name="ticket_reply" placeholder="Type a response"></textarea>
</div>
<?php } ?> <?php } ?>
</div> </div>
<div class="form-group">
<textarea class="form-control tinymce<?php if ($config_ai_enable) { echo "ai"; } ?>" id="textInput" name="ticket_reply" placeholder="Type a response"></textarea>
</div>
<div class="form-row"> <div class="form-row">
<div class="col-md-2"> <div class="col-md-4">
<div class="input-group mb-3"> <div class="input-group mb-3">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-thermometer-half"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-thermometer-half"></i></span>
@@ -554,69 +584,32 @@ if (isset($_GET['ticket_id'])) {
</div> </div>
</div> </div>
<div class="custom-tt-horizontal-spacing"></div> <!-- Add custom class for smaller spacing -->
<!-- Time Tracking --> <!-- Time Tracking -->
<div class="col-sm-3 col-lg-2"> <div class="col-md-6">
<div class="input-group mb-3"> <div class="input-group mb-3">
<div class="form-row"> <div class="input-group pr-0 col-2">
<input type="text" class="form-control" inputmode="numeric" id="hours" name="hours" placeholder="Hrs" min="0" max="23" pattern="0?[0-9]|1[0-9]|2[0-3]">
<div class="input-group custom-tt-width">
<input type="text" class="form-control" inputmode="numeric" id="hours" name="hours" placeholder="Hrs" min="0" max="23" pattern="0?[0-9]|1[0-9]|2[0-3]">
</div>
<div class="input-group custom-tt-width">
<input type="text" class="form-control" inputmode="numeric" id="minutes" name="minutes" placeholder="Mins" min="0" max="59" pattern="[0-5]?[0-9]">
</div>
<div class="input-group custom-tt-width">
<input type="text" class="form-control" inputmode="numeric" id="seconds" name="seconds" placeholder="Secs" min="0" max="59" pattern="[0-5]?[0-9]">
</div>
</div> </div>
<div class="input-group px-0 col-2">
<input type="text" class="form-control" inputmode="numeric" id="minutes" name="minutes" placeholder="Mins" min="0" max="59" pattern="[0-5]?[0-9]">
</div>
<div class="input-group px-0 col-2">
<input type="text" class="form-control" inputmode="numeric" id="seconds" name="seconds" placeholder="Secs" min="0" max="59" pattern="[0-5]?[0-9]">
</div>
<div class="btn-group">
<button type="button" class="btn btn-success" id="startStopTimer"><i class="fas fa-fw fa-pause"></i></button>
<button type="button" class="btn btn-danger" id="resetTimer"><i class="fas fa-fw fa-redo-alt"></i></button>
</div>
</div> </div>
</div> </div>
<!-- Timer Controls -->
<div class="col-sm-2">
<div class="btn-group">
<button type="button" class="btn btn-success" id="startStopTimer"><i class="fas fa-fw fa-pause"></i></button>
<button type="button" class="btn btn-danger" id="resetTimer"><i class="fas fa-fw fa-redo-alt"></i></button>
</div>
</div>
<?php
// Set the initial ticket response type (private/internal note)
// Future updates of the wording/icon are done by Javascript
// Public responses by default (maybe configurable in future?)
$ticket_reply_button_wording = "Respond";
$ticket_reply_button_check = "checked";
$ticket_reply_button_icon = "paper-plane";
// Internal responses by default if 1) the contact email is empty or 2) the contact email matches the agent responding
if (empty($contact_email) || $contact_email == $session_email) {
// Internal
$ticket_reply_button_wording = "Add note";
$ticket_reply_button_check = "";
$ticket_reply_button_icon = "sticky-note";
} ?>
<div class="col-md-2">
<div class="form-group">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="ticket_reply_type_checkbox" name="public_reply_type" value="1" <?php echo $ticket_reply_button_check ?>>
<label class="custom-control-label" for="ticket_reply_type_checkbox">Public Update<br><small class="text-secondary">(Emails contact)</small></label>
</div>
</div>
</div>
<div class="col-md-2"> <div class="col-md-2">
<button type="submit" id="ticket_add_reply" name="add_ticket_reply" class="btn btn-primary text-bold"><i class="fas fa-<?php echo $ticket_reply_button_icon ?> mr-2"></i><?php echo $ticket_reply_button_wording ?></button> <div class="float-right">
<button type="submit" id="ticket_add_reply" name="add_ticket_reply" class="btn btn-primary btn-block text-bold"><i class="fas fa-check mr-2"></i>Submit</button>
</div>
</div> </div>
</div> </div>
@@ -625,7 +618,52 @@ if (isset($_GET['ticket_id'])) {
<!-- End IF for reply modal --> <!-- End IF for reply modal -->
<?php } ?> <?php } ?>
<?php if($ticket_responses) { ?><h5 class="mb-4">Responses (<?php echo $ticket_responses; ?>)</h5><?php } ?> <!-- Ticket Responses -->
<ul class="nav nav-tabs" id="ticketComments">
<li class="nav-item">
<button class="nav-link active" id="all-comments-tab" data-toggle="tab" data-target="#allComments" type="button">
All Comments
<span class="right badge badge-pill badge-dark ml-2"><?php echo $ticket_all_comments_count; ?></span>
</button>
</li>
<li class="nav-item">
<button class="nav-link" id="public-comments-tab" data-toggle="tab" data-target="#publicComments" type="button">
Public
<span class="right badge badge-pill badge-dark ml-2"><?php echo $ticket_public_comments_count; ?></span>
</button>
</li>
<li class="nav-item">
<button class="nav-link" id="notes-tab" data-toggle="tab" data-target="#notes" type="button">
Internal Notes
<span class="right badge badge-pill badge-dark ml-2"><?php echo $ticket_internal_notes_count; ?></span>
</button>
</li>
<li class="nav-item">
<button class="nav-link" id="public-comments-tab" data-toggle="tab" data-target="#publicComments" type="button">
Client Communication
<span class="right badge badge-pill badge-dark ml-2"><?php echo $ticket_public_comments_count; ?></span>
</button>
</li>
<li class="nav-item ml-auto">
<button class="nav-link" id="events-tab" data-toggle="tab" data-target="#events" type="button">
Events
<span class="right badge badge-pill badge-dark ml-2"><?php echo $ticket_responses; ?></span>
</button>
</li>
<li class="nav-item">
<button class="nav-link" id="tasks-tab" data-toggle="tab" data-target="#tasks" type="button">
Tasks
<span class="right badge badge-pill badge-dark ml-2"><?php echo $task_count; ?></span>
</button>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="allComments">All Comments</div>
<div class="tab-pane fade" id="publicComments">Public Comments</div>
<div class="tab-pane fade" id="notes">Internal Notes</div>
<div class="tab-pane fade" id="events">Events</div>
<div class="tab-pane fade" id="tasks">Tasks</div>
</div>
<!-- Ticket replies --> <!-- Ticket replies -->
<?php <?php
@@ -837,7 +875,7 @@ if (isset($_GET['ticket_id'])) {
?> ?>
<tr> <tr>
<td> <td>
<?php if($task_completed_at) { ?> <?php if ($task_completed_at) { ?>
<i class="far fa-fw fa-check-square text-primary"></i> <i class="far fa-fw fa-check-square text-primary"></i>
<?php } else { ?> <?php } else { ?>
<a href="post.php?complete_task=<?php echo $task_id; ?>"> <a href="post.php?complete_task=<?php echo $task_id; ?>">
@@ -1099,7 +1137,6 @@ require_once "footer.php";
<!-- Ticket collision detect JS (jQuery is called in footer, so collision detection script MUST be below it) --> <!-- Ticket collision detect JS (jQuery is called in footer, so collision detection script MUST be below it) -->
<script src="js/ticket_collision_detection.js"></script> <script src="js/ticket_collision_detection.js"></script>
<script src="js/ticket_button_respond_note.js"></script>
<?php } ?> <?php } ?>
<script src="js/pretty_content.js"></script> <script src="js/pretty_content.js"></script>

View File

@@ -8,6 +8,7 @@
</button> </button>
</div> </div>
<form action="post.php" method="post" autocomplete="off"> <form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="billable" value="0">
<div class="modal-body bg-white"> <div class="modal-body bg-white">
<?php if (isset($_GET['client_id'])) { ?> <?php if (isset($_GET['client_id'])) { ?>
@@ -139,6 +140,15 @@
</div> </div>
</div> </div>
<?php if ($config_module_enable_accounting) { ?>
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" name="billable" <?php if ($config_ticket_default_billable == 1) { echo "checked"; } ?> value="1" id="billableSwitch">
<label class="custom-control-label" for="billableSwitch">Mark Billable</label>
</div>
</div>
<?php } ?>
</div> </div>
<?php if (isset($_GET['client_id'])) { ?> <?php if (isset($_GET['client_id'])) { ?>

View File

@@ -12,6 +12,7 @@
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>"> <input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
<input type="hidden" name="ticket_number" value="<?php echo "$ticket_prefix$ticket_number"; ?>"> <input type="hidden" name="ticket_number" value="<?php echo "$ticket_prefix$ticket_number"; ?>">
<input type="hidden" name="contact_notify" value="0"> <!-- Default 0 --> <input type="hidden" name="contact_notify" value="0"> <!-- Default 0 -->
<input type="hidden" name="billable" value="0">
<div class="modal-body bg-white"> <div class="modal-body bg-white">
<ul class="nav nav-pills nav-justified mb-3"> <ul class="nav nav-pills nav-justified mb-3">
@@ -55,37 +56,57 @@
<textarea class="form-control tinymce" rows="8" name="details"><?php echo $ticket_details; ?></textarea> <textarea class="form-control tinymce" rows="8" name="details"><?php echo $ticket_details; ?></textarea>
</div> </div>
<div class="form-group"> <div class="row">
<label>Priority <strong class="text-danger">*</strong></label> <div class="col">
<div class="input-group"> <div class="form-group">
<div class="input-group-prepend"> <label>Priority <strong class="text-danger">*</strong></label>
<span class="input-group-text"><i class="fa fa-fw fa-thermometer-half"></i></span> <div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-thermometer-half"></i></span>
</div>
<select class="form-control select2" name="priority" required>
<option <?php if ($ticket_priority == 'Low') { echo "selected"; } ?> >Low</option>
<option <?php if ($ticket_priority == 'Medium') { echo "selected"; } ?> >Medium</option>
<option <?php if ($ticket_priority == 'High') { echo "selected"; } ?> >High</option>
</select>
</div>
</div>
</div>
<div class="col">
<div class="form-group">
<label>Category</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-layer-group"></i></span>
</div>
<select class="form-control select2" name="category">
<option value="">- Ticket Category -</option>
<?php
$sql_categories = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Ticket' AND categories.category_archived_at IS NULL");
while ($row = mysqli_fetch_array($sql_categories)) {
$category_id = intval($row['category_id']);
$category_name = nullable_htmlentities($row['category_name']);
?>
<option <?php if ($ticket_category == $category_id) {echo "selected";} ?> value="<?php echo $category_id; ?>"><?php echo $category_name; ?></option>
<?php } ?>
</select>
</div>
</div> </div>
<select class="form-control select2" name="priority" required>
<option <?php if ($ticket_priority == 'Low') { echo "selected"; } ?> >Low</option>
<option <?php if ($ticket_priority == 'Medium') { echo "selected"; } ?> >Medium</option>
<option <?php if ($ticket_priority == 'High') { echo "selected"; } ?> >High</option>
</select>
</div> </div>
</div> </div>
<?php if ($config_module_enable_accounting) { <?php if ($config_module_enable_accounting) { ?>
?>
<div class="form-group"> <div class="form-group">
<label>Billable</label> <div class="custom-control custom-switch">
<div class="input-group"> <input type="checkbox" class="custom-control-input" name="billable" <?php if ($ticket_billable == 1) { echo "checked"; } ?> value="1" id="billableSwitch<?php echo $ticket_id; ?>">
<div class="input-group-prepend"> <label class="custom-control-label" for="billableSwitch<?php echo $ticket_id; ?>">Mark Billable</label>
<span class="input-group-text"><i class="fa fa-fw fa-money-bill"></i></span>
</div>
<select class="form-control" name="billable">
<option <?php if ($ticket_billable == 1) { echo "selected"; } ?> value="1">Yes</option>
<option <?php if ($ticket_billable == 0) { echo "selected"; } ?> value="0">No</option>
</select>
</div> </div>
</div> </div>
<?php } ?> <?php } ?>
</div> </div>
<div class="tab-pane fade" id="pills-contacts<?php echo $ticket_id; ?>"> <div class="tab-pane fade" id="pills-contacts<?php echo $ticket_id; ?>">

View File

@@ -284,7 +284,7 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']);
</td> </td>
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ticket_number&order=<?php echo $disp; ?>">Number</a> <th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ticket_number&order=<?php echo $disp; ?>">Number</a>
</th> </th>
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ticket_subject&order=<?php echo $disp; ?>">Subject</a> <th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=ticket_subject&order=<?php echo $disp; ?>">Subject / Tasks</a>
</th> </th>
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=client_name&order=<?php echo $disp; ?>">Client / Contact</a> <th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=client_name&order=<?php echo $disp; ?>">Client / Contact</a>
</th> </th>
@@ -395,6 +395,23 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']);
$ticket_reply_created_at_time_ago = timeAgo($ticket_reply_created_at); $ticket_reply_created_at_time_ago = timeAgo($ticket_reply_created_at);
} }
// Get Tasks
$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
$sql_tasks_completed = mysqli_query($mysqli,
"SELECT * FROM tasks
WHERE task_ticket_id = $ticket_id
AND task_completed_at IS NOT NULL"
);
$completed_task_count = mysqli_num_rows($sql_tasks_completed);
// Tasks Completed Percent
if($task_count) {
$tasks_completed_percent = round(($completed_task_count / $task_count) * 100);
}
?> ?>
<tr class="<?php if(empty($ticket_closed_at) && empty($ticket_updated_at)) { echo "text-bold"; }?> <?php if (empty($ticket_closed_at) && $ticket_reply_type == "Client") { echo "table-warning"; } ?>"> <tr class="<?php if(empty($ticket_closed_at) && empty($ticket_updated_at)) { echo "text-bold"; }?> <?php if (empty($ticket_closed_at) && $ticket_reply_type == "Client") { echo "table-warning"; } ?>">
@@ -418,6 +435,12 @@ $user_active_assigned_tickets = intval($row['total_tickets_assigned']);
<!-- Ticket Subject --> <!-- Ticket Subject -->
<td> <td>
<a href="ticket.php?ticket_id=<?php echo $ticket_id; ?>"><?php echo $ticket_subject; ?></a> <a href="ticket.php?ticket_id=<?php echo $ticket_id; ?>"><?php echo $ticket_subject; ?></a>
<?php if($task_count) { ?>
<div class="progress mt-2" style="height: 20px;">
<div class="progress-bar" style="width: <?php echo $tasks_completed_percent; ?>%;"><?php echo $completed_task_count; ?> / <?php echo $task_count; ?></div>
</div>
<?php } ?>
</td> </td>
<!-- Ticket Contact --> <!-- Ticket Contact -->

View File

@@ -29,18 +29,6 @@
<!-- Right navbar links --> <!-- Right navbar links -->
<ul class="navbar-nav ml-auto"> <ul class="navbar-nav ml-auto">
<?php if ($config_module_enable_ticketing == 1) { ?>
<li class="nav-item">
<a class="nav-link" href="#" data-toggle="modal" data-target="#openTicketsModal">
<i class="fas fa-hourglass-half"></i>
<span class="badge" id="runningTicketsCount">0</span>
</a>
</li>
<?php } ?>
<!-- New Notifications Dropdown --> <!-- New Notifications Dropdown -->
<?php <?php
$sql_notifications = mysqli_query($mysqli, "SELECT * FROM notifications $sql_notifications = mysqli_query($mysqli, "SELECT * FROM notifications
@@ -84,7 +72,7 @@
<small class="text-secondary"><?php echo $notification; ?></small> <small class="text-secondary"><?php echo $notification; ?></small>
</a> </a>
</div> </div>
<?php } ?> <?php } ?>
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
@@ -114,7 +102,7 @@
<?php } ?> <?php } ?>
<!-- End New Notifications Dropdown --> <!-- End New Notifications Dropdown -->
<li class="nav-item dropdown user-menu"> <li class="nav-item dropdown user-menu">
<a href="#" class="nav-link" data-toggle="dropdown"> <a href="#" class="nav-link" data-toggle="dropdown">
<?php if (empty($session_avatar)) { ?> <?php if (empty($session_avatar)) { ?>
@@ -151,7 +139,7 @@
</ul> </ul>
</nav> </nav>
<?php if ($config_module_enable_ticketing == 1) { <?php if ($config_module_enable_ticketing == 1) {
include_once "top_nav_tickets_modal.php"; include_once "top_nav_tickets_modal.php";
} ?> } ?>
<!-- /.navbar --> <!-- /.navbar -->

View File

@@ -1,30 +1,46 @@
<?php <?php
require_once "inc_all_user.php"; require_once "inc_all_user.php";
$row = mysqli_fetch_array(mysqli_query($mysqli, "SELECT user_config_calendar_first_day FROM user_settings WHERE user_id = $session_user_id"));
$user_config_calendar_first_day = intval($row['user_config_calendar_first_day']);
?> ?>
<div class="card card-dark"> <div class="card card-dark">
<div class="card-header py-3"> <div class="card-header py-3">
<h3 class="card-title"><i class="fas fa-fw fa-globe mr-2"></i>Browser Extension</h3> <h3 class="card-title"><i class="fas fa-fw fa-globe mr-2"></i>Preferences</h3>
</div> </div>
<div class="card-body"> <div class="card-body">
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off"> <form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>"> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<div class="form-group">
<label>Calendar starts on<strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-calendar-day"></i></span>
</div>
<select class="form-control select2" name="calendar_first_day" required>
<option <?php if ($user_config_calendar_first_day == '0') { echo "selected"; } ?> value="0" >Sunday</option>
<option <?php if ($user_config_calendar_first_day == '1') { echo "selected"; } ?> value="1" >Monday</option>
</select>
</div>
</div>
<?php if ($session_user_role > 1) { ?> <?php if ($session_user_role > 1) { ?>
<div class="form-group"> <div class="form-group">
<div class="form-check"> <div class="form-check">
<input type="checkbox" class="form-check-input" name="extension" id="extension" value="Yes" <?php if (isset($_COOKIE['user_extension_key'])) {echo "checked";} ?>> <input disabled="disabled" type="checkbox" class="form-check-input" name="extension" id="extension" value="Yes" <?php if (isset($_COOKIE['user_extension_key'])) {echo "checked";} ?>>
<label class="form-check-label" for="extension">Enable Browser Extention?</label> <label class="form-check-label" for="extension">Enable Browser Extention?</label>
<p class="small">Note: You must log out and back in again for these changes take effect.</p> <p class="small">Not currently in use / Note: You must log out and back in again for these changes take effect.</p>
</div> </div>
</div> </div>
<?php } ?> <?php } ?>
<button type="submit" name="edit_your_user_browser_extension" class="btn btn-primary btn-block mt-3"><i class="fas fa-check mr-2"></i>Save</button> <button type="submit" name="edit_your_user_preferences" class="btn btn-primary btn-block mt-3"><i class="fas fa-check mr-2"></i>Save</button>
</form> </form>

View File

@@ -59,10 +59,12 @@ $remember_token_count = mysqli_num_rows($sql_remember_tokens);
if (!empty($session_token)) { if (!empty($session_token)) {
//Generate QR Code based off the generated key // Generate QR Code
print sprintf('<img src="%s"/>', TokenAuth6238::getBarCodeUrl($session_name, ' ', $session_token, $_SERVER['SERVER_NAME'])); $data = "otpauth://totp/ITFlow:$session_email?secret=$session_token";
print "<img src='plugins/barcode/barcode.php?f=png&s=qr&d=$data'>";
echo "<p class='text-secondary'>$session_token</p>"; echo "<p class='text-secondary'>$session_token</p>";
} }
?> ?>