mirror of https://github.com/itflow-org/itflow
Merge branch 'develop' of https://github.com/itflow-org/itflow into develop
This commit is contained in:
commit
169619c9b9
32
CHANGELOG.md
32
CHANGELOG.md
|
|
@ -2,7 +2,37 @@
|
|||
|
||||
This file documents all notable changes made to ITFlow.
|
||||
|
||||
## [25.11] Changelog
|
||||
## [25.11.1] Maint Release
|
||||
|
||||
### Fixes
|
||||
- Fix broken edit Payment Method.
|
||||
- Fix unable to delete Vendor Template.
|
||||
- Fix Mail Queue link in flash alert for testing email and sending a quote.
|
||||
- Add Show Category Type select if not defined.
|
||||
- Add Show Product Type select if not defined.
|
||||
- Fix add ticket watcher.
|
||||
- Fix if Client isn't assigned to a ticket dont show client view.
|
||||
- Fix missing session client id check when paying an invoice from client portal.
|
||||
- Update Composer Webklex-IMAP library dependency symfony/http-foundation from 7.3.3 to 7.3.7 to fix security related issues.
|
||||
- Add back delete Payment provider the database will handle cascade deletes to saved cards, recurring payments and client payment provider reference.
|
||||
- Don't show Client Tickets Breadcrumb if no client is assigned to a ticket.
|
||||
- Don't Show Contact or Assignment Tab in edit ticket if no Client is Assigned.
|
||||
- Don't Show add contact, asset, vendor, watcher if not client is assigned to a ticket.
|
||||
- Don't Show Public Comment & Email if contact email doesn't exist.
|
||||
- Fixed IMAP Test whicn now uses RAW TCP Connection instead of the depracated php-imap extension.
|
||||
- Fix Broken Link in Ticket Updates via Client Portal to agent.
|
||||
|
||||
### Added / Changed
|
||||
- [Feature] Added Asset Tags.
|
||||
- [Feature] Added Quick Add Links to most side bar navs example quickly add a client from sidebar.
|
||||
- Migrate ticket template add to ajax modal.
|
||||
- Add TOTP secret to Client Export PDF in Credential section.
|
||||
- Add UserID on hover in users listing.
|
||||
- Merge ticket now redirects to the new ticket details page.
|
||||
- [Feature] Add Pay via saved card under invoice Listings.
|
||||
- Ticket Related Side Items UI Cleanup to use btn-tool class.
|
||||
|
||||
## [25.11] Stable
|
||||
|
||||
### Deprecation Notice:
|
||||
- **Outdated CRON Scripts**: The following scripts are removed.
|
||||
|
|
|
|||
|
|
@ -140,6 +140,7 @@
|
|||
<?php if ($config_module_enable_itdoc) { ?>
|
||||
<li class="nav-header">TEMPLATES</li>
|
||||
|
||||
<!-- 2025-11-16 JQ - Hide Contracts not yet ready
|
||||
<li class="nav-item">
|
||||
<a href="/admin/contract_template.php" class="nav-link <?php echo (basename($_SERVER['PHP_SELF']) == 'contract_template.php' ? 'active' : ''); ?>">
|
||||
<i class="nav-icon fas fa-file-contract"></i>
|
||||
|
|
@ -149,6 +150,7 @@
|
|||
</p>
|
||||
</a>
|
||||
</li>
|
||||
-->
|
||||
<li class="nav-item">
|
||||
<a href="/admin/project_template.php" class="nav-link <?php echo (in_array(basename($_SERVER['PHP_SELF']), ['project_template.php', 'project_template_details.php']) ? 'active' : ''); ?>">
|
||||
<i class="nav-icon fas fa-project-diagram"></i>
|
||||
|
|
|
|||
|
|
@ -12,11 +12,24 @@ $tag_type = intval($row['tag_type']);
|
|||
$tag_color = nullable_htmlentities($row['tag_color']);
|
||||
$tag_icon = nullable_htmlentities($row['tag_icon']);
|
||||
|
||||
// Generate the HTML form content using output buffering.
|
||||
if ($tag_type == 1) {
|
||||
$tag_type_display = "Client";
|
||||
} elseif ( $tag_type == 2) {
|
||||
$tag_type_display = "Location";
|
||||
} elseif ( $tag_type == 3) {
|
||||
$tag_type_display = "Contact";
|
||||
} elseif ( $tag_type == 4) {
|
||||
$tag_type_display = "Credential";
|
||||
} elseif ( $tag_type == 5) {
|
||||
$tag_type_display = "Asset";
|
||||
} else {
|
||||
$tag_type_display = "Unknown";
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fas fa-fw fa-tag mr-2"></i>Editing tag: <strong><?php echo $tag_name; ?></strong></h5>
|
||||
<h5 class="modal-title"><i class="fas fa-fw fa-tag mr-2"></i><?= $tag_type_display ?> Tag: <strong><?php echo $tag_name; ?></strong></h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
|
|
@ -35,23 +48,6 @@ ob_start();
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Type <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-th"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="type" required>
|
||||
<option value="">- Type -</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>
|
||||
<option value="3" <?php if ($tag_type == 3) { echo "selected"; } ?>>Contact Tag</option>
|
||||
<option value="4" <?php if ($tag_type == 4) { echo "selected"; } ?>>Credential Tag</option>
|
||||
<option value="5" <?php if ($tag_type == 5) { echo "selected"; } ?>>Asset Tag</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Color <strong class="text-danger">*</strong></label>
|
||||
<div class="input-group">
|
||||
|
|
|
|||
|
|
@ -106,12 +106,14 @@ $num_rows = mysqli_num_rows($sql);
|
|||
<i class="fas fa-fw fa-edit mr-2"></i>Edit
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<!-- <a class="dropdown-item text-danger confirm-link" href="post.php?disable_payment_provider=--><?php //echo $provider_id; ?><!--&csrf_token=--><?php //echo $_SESSION['csrf_token'] ?><!--">-->
|
||||
<!-- <i class="fas fa-fw fa-thumbs-down mr-2"></i>Disable-->
|
||||
<!-- </a>-->
|
||||
<!-- <a class="dropdown-item text-danger confirm-link" href="post.php?delete_payment_provider=--><?php //echo $provider_id; ?><!--&csrf_token=--><?php //echo $_SESSION['csrf_token'] ?><!--">-->
|
||||
<!-- <i class="fas fa-fw fa-trash mr-2"></i>Delete-->
|
||||
<!-- </a>-->
|
||||
<a class="dropdown-item text-danger confirm-link" href="post.php?delete_payment_provider=<?= $provider_id ?>&csrf_token=<?= $_SESSION['csrf_token'] ?>">
|
||||
<i class="fas fa-fw fa-trash mr-2"></i><strong>Delete Provider and</strong>
|
||||
<ul class="text-xs">
|
||||
<li>Related Recurring Payments</li>
|
||||
<li>Related Saved cards</li>
|
||||
<li>Client Provider Relations</li>
|
||||
</ul>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
|
|
|||
|
|
@ -101,6 +101,11 @@ if (isset($_GET['delete_payment_provider'])) {
|
|||
|
||||
$provider_id = intval($_GET['delete_payment_provider']);
|
||||
|
||||
// When deleted it cascades deletes
|
||||
// all Recurring paymentes related to payment provider
|
||||
// Delete all Saved Cards related
|
||||
// Delete Client Payment Provider Releation
|
||||
|
||||
$provider_name = sanitizeInput(getFieldById('payment_providers', $provider_id, 'provider_name'));
|
||||
|
||||
// Delete provider
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ if (isset($_GET['delete_saved_payment'])) {
|
|||
|
||||
try {
|
||||
// Initialize stripe
|
||||
require_once 'plugins/stripe-php/init.php';
|
||||
require_once '../plugins/stripe-php/init.php';
|
||||
$stripe = new \Stripe\StripeClient($private_key);
|
||||
|
||||
// Detach PM
|
||||
|
|
@ -56,7 +56,7 @@ if (isset($_GET['delete_saved_payment'])) {
|
|||
|
||||
}
|
||||
|
||||
// Remove payment method from ITFlow
|
||||
// Remove payment method from ITFlow. This will also cascade delete related recurring payments setup
|
||||
mysqli_query($mysqli, "DELETE FROM client_saved_payment_methods WHERE saved_payment_id = $saved_payment_id");
|
||||
|
||||
// SQL Cascade delete will Remove All Associated Auto Payment Methods on recurring invoices in the recurring payments table.
|
||||
|
|
|
|||
|
|
@ -160,27 +160,128 @@ if (isset($_POST['test_email_smtp'])) {
|
|||
}
|
||||
|
||||
if (isset($_POST['test_email_imap'])) {
|
||||
|
||||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
// Setup your IMAP connection parameters
|
||||
$hostname = "{" . $config_imap_host . ":" . $config_imap_port . "/" . $config_imap_encryption . "/novalidate-cert}INBOX";
|
||||
$username = $config_imap_username;
|
||||
$password = $config_imap_password;
|
||||
$host = $config_imap_host;
|
||||
$port = (int) $config_imap_port;
|
||||
$encryption = strtolower(trim($config_imap_encryption)); // e.g. "ssl", "tls", "none"
|
||||
$username = $config_imap_username;
|
||||
$password = $config_imap_password;
|
||||
|
||||
// Build remote socket (implicit SSL vs plain TCP)
|
||||
$transport = 'tcp';
|
||||
if ($encryption === 'ssl') {
|
||||
$transport = 'ssl';
|
||||
}
|
||||
|
||||
$remote_socket = $transport . '://' . $host . ':' . $port;
|
||||
|
||||
// Stream context (you can tighten these if you want strict validation)
|
||||
$contextOptions = [];
|
||||
if (in_array($encryption, ['ssl', 'tls'], true)) {
|
||||
$contextOptions['ssl'] = [
|
||||
'verify_peer' => false,
|
||||
'verify_peer_name' => false,
|
||||
'allow_self_signed' => true,
|
||||
];
|
||||
}
|
||||
|
||||
$context = stream_context_create($contextOptions);
|
||||
|
||||
try {
|
||||
$inbox = @imap_open($hostname, $username, $password);
|
||||
$errno = 0;
|
||||
$errstr = '';
|
||||
|
||||
if ($inbox) {
|
||||
imap_close($inbox);
|
||||
// 10-second timeout, adjust as needed
|
||||
$fp = @stream_socket_client(
|
||||
$remote_socket,
|
||||
$errno,
|
||||
$errstr,
|
||||
10,
|
||||
STREAM_CLIENT_CONNECT,
|
||||
$context
|
||||
);
|
||||
|
||||
if (!$fp) {
|
||||
throw new Exception("Could not connect to IMAP server: [$errno] $errstr");
|
||||
}
|
||||
|
||||
stream_set_timeout($fp, 10);
|
||||
|
||||
// Read server greeting (IMAP servers send something like: * OK Dovecot ready)
|
||||
$greeting = fgets($fp, 1024);
|
||||
if ($greeting === false || strpos($greeting, '* OK') !== 0) {
|
||||
fclose($fp);
|
||||
throw new Exception("Invalid IMAP greeting: " . trim((string) $greeting));
|
||||
}
|
||||
|
||||
// If you really want STARTTLS for "tls" (port 143), you can do it here
|
||||
if ($encryption === 'tls' && stripos($greeting, 'STARTTLS') !== false) {
|
||||
// Request STARTTLS
|
||||
fwrite($fp, "A0001 STARTTLS\r\n");
|
||||
$line = fgets($fp, 1024);
|
||||
if ($line === false || stripos($line, 'A0001 OK') !== 0) {
|
||||
fclose($fp);
|
||||
throw new Exception("STARTTLS failed: " . trim((string) $line));
|
||||
}
|
||||
|
||||
// Enable crypto on the stream
|
||||
if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
|
||||
fclose($fp);
|
||||
throw new Exception("Unable to enable TLS encryption on IMAP connection.");
|
||||
}
|
||||
}
|
||||
|
||||
// --- Do LOGIN command ---
|
||||
$tag = 'A0002';
|
||||
|
||||
// Simple quoting; this may fail with some special chars in username/password.
|
||||
$loginCmd = sprintf(
|
||||
"%s LOGIN \"%s\" \"%s\"\r\n",
|
||||
$tag,
|
||||
addcslashes($username, "\\\""),
|
||||
addcslashes($password, "\\\"")
|
||||
);
|
||||
|
||||
fwrite($fp, $loginCmd);
|
||||
|
||||
$success = false;
|
||||
$errorLine = '';
|
||||
|
||||
while (!feof($fp)) {
|
||||
$line = fgets($fp, 2048);
|
||||
if ($line === false) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Look for tagged response for our LOGIN
|
||||
if (strpos($line, $tag . ' ') === 0) {
|
||||
if (stripos($line, $tag . ' OK') === 0) {
|
||||
$success = true;
|
||||
} else {
|
||||
$errorLine = trim($line);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Always logout / close
|
||||
fwrite($fp, "A0003 LOGOUT\r\n");
|
||||
fclose($fp);
|
||||
|
||||
if ($success) {
|
||||
flash_alert("Connected successfully");
|
||||
} else {
|
||||
throw new Exception(imap_last_error());
|
||||
if (!$errorLine) {
|
||||
$errorLine = 'Unknown IMAP authentication error';
|
||||
}
|
||||
throw new Exception($errorLine);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
flash_alert("<strong>IMAP connection failed:</strong> " . $e->getMessage(), 'error');
|
||||
flash_alert("<strong>IMAP connection failed:</strong> " . htmlspecialchars($e->getMessage()), 'error');
|
||||
}
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ if (isset($_POST['edit_tag'])) {
|
|||
|
||||
$tag_id = intval($_POST['tag_id']);
|
||||
|
||||
mysqli_query($mysqli,"UPDATE tags SET tag_name = '$name', tag_type = $type, tag_color = '$color', tag_icon = '$icon' WHERE tag_id = $tag_id");
|
||||
mysqli_query($mysqli,"UPDATE tags SET tag_name = '$name', tag_color = '$color', tag_icon = '$icon' WHERE tag_id = $tag_id");
|
||||
|
||||
logAction("Tag", "Edit", "$session_name edited tag $name", 0, $tag_id);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,31 @@ $order = "ASC";
|
|||
|
||||
require_once "includes/inc_all_admin.php";
|
||||
|
||||
if (isset($_GET['type'])) {
|
||||
$type_filter = intval($_GET['type']);
|
||||
} else {
|
||||
$type_filter = 1;
|
||||
}
|
||||
|
||||
if ($type_filter == 1) {
|
||||
$tag_type_display = "Client";
|
||||
} elseif ( $type_filter == 2) {
|
||||
$tag_type_display = "Location";
|
||||
} elseif ( $type_filter == 3) {
|
||||
$tag_type_display = "Contact";
|
||||
} elseif ( $type_filter == 4) {
|
||||
$tag_type_display = "Credential";
|
||||
} elseif ( $type_filter == 5) {
|
||||
$tag_type_display = "Asset";
|
||||
} else {
|
||||
$tag_type_display = "Unknown";
|
||||
}
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM tags
|
||||
WHERE tag_name LIKE '%$q%'
|
||||
AND tag_type = $type_filter
|
||||
ORDER BY $sort $order LIMIT $record_from, $record_to"
|
||||
);
|
||||
|
||||
|
|
@ -19,9 +40,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
|
||||
<div class="card card-dark">
|
||||
<div class="card-header py-2">
|
||||
<h3 class="card-title mt-2"><i class="fas fa-fw fa-tags mr-2"></i>Tags</h3>
|
||||
<h3 class="card-title mt-2"><i class="fas fa-fw fa-tags mr-2"></i><?= $tag_type_display ?> Tags</h3>
|
||||
<div class="card-tools">
|
||||
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/tag/tag_add.php"><i class="fas fa-plus mr-2"></i>New Tag</button>
|
||||
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/tag/tag_add.php?type=<?= $type_filter ?>"><i class="fas fa-plus mr-2"></i>New <?= $tag_type_display ?> Tag</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -30,7 +51,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
<div class="col-sm-4 mb-2">
|
||||
<form autocomplete="off">
|
||||
<div class="input-group">
|
||||
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search Tags">
|
||||
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search <?= $tag_type_display ?> Tags">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-primary"><i class="fa fa-search"></i></button>
|
||||
</div>
|
||||
|
|
@ -38,6 +59,45 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
</form>
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<div class="btn-group float-right">
|
||||
<a href="?type=1"
|
||||
class="btn <?php if ($type_filter == 1) {
|
||||
echo 'btn-primary';
|
||||
} else {
|
||||
echo 'btn-default';
|
||||
} ?>">Client</a>
|
||||
<a href="?type=2"
|
||||
class="btn <?php if ($type_filter == 2) {
|
||||
echo 'btn-primary';
|
||||
} else {
|
||||
echo 'btn-default';
|
||||
} ?>">Location</a>
|
||||
<a href="?type=3"
|
||||
class="btn <?php if ($type_filter == 3) {
|
||||
echo 'btn-primary';
|
||||
} else {
|
||||
echo 'btn-default';
|
||||
} ?>">Contact</a>
|
||||
<a href="?type=4"
|
||||
class="btn <?php if ($type_filter == 4) {
|
||||
echo 'btn-primary';
|
||||
} else {
|
||||
echo 'btn-default';
|
||||
} ?>">Credential</a>
|
||||
<a href="?type=5"
|
||||
class="btn <?php if ($type_filter == 5) {
|
||||
echo 'btn-primary';
|
||||
} else {
|
||||
echo 'btn-default';
|
||||
} ?>">Asset</a>
|
||||
<a href="?<?= $url_query_strings_sort ?>&archived=1"
|
||||
class="btn <?php if (isset($_GET['archived'])) {
|
||||
echo 'btn-primary';
|
||||
} else {
|
||||
echo 'btn-default';
|
||||
} ?>"><i
|
||||
class="fas fa-fw fa-archive mr-2"></i>Archived</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -51,11 +111,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
Name <?php if ($sort == 'tag_name') { echo $order_icon; } ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=tag_type&order=<?php echo $disp; ?>">
|
||||
Type <?php if ($sort == 'tag_type') { echo $order_icon; } ?>
|
||||
</a>
|
||||
</th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
|
@ -65,20 +120,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
while ($row = mysqli_fetch_array($sql)) {
|
||||
$tag_id = intval($row['tag_id']);
|
||||
$tag_name = nullable_htmlentities($row['tag_name']);
|
||||
$tag_type = intval($row['tag_type']);
|
||||
if ( $tag_type == 1) {
|
||||
$tag_type_display = "Client Tag";
|
||||
} elseif ( $tag_type == 2) {
|
||||
$tag_type_display = "Location Tag";
|
||||
} elseif ( $tag_type == 3) {
|
||||
$tag_type_display = "Contact Tag";
|
||||
} elseif ( $tag_type == 4) {
|
||||
$tag_type_display = "Credential Tag";
|
||||
} elseif ( $tag_type == 5) {
|
||||
$tag_type_display = "Asset Tag";
|
||||
} else {
|
||||
$tag_type_display = "Unknown Tag";
|
||||
}
|
||||
$tag_color = nullable_htmlentities($row['tag_color']);
|
||||
$tag_icon = nullable_htmlentities($row['tag_icon']);
|
||||
|
||||
|
|
@ -90,7 +131,6 @@ $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>
|
||||
</a>
|
||||
</td>
|
||||
<td><?php echo $tag_type_display; ?></td>
|
||||
<td>
|
||||
<div class="dropdown dropleft text-center">
|
||||
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
|
||||
|
|
@ -119,8 +159,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php require_once "../includes/filter_footer.php";
|
||||
?>
|
||||
<?php require_once "../includes/filter_footer.php"; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -133,9 +133,6 @@ $network_count = intval($row['network_count']);
|
|||
//Other Count
|
||||
$other_count = intval($row['other_count']);
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM assets
|
||||
|
|
|
|||
|
|
@ -744,7 +744,7 @@ if ($user_config_dashboard_technical_enable == 1) {
|
|||
href="ticket.php?ticket_id=<?= "$ticket_id$has_client" ?>"><?= "$ticket_prefix$ticket_number" ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><a href="ticket.php?ticket_id=<?= $ticket_id$has_client" ?>"><?= $ticket_subject ?></a></td>
|
||||
<td><a href="ticket.php?ticket_id=<?= "$ticket_id$has_client" ?>"><?= $ticket_subject ?></a></td>
|
||||
<td><a href="tickets.php?client_id=<?php echo $client_id; ?>"><strong><?php echo $client_name; ?></strong></a></td>
|
||||
<td><?php echo $contact_display; ?></td>
|
||||
<td><span class='p-2 badge badge-pill badge-<?php echo $ticket_priority_color; ?>'><?php echo $ticket_priority; ?></span></td>
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@ if (!empty($q)) {
|
|||
$query_snippet = ""; // empty
|
||||
}
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
// Folder ID
|
||||
$get_folder_id = 0;
|
||||
if (!empty($_GET['folder_id'])) {
|
||||
|
|
|
|||
|
|
@ -14,9 +14,6 @@ if (!empty($_GET['folder_id'])) {
|
|||
$folder_id = 0;
|
||||
}
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
// Folder ID
|
||||
$get_folder_id = 0;
|
||||
if (!empty($_GET['folder_id'])) {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ if (isset($_GET['invoice_id'])) {
|
|||
$mysqli,
|
||||
"SELECT * FROM invoices
|
||||
LEFT JOIN clients ON invoice_client_id = client_id
|
||||
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 contacts ON client_id = contact_client_id AND contact_primary = 1
|
||||
LEFT JOIN locations ON client_id = location_client_id AND location_primary = 1
|
||||
WHERE invoice_id = $invoice_id
|
||||
$access_permission_query
|
||||
LIMIT 1"
|
||||
|
|
|
|||
|
|
@ -344,8 +344,6 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
$recurring_invoice_display = "-";
|
||||
}
|
||||
|
||||
|
||||
|
||||
$now = time();
|
||||
|
||||
if (($invoice_status == "Sent" || $invoice_status == "Partial" || $invoice_status == "Viewed") && strtotime($invoice_due) + 86400 < $now) {
|
||||
|
|
@ -356,6 +354,15 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
|
||||
$invoice_badge_color = getInvoiceBadgeColor($invoice_status);
|
||||
|
||||
// Saved Payment Methods
|
||||
$sql_saved_payment_methods = mysqli_query($mysqli, "
|
||||
SELECT * FROM client_saved_payment_methods
|
||||
LEFT JOIN payment_providers
|
||||
ON client_saved_payment_methods.saved_payment_provider_id = payment_providers.payment_provider_id
|
||||
WHERE saved_payment_client_id = $client_id
|
||||
AND payment_provider_active = 1;
|
||||
");
|
||||
|
||||
?>
|
||||
|
||||
<tr>
|
||||
|
|
@ -395,10 +402,8 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
<i class="fa fa-fw fa-credit-card mr-2"></i>Add Payment
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<?php if ($invoice_status !== 'Partial' && $config_stripe_enable && $stripe_id && $stripe_pm) { ?>
|
||||
<a class="dropdown-item confirm-link" href="post.php?add_payment_stripe&invoice_id=<?php echo $invoice_id; ?>&csrf_token=<?php echo $_SESSION['csrf_token']; ?>">
|
||||
<i class="fa fa-fw fa-credit-card mr-2"></i>Pay via saved card
|
||||
</a>
|
||||
<?php if (mysqli_num_rows($sql_saved_payment_methods) > 0 && ($invoice_status === 'Sent' || $invoice_status === 'Viewed')) { ?>
|
||||
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/payment/payment_saved_method_add.php?id=<?= $invoice_id ?>"><i class="fas fa-fw fa-wallet mr-2"></i>Pay with Saved Card</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ ob_start();
|
|||
|
||||
// Send a POST request to ajax.php as ajax.php with data contact_set_notes=true, contact_id=NUM, notes=NOTES
|
||||
jQuery.post(
|
||||
"../ajax.php",
|
||||
"ajax.php",
|
||||
{
|
||||
asset_set_notes: 'TRUE',
|
||||
asset_id: asset_id,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ ob_start();
|
|||
|
||||
?>
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-clone mr-2"></i>Merge & close <strong><?= $count ?></strong>tickets</h5>
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-clone mr-2"></i>Merge & close <strong><?= $count ?></strong> tickets</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
|
|
@ -75,3 +75,5 @@ ob_start();
|
|||
|
||||
<!-- Ticket merge JS -->
|
||||
<script src="/agent/js/ticket_merge.js"></script>
|
||||
|
||||
<?php require_once '../../../includes/modal_footer.php';
|
||||
|
|
|
|||
|
|
@ -38,33 +38,35 @@ while ($row = mysqli_fetch_array($sql_additional_assets)) {
|
|||
ob_start();
|
||||
?>
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-life-ring mr-2"></i>Editing ticket: <strong><?php echo "$ticket_prefix$ticket_number"; ?></strong> - <?php echo $client_name; ?></h5>
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-life-ring mr-2"></i>Ticket: <strong><?= "$ticket_prefix$ticket_number" ?></strong> - <?= $client_name ?></h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="ticket_id" value="<?php echo $ticket_id; ?>">
|
||||
<input type="hidden" name="ticket_id" value="<?= $ticket_id ?>">
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<?php if ($client_id) { ?>
|
||||
<ul class="nav nav-pills nav-justified mb-3">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="pill" href="#pills-details<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-life-ring mr-2"></i>Details</a>
|
||||
<a class="nav-link active" data-toggle="pill" href="#pills-details"><i class="fa fa-fw fa-life-ring mr-2"></i>Details</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-contacts"><i class="fa fa-fw fa-users mr-2"></i>Contact</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-contacts<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-users mr-2"></i>Contact</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-assignment<?php echo $ticket_id; ?>"><i class="fa fa-fw fa-desktop mr-2"></i>Assignment</a>
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-assignment"><i class="fa fa-fw fa-desktop mr-2"></i>Assignment</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<div class="tab-content" <?php if (lookupUserPermission('module_support') <= 1) { echo 'inert'; } ?>>
|
||||
|
||||
<div class="tab-pane fade show active" id="pills-details<?php echo $ticket_id; ?>">
|
||||
<div class="tab-pane fade show active" id="pills-details">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Subject <strong class="text-danger">*</strong></label>
|
||||
|
|
@ -182,7 +184,9 @@ ob_start();
|
|||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-contacts<?php echo $ticket_id; ?>">
|
||||
<?php if ($client_id) { ?>
|
||||
|
||||
<div class="tab-pane fade" id="pills-contacts">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Contact</label>
|
||||
|
|
@ -236,7 +240,7 @@ ob_start();
|
|||
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-assignment<?php echo $ticket_id; ?>">
|
||||
<div class="tab-pane fade" id="pills-assignment">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Asset</label>
|
||||
|
|
@ -372,7 +376,7 @@ ob_start();
|
|||
while ($row = mysqli_fetch_array($sql_projects)) {
|
||||
$project_id_select = intval($row['project_id']);
|
||||
$project_name_select = nullable_htmlentities($row['project_name']); ?>
|
||||
<option <?php if ($project_id == $project_id_select) { echo "selected"; } ?> value="<?php echo $project_id_select; ?>"><?php echo $project_name_select; ?></option>
|
||||
<option <?php if ($project_id == $project_id_select) { echo "selected"; } ?> value="<?= $project_id_select ?>"><?= $project_name_select ?></option>
|
||||
|
||||
<?php } ?>
|
||||
</select>
|
||||
|
|
@ -380,13 +384,14 @@ ob_start();
|
|||
</div>
|
||||
|
||||
</div>
|
||||
<?php } // End client_id check ?>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="submit" name="edit_ticket" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Save</button>
|
||||
<button type="submit" name="edit_ticket" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Save changes</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -38,9 +38,6 @@ if (isset($_GET['account']) & !empty($_GET['account'])) {
|
|||
$account_filter = '';
|
||||
}
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM payments
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ require_once "includes/inc_all.php";
|
|||
// Perms
|
||||
enforceUserPermission('module_financial');
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM recurring_expenses
|
||||
|
|
|
|||
|
|
@ -9,9 +9,6 @@ require_once "includes/inc_all.php";
|
|||
// Perms
|
||||
enforceUserPermission('module_financial');
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM revenues
|
||||
|
|
|
|||
122
agent/ticket.php
122
agent/ticket.php
|
|
@ -39,7 +39,6 @@ if (isset($_GET['ticket_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"
|
||||
);
|
||||
|
||||
|
|
@ -358,9 +357,11 @@ if (isset($_GET['ticket_id'])) {
|
|||
<li class="breadcrumb-item">
|
||||
<a href="tickets.php">All Tickets</a>
|
||||
</li>
|
||||
<?php if ($client_url) { ?>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="tickets.php?client_id=<?php echo $client_id; ?>"><?= $client_name ?> Tickets</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<li class="breadcrumb-item active"><?php echo "$ticket_prefix$ticket_number";?></li>
|
||||
</ol>
|
||||
|
||||
|
|
@ -415,18 +416,13 @@ if (isset($_GET['ticket_id'])) {
|
|||
<i class="fas fa-fw fa-ellipsis-v"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item ajax-modal" href="#"
|
||||
data-modal-size = "lg"
|
||||
data-modal-url="modals/ticket/ticket_edit.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-edit mr-2"></i>Edit
|
||||
</a>
|
||||
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_summary.php?ticket_id=<?= $ticket_id ?>" data-modal-size="lg">
|
||||
<i class="fas fa-fw fa-lightbulb mr-2"></i>Summarize
|
||||
</a>
|
||||
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_merge.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-clone mr-2"></i>Merge
|
||||
</a>
|
||||
<?php if (empty($ticket_closed_at)) { ?>
|
||||
<?php if (empty($ticket_closed_at) && $client_id) { ?>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item ajax-modal" href="#"
|
||||
data-modal-url="modals/ticket/ticket_contact.php?id=<?= $ticket_id ?>">
|
||||
|
|
@ -564,9 +560,14 @@ if (isset($_GET['ticket_id'])) {
|
|||
<div class="card card-dark mb-3">
|
||||
|
||||
<div class="card-header bg-dark">
|
||||
<h3 class="card-title">
|
||||
<h5 class="card-title">
|
||||
Ticket Details
|
||||
</h3>
|
||||
</h5>
|
||||
<?php if (empty($ticket_closed_at)) { ?>
|
||||
<div class="card-tools">
|
||||
<button type="button" class="btn btn-tool ajax-modal" data-modal-url="modals/ticket/ticket_edit.php?id=<?= $ticket_id ?>" data-modal-size="lg"><i class="fas fa-edit"></i></button>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<div class="card-body prettyContent" id="ticketDetails">
|
||||
|
|
@ -599,9 +600,11 @@ if (isset($_GET['ticket_id'])) {
|
|||
<label class="btn btn-outline-dark active">
|
||||
<input type="radio" name="public_reply_type" value="0" checked>Internal Note
|
||||
</label>
|
||||
<?php if ($contact_email) { ?>
|
||||
<label class="btn btn-outline-info">
|
||||
<input type="radio" name="public_reply_type" value="2">Public Comment & Email
|
||||
</label>
|
||||
<?php } ?>
|
||||
<label class="btn btn-outline-info">
|
||||
<input type="radio" name="public_reply_type" value="1">Public Comment
|
||||
</label>
|
||||
|
|
@ -807,16 +810,17 @@ if (isset($_GET['ticket_id'])) {
|
|||
<div class="col-md-3">
|
||||
|
||||
<!-- Ticket details right card -->
|
||||
<div class="card">
|
||||
<div class="card <?php if(!$ticket_resolved_at) { echo "collapsed-card"; } ?>">
|
||||
<div class="card-header">
|
||||
<a class="text-reset text-decoration-none" href="#" data-toggle="collapse" data-target="#ticketDetailsCard">
|
||||
<h5 class="card-title mt-1"><i class="fas fa-fw fa-life-ring mr-2"></i>Ticket Details</h5>
|
||||
</a>
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-life-ring mr-2"></i>Ticket Details</h5>
|
||||
|
||||
<div class="card-tools">
|
||||
<a class="fa fa-chevron-down" href="#" data-toggle="collapse" data-target="#ticketDetailsCard"></a>
|
||||
<button type="button" class="btn btn-tool" data-card-widget="collapse">
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body collapse <?php echo !empty($ticket_resolved_at) ? 'show' : ''; ?>" id="ticketDetailsCard">
|
||||
<div class="card-body">
|
||||
|
||||
<!-- Created -->
|
||||
<div title="<?php echo $ticket_created_at; ?>">
|
||||
|
|
@ -912,12 +916,12 @@ if (isset($_GET['ticket_id'])) {
|
|||
<!-- Tasks Card -->
|
||||
<?php if (empty($ticket_resolved_at) || (!empty($ticket_resolved_at) && $task_count > 0)) { ?>
|
||||
<div class="card">
|
||||
<div class="card-header py-2">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-tasks mr-2 mt-2"></i>Tasks</h5>
|
||||
<div class="card-header">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-tasks mr-2"></i>Tasks</h5>
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<div class="card-tools">
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<div class="dropdown dropleft text-center">
|
||||
<button class="btn btn-light text-secondary btn-sm" type="button" data-toggle="dropdown">
|
||||
<button class="btn btn-tool" type="button" data-toggle="dropdown">
|
||||
<i class="fas fa-ellipsis-v"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
|
|
@ -934,8 +938,8 @@ if (isset($_GET['ticket_id'])) {
|
|||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
|
||||
|
|
@ -964,7 +968,7 @@ if (isset($_GET['ticket_id'])) {
|
|||
$task_completion_estimate = intval($row['task_completion_estimate']);
|
||||
$task_completed_at = nullable_htmlentities($row['task_completed_at']);
|
||||
?>
|
||||
<tr data-task-id="<?php echo $task_id; ?>">
|
||||
<tr data-task-id="<?= $task_id ?>">
|
||||
<td>
|
||||
<?php if ($task_completed_at) { ?>
|
||||
<i class="far fa-check-square text-success"></i>
|
||||
|
|
@ -1022,16 +1026,16 @@ if (isset($_GET['ticket_id'])) {
|
|||
<!-- Contact card -->
|
||||
<?php if ($contact_id) { ?>
|
||||
<div class="card">
|
||||
<div class="card-header py-2">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-user-check mr-2 mt-2"></i>Contact</h5>
|
||||
<div class="card-header">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-user-check mr-2"></i>Contact</h5>
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<div class="card-tools">
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#"
|
||||
data-modal-url="modals/ticket/ticket_contact.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
<?php } ?>
|
||||
<a class="btn btn-tool ajax-modal" href="#"
|
||||
data-modal-url="modals/ticket/ticket_contact.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
|
|
@ -1073,23 +1077,19 @@ if (isset($_GET['ticket_id'])) {
|
|||
<?php } ?>
|
||||
<!-- End contact card -->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Ticket watchers card -->
|
||||
<?php if (empty($ticket_closed_at) && mysqli_num_rows($sql_ticket_watchers) > 0) { ?>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header py-2">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-eye mr-2 mt-2"></i>Watchers</h5>
|
||||
<div class="card-header">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-eye mr-2"></i>Watchers</h5>
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<div class="card-tools">
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_add_watcher.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-plus"></i>
|
||||
</a>
|
||||
<?php } ?>
|
||||
<a class="btn btn-tool ajax-modal" href="#" data-modal-url="modals/ticket/ticket_add_watcher.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-plus"></i>
|
||||
</a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
|
|
@ -1117,15 +1117,15 @@ if (isset($_GET['ticket_id'])) {
|
|||
<!-- Asset card -->
|
||||
<?php if ($asset_id) { ?>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header py-2">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-desktop mr-2 mt-2"></i>Assets</h5>
|
||||
<div class="card-header">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-desktop mr-2"></i>Assets</h5>
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<div class="card-tools">
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_asset.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-edit"></i>
|
||||
</a>
|
||||
<?php } ?>
|
||||
<a class="btn btn-tool ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_asset.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-edit"></i>
|
||||
</a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
|
|
@ -1165,15 +1165,15 @@ if (isset($_GET['ticket_id'])) {
|
|||
<!-- Vendor card -->
|
||||
<?php if ($vendor_id) { ?>
|
||||
<div class="card mb-3">
|
||||
<div class="card-header py-2">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-building mr-2 mt-2"></i>Vendor</h5>
|
||||
<div class="card-header">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-building mr-2"></i>Vendor</h5>
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<div class="card-tools">
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_vendor.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-edit"></i>
|
||||
</a>
|
||||
<?php } ?>
|
||||
<a class="btn btn-tool ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_vendor.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-edit"></i>
|
||||
</a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
|
|
@ -1220,15 +1220,15 @@ if (isset($_GET['ticket_id'])) {
|
|||
<!-- project card -->
|
||||
<?php if ($project_id) { ?>
|
||||
<div class="card">
|
||||
<div class="card-header py-2">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-project-diagram mr-2 mt-2"></i>Project</h5>
|
||||
<div class="card-header">
|
||||
<h5 class="card-title"><i class="fas fa-fw fa-project-diagram mr-2"></i>Project</h5>
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<div class="card-tools">
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<button type="button" class="btn btn-light text-secondary btn-sm ajax-modal" data-modal-url="modals/ticket/ticket_edit_project.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<?php } ?>
|
||||
<button type="button" class="btn btn-tool ajax-modal" data-modal-url="modals/ticket/ticket_edit_project.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -28,10 +28,6 @@ if (isset($_GET['account_to']) & !empty($_GET['account_to'])) {
|
|||
$account_to_filter = '';
|
||||
}
|
||||
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS transfer_created_at, expense_date AS transfer_date, expense_amount AS transfer_amount, expense_account_id AS transfer_account_from, revenue_account_id AS transfer_account_to, transfer_expense_id, transfer_revenue_id , transfer_id, transfer_method, transfer_notes FROM transfers, expenses, revenues
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ if (isset($_GET['client_id'])) {
|
|||
$client_url = '';
|
||||
}
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM trips
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ if (isset($_POST['add_ticket'])) {
|
|||
$details = removeEmoji($details);
|
||||
|
||||
$email_subject = "ITFlow - New Ticket - $client_name: $subject";
|
||||
$email_body = "Hello, <br><br>This is a notification that a new ticket has been raised in ITFlow. <br>Client: $client_name<br>Priority: $priority<br>Link: https://$config_base_url/ticket.php?ticket_id=$ticket_id <br><br><b>$subject</b><br>$details";
|
||||
$email_body = "Hello, <br><br>This is a notification that a new ticket has been raised in ITFlow. <br>Client: $client_name<br>Priority: $priority<br>Link: https://$config_base_url/agent/ticket.php?ticket_id=$ticket_id&client_id=$session_client_id <br><br><b>$subject</b><br>$details";
|
||||
|
||||
// Queue Mail
|
||||
$data = [
|
||||
|
|
@ -113,7 +113,7 @@ if (isset($_POST['add_ticket_comment'])) {
|
|||
$tech_name = sanitizeInput($tech_details['user_name']);
|
||||
|
||||
$subject = "$config_app_name Ticket updated - [$config_ticket_prefix$ticket_number] $ticket_subject";
|
||||
$body = "Hello $tech_name,<br><br>A new reply has been added to the below ticket, check ITFlow for full details.<br><br>Client: $client_name<br>Ticket: $config_ticket_prefix$ticket_number<br>Subject: $ticket_subject<br><br>https://$config_base_url/ticket.php?ticket_id=$ticket_id";
|
||||
$body = "Hello $tech_name,<br><br>A new reply has been added to the below ticket, check ITFlow for full details.<br><br>Client: $client_name<br>Ticket: $config_ticket_prefix$ticket_number<br>Subject: $ticket_subject<br><br>https://$config_base_url/agent/ticket.php?ticket_id=$ticket_id&client_id=$session_client_id";
|
||||
|
||||
$data = [
|
||||
[
|
||||
|
|
@ -440,7 +440,7 @@ if (isset($_GET['add_payment_by_provider'])) {
|
|||
$sql = mysqli_query($mysqli,"SELECT * FROM invoices
|
||||
LEFT JOIN clients ON invoice_client_id = client_id
|
||||
LEFT JOIN contacts ON client_id = contact_client_id AND contact_primary = 1
|
||||
WHERE invoice_id = $invoice_id"
|
||||
WHERE invoice_id = $invoice_id AND client_id = $session_client_id"
|
||||
);
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$invoice_number = intval($row['invoice_number']);
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@
|
|||
* Update this file each time we merge develop into master. Format is YY.MM (add a .v if there is more than one release a month.
|
||||
*/
|
||||
|
||||
DEFINE("APP_VERSION", "25.11");
|
||||
DEFINE("APP_VERSION", "25.11.1");
|
||||
|
|
|
|||
|
|
@ -893,16 +893,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v7.3.3",
|
||||
"version": "v7.3.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00"
|
||||
"reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00",
|
||||
"reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/db488a62f98f7a81d5746f05eea63a74e55bb7c4",
|
||||
"reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -952,7 +952,7 @@
|
|||
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.3.3"
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.3.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -972,7 +972,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-08-20T08:04:18+00:00"
|
||||
"time": "2025-11-08T16:41:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ $baseDir = dirname($vendorDir);
|
|||
return array(
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',
|
||||
'606a39d89246991a373564698c2d8383' => $vendorDir . '/symfony/polyfill-php85/bootstrap.php',
|
||||
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
|
||||
'606a39d89246991a373564698c2d8383' => $vendorDir . '/symfony/polyfill-php85/bootstrap.php',
|
||||
'2203a247e6fda86070a5e4e07aed533a' => $vendorDir . '/symfony/clock/Resources/now.php',
|
||||
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
|
||||
'9d2b9fc6db0f153a0a149fefb182415e' => $vendorDir . '/symfony/polyfill-php84/bootstrap.php',
|
||||
'a1105708a18b76903365ca1c4aa61b02' => $vendorDir . '/symfony/translation/Resources/functions.php',
|
||||
'23f09fe3194f8c2f70923f90d6702129' => $vendorDir . '/illuminate/collections/functions.php',
|
||||
'60799491728b879e74601d83e38b2cad' => $vendorDir . '/illuminate/collections/helpers.php',
|
||||
'f625ee536139dfb962a398b200bdb2bd' => $vendorDir . '/illuminate/support/functions.php',
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ return array(
|
|||
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
|
||||
'Psr\\Container\\' => array($vendorDir . '/psr/container/src'),
|
||||
'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'),
|
||||
'Illuminate\\Support\\' => array($vendorDir . '/illuminate/macroable', $vendorDir . '/illuminate/conditionable', $vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/support'),
|
||||
'Illuminate\\Support\\' => array($vendorDir . '/illuminate/collections', $vendorDir . '/illuminate/conditionable', $vendorDir . '/illuminate/macroable', $vendorDir . '/illuminate/support'),
|
||||
'Illuminate\\Pagination\\' => array($vendorDir . '/illuminate/pagination'),
|
||||
'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'),
|
||||
'Doctrine\\Inflector\\' => array($vendorDir . '/doctrine/inflector/src'),
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ class ComposerStaticInit9b9826e5b5cc7806cd328c4112cca75e
|
|||
public static $files = array (
|
||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||
'662a729f963d39afe703c9d9b7ab4a8c' => __DIR__ . '/..' . '/symfony/polyfill-php83/bootstrap.php',
|
||||
'606a39d89246991a373564698c2d8383' => __DIR__ . '/..' . '/symfony/polyfill-php85/bootstrap.php',
|
||||
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
|
||||
'606a39d89246991a373564698c2d8383' => __DIR__ . '/..' . '/symfony/polyfill-php85/bootstrap.php',
|
||||
'2203a247e6fda86070a5e4e07aed533a' => __DIR__ . '/..' . '/symfony/clock/Resources/now.php',
|
||||
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
|
||||
'9d2b9fc6db0f153a0a149fefb182415e' => __DIR__ . '/..' . '/symfony/polyfill-php84/bootstrap.php',
|
||||
'a1105708a18b76903365ca1c4aa61b02' => __DIR__ . '/..' . '/symfony/translation/Resources/functions.php',
|
||||
'23f09fe3194f8c2f70923f90d6702129' => __DIR__ . '/..' . '/illuminate/collections/functions.php',
|
||||
'60799491728b879e74601d83e38b2cad' => __DIR__ . '/..' . '/illuminate/collections/helpers.php',
|
||||
'f625ee536139dfb962a398b200bdb2bd' => __DIR__ . '/..' . '/illuminate/support/functions.php',
|
||||
|
|
@ -118,9 +118,9 @@ class ComposerStaticInit9b9826e5b5cc7806cd328c4112cca75e
|
|||
),
|
||||
'Illuminate\\Support\\' =>
|
||||
array (
|
||||
0 => __DIR__ . '/..' . '/illuminate/macroable',
|
||||
0 => __DIR__ . '/..' . '/illuminate/collections',
|
||||
1 => __DIR__ . '/..' . '/illuminate/conditionable',
|
||||
2 => __DIR__ . '/..' . '/illuminate/collections',
|
||||
2 => __DIR__ . '/..' . '/illuminate/macroable',
|
||||
3 => __DIR__ . '/..' . '/illuminate/support',
|
||||
),
|
||||
'Illuminate\\Pagination\\' =>
|
||||
|
|
|
|||
|
|
@ -929,17 +929,17 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/http-foundation",
|
||||
"version": "v7.3.3",
|
||||
"version_normalized": "7.3.3.0",
|
||||
"version": "v7.3.7",
|
||||
"version_normalized": "7.3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-foundation.git",
|
||||
"reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00"
|
||||
"reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00",
|
||||
"reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00",
|
||||
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/db488a62f98f7a81d5746f05eea63a74e55bb7c4",
|
||||
"reference": "db488a62f98f7a81d5746f05eea63a74e55bb7c4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -963,7 +963,7 @@
|
|||
"symfony/mime": "^6.4|^7.0",
|
||||
"symfony/rate-limiter": "^6.4|^7.0"
|
||||
},
|
||||
"time": "2025-08-20T08:04:18+00:00",
|
||||
"time": "2025-11-08T16:41:12+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
|
@ -991,7 +991,7 @@
|
|||
"description": "Defines an object-oriented layer for the HTTP specification",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.3.3"
|
||||
"source": "https://github.com/symfony/http-foundation/tree/v7.3.7"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'reference' => '981fb9585d0c76e8b9c31812d58dfdd5b56d6454',
|
||||
'reference' => '612041635d962d37f2f400ba1974bec5456ccd1e',
|
||||
'name' => '__root__',
|
||||
'dev' => true,
|
||||
),
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'reference' => '981fb9585d0c76e8b9c31812d58dfdd5b56d6454',
|
||||
'reference' => '612041635d962d37f2f400ba1974bec5456ccd1e',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'carbonphp/carbon-doctrine-types' => array(
|
||||
|
|
@ -158,12 +158,12 @@
|
|||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/http-foundation' => array(
|
||||
'pretty_version' => 'v7.3.3',
|
||||
'version' => '7.3.3.0',
|
||||
'pretty_version' => 'v7.3.7',
|
||||
'version' => '7.3.7.0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../symfony/http-foundation',
|
||||
'aliases' => array(),
|
||||
'reference' => '7475561ec27020196c49bb7c4f178d33d7d3dc00',
|
||||
'reference' => 'db488a62f98f7a81d5746f05eea63a74e55bb7c4',
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'symfony/polyfill-mbstring' => array(
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ class BinaryFileResponse extends Response
|
|||
for ($i = 0, $filenameLength = mb_strlen($filename, $encoding); $i < $filenameLength; ++$i) {
|
||||
$char = mb_substr($filename, $i, 1, $encoding);
|
||||
|
||||
if ('%' === $char || \ord($char) < 32 || \ord($char) > 126) {
|
||||
if ('%' === $char || \ord($char[0]) < 32 || \ord($char[0]) > 126) {
|
||||
$filenameFallback .= '_';
|
||||
} else {
|
||||
$filenameFallback .= $char;
|
||||
|
|
|
|||
|
|
@ -300,10 +300,21 @@ class Request
|
|||
$server['PATH_INFO'] = '';
|
||||
$server['REQUEST_METHOD'] = strtoupper($method);
|
||||
|
||||
if (($i = strcspn($uri, ':/?#')) && ':' === ($uri[$i] ?? null) && (strspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-.') !== $i || strcspn($uri, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'))) {
|
||||
throw new BadRequestException('Invalid URI: Scheme is malformed.');
|
||||
}
|
||||
if (false === $components = parse_url(\strlen($uri) !== strcspn($uri, '?#') ? $uri : $uri.'#')) {
|
||||
throw new BadRequestException('Invalid URI.');
|
||||
}
|
||||
|
||||
$part = ($components['user'] ?? '').':'.($components['pass'] ?? '');
|
||||
|
||||
if (':' !== $part && \strlen($part) !== strcspn($part, '[]')) {
|
||||
throw new BadRequestException('Invalid URI: Userinfo is malformed.');
|
||||
}
|
||||
if (($part = $components['host'] ?? '') && !self::isHostValid($part)) {
|
||||
throw new BadRequestException('Invalid URI: Host is malformed.');
|
||||
}
|
||||
if (false !== ($i = strpos($uri, '\\')) && $i < strcspn($uri, '?#')) {
|
||||
throw new BadRequestException('Invalid URI: A URI cannot contain a backslash.');
|
||||
}
|
||||
|
|
@ -1091,10 +1102,8 @@ class Request
|
|||
// host is lowercase as per RFC 952/2181
|
||||
$host = strtolower(preg_replace('/:\d+$/', '', trim($host)));
|
||||
|
||||
// as the host can come from the user (HTTP_HOST and depending on the configuration, SERVER_NAME too can come from the user)
|
||||
// check that it does not contain forbidden characters (see RFC 952 and RFC 2181)
|
||||
// use preg_replace() instead of preg_match() to prevent DoS attacks with long host names
|
||||
if ($host && '' !== preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $host)) {
|
||||
// the host can come from the user (HTTP_HOST and depending on the configuration, SERVER_NAME too can come from the user)
|
||||
if ($host && !self::isHostValid($host)) {
|
||||
if (!$this->isHostValid) {
|
||||
return '';
|
||||
}
|
||||
|
|
@ -1236,15 +1245,22 @@ class Request
|
|||
static::initializeFormats();
|
||||
}
|
||||
|
||||
$exactFormat = null;
|
||||
$canonicalFormat = null;
|
||||
|
||||
foreach (static::$formats as $format => $mimeTypes) {
|
||||
if (\in_array($mimeType, (array) $mimeTypes, true)) {
|
||||
return $format;
|
||||
if (\in_array($mimeType, $mimeTypes, true)) {
|
||||
$exactFormat = $format;
|
||||
}
|
||||
if (null !== $canonicalMimeType && \in_array($canonicalMimeType, (array) $mimeTypes, true)) {
|
||||
return $format;
|
||||
if (null !== $canonicalMimeType && \in_array($canonicalMimeType, $mimeTypes, true)) {
|
||||
$canonicalFormat = $format;
|
||||
}
|
||||
}
|
||||
|
||||
if ($format = $exactFormat ?? $canonicalFormat) {
|
||||
return $format;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -1259,7 +1275,7 @@ class Request
|
|||
static::initializeFormats();
|
||||
}
|
||||
|
||||
static::$formats[$format] = \is_array($mimeTypes) ? $mimeTypes : [$mimeTypes];
|
||||
static::$formats[$format ?? ''] = (array) $mimeTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1892,9 +1908,8 @@ class Request
|
|||
}
|
||||
|
||||
$pathInfo = substr($requestUri, \strlen($baseUrl));
|
||||
if ('' === $pathInfo) {
|
||||
// If substr() returns false then PATH_INFO is set to an empty string
|
||||
return '/';
|
||||
if ('' === $pathInfo || '/' !== $pathInfo[0]) {
|
||||
return '/'.$pathInfo;
|
||||
}
|
||||
|
||||
return $pathInfo;
|
||||
|
|
@ -2101,4 +2116,21 @@ class Request
|
|||
|
||||
return $this->isIisRewrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* See https://url.spec.whatwg.org/.
|
||||
*/
|
||||
private static function isHostValid(string $host): bool
|
||||
{
|
||||
if ('[' === $host[0]) {
|
||||
return ']' === $host[-1] && filter_var(substr($host, 1, -1), \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6);
|
||||
}
|
||||
|
||||
if (preg_match('/\.[0-9]++\.?$/D', $host)) {
|
||||
return null !== filter_var($host, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4 | \FILTER_NULL_ON_FAILURE);
|
||||
}
|
||||
|
||||
// use preg_replace() instead of preg_match() to prevent DoS attacks with long host names
|
||||
return '' === preg_replace('/[-a-zA-Z0-9_]++\.?/', '', $host);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ class ResponseHeaderBag extends HeaderBag
|
|||
|
||||
public function setCookie(Cookie $cookie): void
|
||||
{
|
||||
$this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie;
|
||||
$this->cookies[$cookie->getDomain() ?? ''][$cookie->getPath()][$cookie->getName()] = $cookie;
|
||||
$this->headerNames['set-cookie'] = 'Set-Cookie';
|
||||
}
|
||||
|
||||
|
|
@ -170,13 +170,13 @@ class ResponseHeaderBag extends HeaderBag
|
|||
{
|
||||
$path ??= '/';
|
||||
|
||||
unset($this->cookies[$domain][$path][$name]);
|
||||
unset($this->cookies[$domain ?? ''][$path][$name]);
|
||||
|
||||
if (empty($this->cookies[$domain][$path])) {
|
||||
unset($this->cookies[$domain][$path]);
|
||||
if (empty($this->cookies[$domain ?? ''][$path])) {
|
||||
unset($this->cookies[$domain ?? ''][$path]);
|
||||
|
||||
if (empty($this->cookies[$domain])) {
|
||||
unset($this->cookies[$domain]);
|
||||
if (empty($this->cookies[$domain ?? ''])) {
|
||||
unset($this->cookies[$domain ?? '']);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -132,14 +132,12 @@ class ServerEvent implements \IteratorAggregate
|
|||
}
|
||||
yield $head;
|
||||
|
||||
if ($this->data) {
|
||||
if (is_iterable($this->data)) {
|
||||
foreach ($this->data as $data) {
|
||||
yield \sprintf('data: %s', $data)."\n";
|
||||
}
|
||||
} else {
|
||||
yield \sprintf('data: %s', $this->data)."\n";
|
||||
if (is_iterable($this->data)) {
|
||||
foreach ($this->data as $data) {
|
||||
yield \sprintf('data: %s', $data)."\n";
|
||||
}
|
||||
} elseif ('' !== $this->data) {
|
||||
yield \sprintf('data: %s', $this->data)."\n";
|
||||
}
|
||||
|
||||
yield "\n";
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ class PdoSessionHandler extends AbstractSessionHandler
|
|||
$table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true);
|
||||
break;
|
||||
case 'sqlsrv':
|
||||
$table->addColumn($this->idCol, Types::TEXT)->setLength(128)->setNotnull(true);
|
||||
$table->addColumn($this->idCol, Types::STRING)->setLength(128)->setNotnull(true);
|
||||
$table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true);
|
||||
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
|
||||
$table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue