Merge branch 'master' into techbar
This commit is contained in:
2
.github/workflows/php-lint.yml
vendored
2
.github/workflows/php-lint.yml
vendored
@@ -12,4 +12,4 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Check PHP syntax errors
|
||||
uses: overtrue/phplint@4.1.0
|
||||
uses: overtrue/phplint@9.4.1
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
$key = randomString(156);
|
||||
$decryptPW = randomString(160);
|
||||
?>
|
||||
<div class="modal" id="addApiKeyModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
@@ -13,64 +14,103 @@ $key = randomString(156);
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<div class="modal-body bg-white">
|
||||
|
||||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
|
||||
<input type="hidden" name="key" value="<?php echo $key ?>">
|
||||
|
||||
<div class="form-group">
|
||||
<label>API Key <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-key"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" value="<?php echo $key ?>" required disabled>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-default clipboardjs" type="button" data-clipboard-text="<?php echo $key; ?>"><i class="fa fa-fw fa-copy"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-pills nav-justified mb-3">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="pill" href="#pills-api-details">Details</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-api-keys">Keys</a>
|
||||
</li>
|
||||
</ul>
|
||||
<hr>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Name <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-sticky-note"></i></span>
|
||||
<div class="tab-content">
|
||||
|
||||
<div class="tab-pane fade show active" id="pills-api-details">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
|
||||
<input type="hidden" name="key" value="<?php echo $key ?>">
|
||||
<input type="hidden" name="password" value="<?php echo $decryptPW ?>">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Name <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-sticky-note"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="name" placeholder="Key Name" required autofocus>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Expiration Date <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"></i></span>
|
||||
</div>
|
||||
<input type="date" class="form-control" name="expire" min="<?php echo date('Y-m-d')?>" max="2999-12-31" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Client Access <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-user"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="client" required>
|
||||
<option value="0"> ALL CLIENTS </option>
|
||||
<?php
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM clients ORDER BY client_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
$client_id = intval($row['client_id']);
|
||||
$client_name = nullable_htmlentities($row['client_name']); ?>
|
||||
<option value="<?php echo $client_id; ?>"><?php echo "$client_name (Client ID: $client_id)"; ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="name" placeholder="Key Name" required autofocus>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="pills-api-keys">
|
||||
<div class="form-group">
|
||||
<label>API Key <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-key"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" value="<?php echo $key ?>" required disabled>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-default clipboardjs" type="button" data-clipboard-text="<?php echo $key; ?>"><i class="fa fa-fw fa-copy"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Login credential decryption password <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-unlock-alt"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" value="<?php echo $decryptPW ?>" required disabled>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-default clipboardjs" type="button" data-clipboard-text="<?php echo $decryptPW; ?>"><i class="fa fa-fw fa-copy"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<label>I have made a copy of the key(s)<strong class="text-danger">*</strong></label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<input type="checkbox" name="ack" value="1" required>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Expiration Date <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"></i></span>
|
||||
</div>
|
||||
<input type="date" class="form-control" name="expire" min="<?php echo date('Y-m-d')?>" max="2999-12-31" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Client Access <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-user"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="client" required>
|
||||
<option value="0"> ALL CLIENTS </option>
|
||||
<?php
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM clients ORDER BY client_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
$client_id = intval($row['client_id']);
|
||||
$client_name = nullable_htmlentities($row['client_name']); ?>
|
||||
<option value="<?php echo $client_id; ?>"><?php echo "$client_name (Client ID: $client_id)"; ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer bg-white">
|
||||
<button type="submit" name="add_api_key" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
|
||||
|
||||
@@ -186,7 +186,7 @@ $loadedModules = get_loaded_extensions();
|
||||
|
||||
//Get Server Info / Service versions
|
||||
$phpVersion = phpversion();
|
||||
$mysqlVersion = $mysqli->server_version;
|
||||
$databaseInfo = mysqli_get_server_info($mysqli) . " / " . $mysqli->server_version;
|
||||
$operatingSystem = php_uname();
|
||||
$webServer = $_SERVER['SERVER_SOFTWARE'];
|
||||
$errorLog = ini_get('error_log') ?: "Debian/Ubuntu default is usually /var/log/apache2/error.log";
|
||||
@@ -204,7 +204,7 @@ $updates = fetchUpdates();
|
||||
|
||||
<?php
|
||||
echo "PHP version: " . $phpVersion . "<br>";
|
||||
echo "MySQL Version: " . $mysqlVersion . "<br>";
|
||||
echo "Database Version: " . $databaseInfo . "<br>";
|
||||
echo "Operating System: " . $operatingSystem . "<br>";
|
||||
echo "Web Server: " . $webServer . "<br>";
|
||||
echo "Apache/PHP Error Log: " . $errorLog
|
||||
|
||||
@@ -16,6 +16,16 @@ if (isset($_GET['user']) & !empty($_GET['user'])) {
|
||||
$user = '';
|
||||
}
|
||||
|
||||
// Client Filter
|
||||
if (isset($_GET['client']) & !empty($_GET['client'])) {
|
||||
$client_query = 'AND (log_client_id = ' . intval($_GET['client']) . ')';
|
||||
$client = intval($_GET['client']);
|
||||
} else {
|
||||
// Default - any
|
||||
$client_query = '';
|
||||
$client = '';
|
||||
}
|
||||
|
||||
// Log Type Filter
|
||||
if (isset($_GET['type']) & !empty($_GET['type'])) {
|
||||
$log_type_query = "AND (log_type = '" . sanitizeInput($_GET['type']) . "')";
|
||||
@@ -42,14 +52,15 @@ $url_query_strings_sort = http_build_query($get_copy);
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM logs
|
||||
LEFT JOIN users ON log_user_id = user_id
|
||||
LEFT JOIN clients ON log_client_id = client_id
|
||||
WHERE (log_type LIKE '%$q%' OR log_action LIKE '%$q%' OR log_description LIKE '%$q%' OR log_ip LIKE '%$q%' OR log_user_agent LIKE '%$q%' OR user_name LIKE '%$q%' OR client_name LIKE '%$q%')
|
||||
AND DATE(log_created_at) BETWEEN '$dtf' AND '$dtt'
|
||||
$user_query
|
||||
$log_type_query
|
||||
$log_action_query
|
||||
ORDER BY $sort $order LIMIT $record_from, $record_to"
|
||||
LEFT JOIN users ON log_user_id = user_id
|
||||
LEFT JOIN clients ON log_client_id = client_id
|
||||
WHERE (log_type LIKE '%$q%' OR log_action LIKE '%$q%' OR log_description LIKE '%$q%' OR log_ip LIKE '%$q%' OR log_user_agent LIKE '%$q%' OR user_name LIKE '%$q%' OR client_name LIKE '%$q%')
|
||||
AND DATE(log_created_at) BETWEEN '$dtf' AND '$dtt'
|
||||
$user_query
|
||||
$client_query
|
||||
$log_type_query
|
||||
$log_action_query
|
||||
ORDER BY $sort $order LIMIT $record_from, $record_to"
|
||||
);
|
||||
|
||||
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
@@ -72,6 +83,27 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-2">
|
||||
<div class="form-group">
|
||||
<select class="form-control select2" name="client" onchange="this.form.submit()">
|
||||
<option value="" <?php if ($client == "") { echo "selected"; } ?>>- All Clients -</option>
|
||||
|
||||
<?php
|
||||
$sql_clients_filter = mysqli_query($mysqli, "SELECT * FROM clients ORDER BY client_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql_clients_filter)) {
|
||||
$client_id = intval($row['client_id']);
|
||||
$client_name = nullable_htmlentities($row['client_name']);
|
||||
?>
|
||||
<option <?php if ($client == $client_id) { echo "selected"; } ?> value="<?php echo $client_id; ?>"><?php echo $client_name; ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-2">
|
||||
<div class="form-group">
|
||||
<select class="form-control select2" name="user" onchange="this.form.submit()">
|
||||
@@ -170,13 +202,14 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tr>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_created_at&order=<?php echo $disp; ?>">Timestamp</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=user_name&order=<?php echo $disp; ?>">User</a></th>
|
||||
<?php if(empty($client)) { ?>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=client_name&order=<?php echo $disp; ?>">Client</a></th>
|
||||
<?php } ?>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_type&order=<?php echo $disp; ?>">Type</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_action&order=<?php echo $disp; ?>">Action</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_description&order=<?php echo $disp; ?>">Description</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_ip&order=<?php echo $disp; ?>">IP Address</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_user_agent&order=<?php echo $disp; ?>">User Agent</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_entity_id&order=<?php echo $disp; ?>">Entity ID</a></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -213,13 +246,14 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<tr>
|
||||
<td><?php echo $log_created_at; ?></td>
|
||||
<td><?php echo $user_name_display; ?></td>
|
||||
<?php if(empty($client)) { ?>
|
||||
<td><?php echo $client_name_display; ?></td>
|
||||
<?php } ?>
|
||||
<td><?php echo $log_type; ?></td>
|
||||
<td><?php echo $log_action; ?></td>
|
||||
<td><?php echo $log_description; ?></td>
|
||||
<td><?php echo $log_ip; ?></td>
|
||||
<td><?php echo "$log_user_os<br>$log_user_browser"; ?></td>
|
||||
<td><?php echo $log_entity_id; ?></td>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -48,9 +48,12 @@ $git_log = shell_exec("git log $repo_branch..origin/$repo_branch --pretty=format
|
||||
<small class="text-secondary">Current DB Version: <?php echo CURRENT_DATABASE_VERSION; ?></small>
|
||||
<br>
|
||||
<small class="text-secondary">Latest DB Version: <?php echo LATEST_DATABASE_VERSION; ?></small>
|
||||
<br>
|
||||
<small class="text-secondary">Branch: <?php echo $repo_branch; ?></small>
|
||||
<?php } else { ?>
|
||||
<p class="text-secondary">Current Database Version:<br><strong class="text-dark"><?php echo CURRENT_DATABASE_VERSION; ?></strong></p>
|
||||
<p class="text-secondary">Current App Version:<br><strong class="text-dark"><?php echo $current_version; ?></strong></p>
|
||||
<p class="text-secondary">Branch:<br><strong class="text-dark"><?php echo $repo_branch; ?></strong></p>
|
||||
<p class="text-muted">You are up to date!<br>Everything is going to be alright</p>
|
||||
<i class="far fa-3x text-dark fa-smile-wink"></i><br>
|
||||
<?php }
|
||||
|
||||
2
ajax.php
2
ajax.php
@@ -176,7 +176,7 @@ if (isset($_POST['asset_set_notes'])) {
|
||||
mysqli_query($mysqli, "UPDATE assets SET asset_notes = '$notes' WHERE asset_id = $asset_id");
|
||||
|
||||
// Logging
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Assets', log_action = 'Modify', log_description = '$session_name modified asset notes', 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 = 'Asset', log_action = 'Modify', log_description = '$session_name modified asset notes', log_ip = '$session_ip', log_user_agent = '$session_user_agent', log_user_id = $session_user_id");
|
||||
|
||||
}
|
||||
|
||||
|
||||
30
api/v1/credentials/create.php
Normal file
30
api/v1/credentials/create.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
require_once '../validate_api_key.php';
|
||||
|
||||
require_once '../require_post_method.php';
|
||||
|
||||
// Parse info
|
||||
require_once 'credential_model.php';
|
||||
|
||||
// Default
|
||||
$insert_id = false;
|
||||
|
||||
if (!empty($api_key_decrypt_password) && !empty($name) && !(empty($password))) {
|
||||
|
||||
// Add credential
|
||||
$insert_sql = mysqli_query($mysqli,"INSERT INTO logins SET login_name = '$name', login_description = '$description', login_uri = '$uri', login_uri_2 = '$uri_2', login_username = '$username', login_password = '$password', login_otp_secret = '$otp_secret', login_note = '$note', login_important = $important, login_contact_id = $contact_id, login_vendor_id = $vendor_id, login_asset_id = $asset_id, login_software_id = $software_id, login_client_id = $client_id");
|
||||
|
||||
// Check insert & get insert ID
|
||||
if ($insert_sql) {
|
||||
$insert_id = mysqli_insert_id($mysqli);
|
||||
|
||||
//Logging
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Credential', log_action = 'Create', log_description = '$name via API ($api_key_name)', log_ip = '$ip', log_user_agent = '$user_agent', log_client_id = $client_id");
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'API', log_action = 'Success', log_description = 'Created credential $name via API ($api_key_name)', log_ip = '$ip', log_user_agent = '$user_agent', log_client_id = $client_id");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Output
|
||||
require_once '../create_output.php';
|
||||
120
api/v1/credentials/credential_model.php
Normal file
120
api/v1/credentials/credential_model.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
|
||||
// Variable assignment from POST (or: blank/from DB is updating)
|
||||
|
||||
$api_key_decrypt_password = '';
|
||||
if (isset($_POST['api_key_decrypt_password'])) {
|
||||
$api_key_decrypt_password = $_POST['api_key_decrypt_password']; // No sanitization
|
||||
}
|
||||
|
||||
if (isset($_POST['login_name'])) {
|
||||
$name = sanitizeInput($_POST['login_name']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_name'])) {
|
||||
$name = $credential_row['login_name'];
|
||||
} else {
|
||||
$name = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_description'])) {
|
||||
$description = sanitizeInput($_POST['login_description']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_description'])) {
|
||||
$description = $credential_row['login_description'];
|
||||
} else {
|
||||
$description = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_uri'])) {
|
||||
$uri = sanitizeInput($_POST['login_uri']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_uri'])) {
|
||||
$uri = $credential_row['login_uri'];
|
||||
} else {
|
||||
$uri = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_uri_2'])) {
|
||||
$uri_2 = sanitizeInput($_POST['login_uri_2']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_uri_2'])) {
|
||||
$uri_2 = $credential_row['login_uri_2'];
|
||||
} else {
|
||||
$uri_2 = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_username'])) {
|
||||
$username = $_POST['login_username'];
|
||||
$username = apiEncryptLoginEntry($username, $api_key_decrypt_hash, $api_key_decrypt_password);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_username'])) {
|
||||
$username = $credential_row['login_username'];
|
||||
} else {
|
||||
$username = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_password'])) {
|
||||
$password = $_POST['login_password'];
|
||||
$password = apiEncryptLoginEntry($password, $api_key_decrypt_hash, $api_key_decrypt_password);
|
||||
$password_changed = true;
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_password'])) {
|
||||
$password = $credential_row['login_password'];
|
||||
$password_changed = false;
|
||||
} else {
|
||||
$password = '';
|
||||
$password_changed = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (isset($_POST['login_otp_secret'])) {
|
||||
$otp_secret = sanitizeInput($_POST['login_otp_secret']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_otp_secret'])) {
|
||||
$otp_secret = $credential_row['login_otp_secret'];
|
||||
} else {
|
||||
$otp_secret = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_note'])) {
|
||||
$note = sanitizeInput($_POST['login_note']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_note'])) {
|
||||
$note = $credential_row['login_note'];
|
||||
} else {
|
||||
$note = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_important'])) {
|
||||
$important = intval($_POST['login_important']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_important'])) {
|
||||
$important = $credential_row['login_important'];
|
||||
} else {
|
||||
$important = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_contact_id'])) {
|
||||
$contact_id = intval($_POST['login_contact_id']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_contact_id'])) {
|
||||
$contact_id = $credential_row['login_contact_id'];
|
||||
} else {
|
||||
$contact_id = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_vendor_id'])) {
|
||||
$vendor_id = intval($_POST['login_vendor_id']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_vendor_id'])) {
|
||||
$vendor_id = $credential_row['login_vendor_id'];
|
||||
} else {
|
||||
$vendor_id = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_asset_id'])) {
|
||||
$asset_id = intval($_POST['login_asset_id']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_asset_id'])) {
|
||||
$asset_id = $credential_row['login_asset_id'];
|
||||
} else {
|
||||
$asset_id = '';
|
||||
}
|
||||
|
||||
if (isset($_POST['login_software_id'])) {
|
||||
$software_id = intval($_POST['login_software_id']);
|
||||
} elseif (isset($credential_row) && isset($credential_row['login_software_id'])) {
|
||||
$software_id = $credential_row['login_software_id'];
|
||||
} else {
|
||||
$software_id = '';
|
||||
}
|
||||
59
api/v1/credentials/read.php
Normal file
59
api/v1/credentials/read.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
require_once '../validate_api_key.php';
|
||||
|
||||
require_once '../require_get_method.php';
|
||||
|
||||
// Defaults
|
||||
$sql = false;
|
||||
|
||||
$api_key_decrypt_password = '';
|
||||
if (isset($_GET['api_key_decrypt_password'])) {
|
||||
$api_key_decrypt_password = $_GET['api_key_decrypt_password']; // No sanitization
|
||||
}
|
||||
|
||||
// Specific credential/login via ID (single)
|
||||
if (isset($_GET['login_id']) && !empty($api_key_decrypt_password)) {
|
||||
|
||||
$id = intval($_GET['login_id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM logins WHERE login_id = '$id' AND login_client_id LIKE '$client_id' LIMIT 1");
|
||||
|
||||
|
||||
} elseif (!empty($api_key_decrypt_password)) {
|
||||
// All credentials ("logins")
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM logins WHERE login_client_id LIKE '$client_id' ORDER BY login_id LIMIT $limit OFFSET $offset");
|
||||
|
||||
}
|
||||
|
||||
// Output - Not using the standard API read_output.php
|
||||
// Usually we just output what is in the database, but credentials need to be decrypted first.
|
||||
|
||||
if ($sql && mysqli_num_rows($sql) > 0) {
|
||||
|
||||
$return_arr['success'] = "True";
|
||||
$return_arr['count'] = mysqli_num_rows($sql);
|
||||
|
||||
$row = array();
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
$row['login_username'] = apiDecryptLoginEntry($row['login_username'], $api_key_decrypt_hash, $api_key_decrypt_password);
|
||||
$row['login_password'] = apiDecryptLoginEntry($row['login_password'], $api_key_decrypt_hash, $api_key_decrypt_password);
|
||||
$return_arr['data'][] = $row;
|
||||
}
|
||||
|
||||
echo json_encode($return_arr);
|
||||
exit();
|
||||
}
|
||||
else {
|
||||
$return_arr['success'] = "False";
|
||||
$return_arr['message'] = "No resource (for this client and company) with the specified parameter(s).";
|
||||
|
||||
// Log any database/schema related errors to the PHP Error log
|
||||
if (mysqli_error($mysqli)) {
|
||||
error_log("API Database Error: " . mysqli_error($mysqli));
|
||||
}
|
||||
|
||||
echo json_encode($return_arr);
|
||||
exit();
|
||||
}
|
||||
38
api/v1/credentials/update.php
Normal file
38
api/v1/credentials/update.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
require_once '../validate_api_key.php';
|
||||
|
||||
require_once '../require_post_method.php';
|
||||
|
||||
// Parse ID
|
||||
$login_id = intval($_POST['login_id']);
|
||||
|
||||
// Default
|
||||
$update_count = false;
|
||||
|
||||
if (!empty($_POST['api_key_decrypt_password']) && !empty($login_id)) {
|
||||
|
||||
$credential_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT * FROM logins WHERE login_id = '$login_id' AND login_client_id = $client_id LIMIT 1"));
|
||||
|
||||
// Variable assignment from POST - assigning the current database value if a value is not provided
|
||||
require_once 'credential_model.php';
|
||||
|
||||
$update_sql = mysqli_query($mysqli,"UPDATE logins SET login_name = '$name', login_description = '$description', login_uri = '$uri', login_uri_2 = '$uri_2', login_username = '$username', login_password = '$password', login_otp_secret = '$otp_secret', login_note = '$note', login_important = $important, login_contact_id = $contact_id, login_vendor_id = $vendor_id, login_asset_id = $asset_id, login_software_id = $software_id, login_client_id = $client_id WHERE login_id = '$login_id' AND login_client_id = $client_id LIMIT 1");
|
||||
|
||||
// Check insert & get insert ID
|
||||
if ($update_sql) {
|
||||
$update_count = mysqli_affected_rows($mysqli);
|
||||
|
||||
if ($password_changed) {
|
||||
mysqli_query($mysqli, "UPDATE logins SET login_password_changed_at = NOW() WHERE login_id = $login_id LIMIT 1");
|
||||
}
|
||||
|
||||
//Logging
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Credential', log_action = 'Update', log_description = '$name via API ($api_key_name)', log_ip = '$ip', log_user_agent = '$user_agent', log_client_id = $client_id");
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'API', log_action = 'Success', log_description = 'Updated credential $name via API ($api_key_name)', log_ip = '$ip', log_user_agent = '$user_agent', log_client_id = $client_id");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Output
|
||||
require_once '../update_output.php';
|
||||
@@ -88,6 +88,7 @@ if (isset($api_key)) {
|
||||
// Set client ID, company ID & key name
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$api_key_name = htmlentities($row['api_key_name']);
|
||||
$api_key_decrypt_hash = $row['api_key_decrypt_hash']; // No sanitization
|
||||
$client_id = intval($row['api_key_client_id']);
|
||||
|
||||
// Set limit & offset for queries
|
||||
|
||||
@@ -314,6 +314,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($_GET['type'] !== 'virtual') { ?>
|
||||
<div class="form-group">
|
||||
<label>Purchase Date</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
|
||||
</div>
|
||||
<input type="date" class="form-control" name="purchase_date" max="2999-12-31">
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Install Date</label>
|
||||
<div class="input-group">
|
||||
@@ -325,15 +337,6 @@
|
||||
</div>
|
||||
|
||||
<?php if ($_GET['type'] !== 'virtual') { ?>
|
||||
<div class="form-group">
|
||||
<label>Purchase Date</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
|
||||
</div>
|
||||
<input type="date" class="form-control" name="purchase_date" max="2999-12-31">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Warranty Expire</label>
|
||||
<div class="input-group">
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-notes<?php echo $asset_id; ?>">Notes</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-history<?php echo $asset_id; ?>">History</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
@@ -333,6 +336,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($asset_type !== 'Virtual Machine') { ?>
|
||||
<div class="form-group">
|
||||
<label>Purchase Date</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
|
||||
</div>
|
||||
<input type="date" class="form-control" name="purchase_date" max="2999-12-31" value="<?php echo $asset_purchase_date; ?>">
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Install Date</label>
|
||||
<div class="input-group">
|
||||
@@ -344,16 +359,6 @@
|
||||
</div>
|
||||
|
||||
<?php if ($asset_type !== 'Virtual Machine') { ?>
|
||||
<div class="form-group">
|
||||
<label>Purchase Date</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-shopping-cart"></i></span>
|
||||
</div>
|
||||
<input type="date" class="form-control" name="purchase_date" max="2999-12-31" value="<?php echo $asset_purchase_date; ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Warranty Expire</label>
|
||||
<div class="input-group">
|
||||
@@ -386,6 +391,32 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="tab-pane fade" id="pills-history<?php echo $asset_id; ?>">
|
||||
|
||||
<?php $sql_history = mysqli_query($mysqli, "SELECT * FROM logs WHERE log_type = 'asset' and log_entity_id = $asset_id and log_client_id = $client_id"); ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Asset History</label>
|
||||
|
||||
<ul>
|
||||
|
||||
<?php
|
||||
while ($row = mysqli_fetch_array($sql_history)) {
|
||||
$log_action = nullable_htmlentities(($row['log_action']));
|
||||
$log_description = nullable_htmlentities(($row['log_description']));
|
||||
$log_created_at = nullable_htmlentities(($row['log_created_at']));
|
||||
echo "<li>$log_created_at - $log_action: $log_description</li>";
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-white">
|
||||
|
||||
46
client_asset_transfer_modal.php
Normal file
46
client_asset_transfer_modal.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<div class="modal" id="transferAssetModal<?php echo $asset_id; ?>" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content bg-dark">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-<?php echo $device_icon; ?> mr-2"></i>Transfer asset: <strong><?php echo $asset_name; ?></strong> to a different client</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="current_asset_id" value="<?php echo $asset_id; ?>">
|
||||
<div class="modal-body bg-white">
|
||||
|
||||
<div class="form-group">
|
||||
<label>New 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>
|
||||
|
||||
<?php $clients_sql = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_id != $client_id AND client_archived_at IS NULL"); ?>
|
||||
<select class="form-control select2" name="new_client_id" required>
|
||||
<?php
|
||||
while ($row = mysqli_fetch_array($clients_sql)) {
|
||||
$id = intval($row["client_id"]);
|
||||
$name = nullable_htmlentities($row["client_name"]);
|
||||
echo "<option value='$id'>$name</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-dark" role="alert">
|
||||
<i>The current asset will be archived and content copied to a new asset.</i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer bg-white">
|
||||
<button type="submit" name="change_client_asset" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Transfer</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -240,7 +240,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
if ($_GET['type'] !== 'network' && $_GET['type'] !== 'other') { ?>
|
||||
<th><a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=asset_os&order=<?php echo $disp; ?>">OS</a></th>
|
||||
<?php } ?>
|
||||
<th><a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=asset_ip&order=<?php echo $disp; ?>">IP</a></th>
|
||||
<th><a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=interface_ip&order=<?php echo $disp; ?>">IP</a></th>
|
||||
<th><a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=asset_install_date&order=<?php echo $disp; ?>">Install Date</a></th>
|
||||
<?php if ($_GET['type'] !== 'network' && $_GET['type'] !== 'servers' && $_GET['type'] !== 'other') { ?>
|
||||
<th><a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=contact_name&order=<?php echo $disp; ?>">Assigned To</a></th>
|
||||
@@ -466,6 +466,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<i class="fas fa-fw fa-redo mr-2"></i>Unarchive
|
||||
</a>
|
||||
<?php } else { ?>
|
||||
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#transferAssetModal<?php echo $asset_id; ?>">
|
||||
<i class="fas fa-fw fa-arrow-right mr-2"></i>Transfer
|
||||
</a>
|
||||
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_asset=<?php echo $asset_id; ?>">
|
||||
<i class="fas fa-fw fa-archive mr-2"></i>Archive
|
||||
</a>
|
||||
@@ -489,6 +492,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
require "client_asset_copy_modal.php";
|
||||
|
||||
require "client_asset_transfer_modal.php";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
<?php
|
||||
require_once "inc_all_client.php";
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM contacts
|
||||
WHERE contact_client_id = $client_id
|
||||
AND contact_archived_at IS NULL
|
||||
AND contact_email != ''
|
||||
ORDER BY contact_primary DESC,
|
||||
contact_important DESC"
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title mt-2 mb-2"><i class="fa fa-fw fa-envelope-open mr-2"></i>Bulk Mail to Special Contacts</h3>
|
||||
<div class="card-tools">
|
||||
<button id="bulkActionButton" hidden class="btn btn-primary" type="submit" form='bulkActions' name="send_bulk_mail_now">
|
||||
<i class="fas fa-fw fa-paper-plane mr-2"></i>Send Now (<span id="selectedCount">0</span>)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="bulkActions" action="post.php" method="post">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
|
||||
<h5>Email Message</h5>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="form-group">
|
||||
<select type="text" class="form-control select2" name="mail_from">
|
||||
<option value="<?php echo nullable_htmlentities($config_mail_from_email); ?>">
|
||||
<?php echo nullable_htmlentities("$config_mail_from_name - $config_mail_from_email"); ?></option>
|
||||
<option value="<?php echo nullable_htmlentities($config_invoice_from_email); ?>">
|
||||
<?php echo nullable_htmlentities("$config_invoice_from_name - $config_invoice_from_email"); ?></option>
|
||||
<option value="<?php echo nullable_htmlentities($config_quote_from_email); ?>">
|
||||
<?php echo nullable_htmlentities("$config_quote_from_name - $config_quote_from_email"); ?></option>
|
||||
<option value="<?php echo nullable_htmlentities($config_ticket_from_email); ?>">
|
||||
<?php echo nullable_htmlentities("$config_ticket_from_name - $config_ticket_from_email"); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="mail_from_name" placeholder="From Name"
|
||||
value="<?php echo nullable_htmlentities($config_mail_from_name); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="subject" placeholder="Subject" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<textarea class="form-control tinymce" name="body"
|
||||
placeholder="Type an email in here"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
|
||||
</div>
|
||||
<input type="datetime-local" class="form-control" name="queued_at">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
|
||||
<h5>Select Contacts</h5>
|
||||
<hr>
|
||||
<div class="card">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="selectAllCheckbox"
|
||||
onclick="checkAll(this)">
|
||||
</div>
|
||||
</td>
|
||||
<th>Name</th>
|
||||
<th>Title</th>
|
||||
<th>Email</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
<?php
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
$contact_id = intval($row['contact_id']);
|
||||
$contact_name = nullable_htmlentities($row['contact_name']);
|
||||
$contact_title = nullable_htmlentities($row['contact_title']);
|
||||
if (empty($contact_title)) {
|
||||
$contact_title_display = "-";
|
||||
} else {
|
||||
$contact_title_display = "$contact_title";
|
||||
}
|
||||
$contact_email = nullable_htmlentities($row['contact_email']);
|
||||
$contact_primary = intval($row['contact_primary']);
|
||||
$contact_important = intval($row['contact_important']);
|
||||
$contact_billing = intval($row['contact_billing']);
|
||||
$contact_technical = intval($row['contact_technical']);
|
||||
?>
|
||||
<tr>
|
||||
<td class="pr-0 bg-light">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input bulk-select" name="contact_ids[]"
|
||||
value="<?php echo $contact_id; ?>">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<a href="client_contact_details.php?client_id=<?php echo $client_id; ?>&contact_id=<?php echo $contact_id; ?>"
|
||||
target="_blank">
|
||||
<?php echo $contact_name; ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><?php echo $contact_title_display; ?></td>
|
||||
<td><?php echo $contact_email; ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<script src="js/bulk_actions.js"></script>
|
||||
|
||||
<?php
|
||||
|
||||
require_once "footer.php";
|
||||
57
client_contact_bulk_email_modal.php
Normal file
57
client_contact_bulk_email_modal.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<div class="modal" id="bulkSendEmailModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content bg-dark">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-envelope-open mr-2"></i>Bulk Send Email</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body bg-white">
|
||||
|
||||
<div class="form-group">
|
||||
<select type="text" class="form-control select2" name="mail_from">
|
||||
<option value="<?php echo nullable_htmlentities($config_mail_from_email); ?>">
|
||||
<?php echo nullable_htmlentities("$config_mail_from_name - $config_mail_from_email"); ?></option>
|
||||
<option value="<?php echo nullable_htmlentities($config_invoice_from_email); ?>">
|
||||
<?php echo nullable_htmlentities("$config_invoice_from_name - $config_invoice_from_email"); ?></option>
|
||||
<option value="<?php echo nullable_htmlentities($config_quote_from_email); ?>">
|
||||
<?php echo nullable_htmlentities("$config_quote_from_name - $config_quote_from_email"); ?></option>
|
||||
<option value="<?php echo nullable_htmlentities($config_ticket_from_email); ?>">
|
||||
<?php echo nullable_htmlentities("$config_ticket_from_name - $config_ticket_from_email"); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="mail_from_name" placeholder="From Name"
|
||||
value="<?php echo nullable_htmlentities($config_mail_from_name); ?>">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" name="subject" placeholder="Subject">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<textarea class="form-control tinymce" name="body"
|
||||
placeholder="Type an email in here"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-calendar"></i></span>
|
||||
</div>
|
||||
<input type="datetime-local" class="form-control" name="queued_at">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer bg-white">
|
||||
<button type="submit" name="send_bulk_mail_now" class="btn btn-primary text-bold"><i class="fas fa-paper-plane mr-2"></i>Send</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
<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 $contact_id; ?>"><i class="fa fa-fw fa-user mr-2"></i>Details</a>
|
||||
<a class="nav-link active" data-toggle="pill" href="#pills-details<?php echo $contact_id; ?>"><i class="fa fa-fw fa-id-badge mr-2"></i>Details</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-photo<?php echo $contact_id; ?>"><i class="fa fa-fw fa-image mr-2"></i>Photo</a>
|
||||
|
||||
@@ -54,7 +54,7 @@ $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="fa fa-fw fa-users mr-2"></i>Contacts</h3>
|
||||
<h3 class="card-title mt-2"><i class="fa fa-fw fa-address-book mr-2"></i>Contacts</h3>
|
||||
<div class="card-tools">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addContactModal">
|
||||
@@ -156,6 +156,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkAssignTagsModal">
|
||||
<i class="fas fa-fw fa-tags mr-2"></i>Assign Tags
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#bulkSendEmailModal">
|
||||
<i class="fas fa-fw fa-paper-plane mr-2"></i>Send Email
|
||||
</a>
|
||||
<?php if ($archived) { ?>
|
||||
<div class="dropdown-divider"></div>
|
||||
<button class="dropdown-item text-info"
|
||||
@@ -411,6 +415,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<?php require_once "client_contact_bulk_edit_department_modal.php"; ?>
|
||||
<?php require_once "client_contact_bulk_edit_role_modal.php"; ?>
|
||||
<?php require_once "client_contact_bulk_assign_tags_modal.php"; ?>
|
||||
<?php require_once "client_contact_bulk_email_modal.php"; ?>
|
||||
</form>
|
||||
<?php require_once "pagination.php";
|
||||
?>
|
||||
|
||||
@@ -217,6 +217,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<th>
|
||||
<a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=document_updated_at&order=<?php echo $disp; ?>">Last Update</a>
|
||||
</th>
|
||||
<th></th>
|
||||
<th class="text-center">
|
||||
Action
|
||||
</th>
|
||||
@@ -235,6 +236,31 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
$document_updated_at = date("m/d/Y",strtotime($row['document_updated_at']));
|
||||
$document_folder_id = intval($row['document_folder_id']);
|
||||
|
||||
// Check if shared
|
||||
$sql_shared = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT * FROM shared_items
|
||||
WHERE item_client_id = $client_id
|
||||
AND item_active = 1
|
||||
AND item_views != item_view_limit
|
||||
AND item_expire_at > NOW()
|
||||
AND item_type = 'Document'
|
||||
AND item_related_id = $document_id
|
||||
LIMIT 1"
|
||||
);
|
||||
$row = mysqli_fetch_array($sql_shared);
|
||||
$item_id = intval($row['item_id']);
|
||||
$item_active = nullable_htmlentities($row['item_active']);
|
||||
$item_key = nullable_htmlentities($row['item_key']);
|
||||
$item_type = nullable_htmlentities($row['item_type']);
|
||||
$item_related_id = intval($row['item_related_id']);
|
||||
$item_note = nullable_htmlentities($row['item_note']);
|
||||
$item_views = nullable_htmlentities($row['item_views']);
|
||||
$item_view_limit = nullable_htmlentities($row['item_view_limit']);
|
||||
$item_created_at = nullable_htmlentities($row['item_created_at']);
|
||||
$item_expire_at = nullable_htmlentities($row['item_expire_at']);
|
||||
$item_expire_at_human = timeAgo($row['item_expire_at']);
|
||||
|
||||
?>
|
||||
|
||||
<tr>
|
||||
@@ -252,6 +278,13 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<div class="text-secondary mt-1"><?php echo $document_created_by_name; ?>
|
||||
</td>
|
||||
<td><?php echo $document_updated_at; ?></td>
|
||||
<td>
|
||||
<?php if($item_id) { ?>
|
||||
<div title="Expires <?php echo $item_expire_at_human; ?>">
|
||||
<i class="fas fa-fw fa-link"></i> Shared
|
||||
</div>
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="dropdown dropleft text-center">
|
||||
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<label>Name <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-user"></i></span>
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-id-badge"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="name" placeholder="Name or Company"
|
||||
value="<?php echo $client_name; ?>" required>
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
$sql_assets_select = mysqli_query($mysqli, "SELECT * FROM assets
|
||||
WHERE asset_client_id = $client_id
|
||||
AND asset_archived_at IS NULL
|
||||
$exclude_condition
|
||||
ORDER BY asset_name ASC"
|
||||
);
|
||||
while ($row = mysqli_fetch_array($sql_assets_select)) {
|
||||
@@ -65,7 +64,7 @@
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="modal-footer bg-white">
|
||||
<button type="submit" name="link_asset_to_file" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Link</button>
|
||||
|
||||
@@ -70,10 +70,10 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
?>
|
||||
|
||||
<div class="card card-dark">
|
||||
|
||||
|
||||
<div class="card-header py-2">
|
||||
<h3 class="card-title mt-2"><i class="fa fa-fw fa-paperclip mr-2"></i>Files</h3>
|
||||
|
||||
|
||||
<div class="card-tools">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#uploadFilesModal">
|
||||
@@ -88,7 +88,7 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3 border-right mb-3">
|
||||
@@ -156,7 +156,7 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
</div>
|
||||
|
||||
<div class="col-md-9">
|
||||
|
||||
|
||||
<form autocomplete="off">
|
||||
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
|
||||
<input type="hidden" name="view" value="<?php echo $view; ?>">
|
||||
@@ -174,7 +174,7 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
<div class="btn-group float-right">
|
||||
<a href="?<?php echo $url_query_strings_sort; ?>&view=0" class="btn <?php if($view == 0){ echo "btn-primary"; } else { echo "btn-outline-secondary"; } ?>"><i class="fas fa-list-ul"></i></a>
|
||||
<a href="?<?php echo $url_query_strings_sort; ?>&view=1" class="btn <?php if($view == 1){ echo "btn-primary"; } else { echo "btn-outline-secondary"; } ?>"><i class="fas fa-th-large"></i></a>
|
||||
|
||||
|
||||
<div class="dropdown ml-2" id="bulkActionButton" hidden>
|
||||
<button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown">
|
||||
<i class="fas fa-fw fa-layer-group mr-2"></i>Bulk Action (<span id="selectedCount">0</span>)
|
||||
@@ -190,7 +190,7 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<?php
|
||||
@@ -225,7 +225,10 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
|
||||
<small><?php echo $file_name; ?></small>
|
||||
|
||||
<a href="#" data-toggle="modal" data-target="#deleteFileModal" onclick="populateFileDeleteModal(<?php echo "$file_id , '$file_name'" ?>)" class="text-white float-right mr-1"><i class="fa fa-times"></i></a>
|
||||
<?php if ($session_user_role == 3) { ?>
|
||||
<a href="#" data-toggle="modal" data-target="#deleteFileModal" onclick="populateFileDeleteModal(<?php echo "$file_id , '$file_name'" ?>)" class="text-white float-right mr-1"><i class="fa fa-times"></i></a>
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -243,7 +246,7 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
|
||||
<div class="table-responsive-sm">
|
||||
<table class="table border">
|
||||
|
||||
|
||||
<thead class="thead-light <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
|
||||
<tr>
|
||||
<td class="bg-light pr-0">
|
||||
@@ -253,10 +256,11 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
</td>
|
||||
<th><a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_name&order=<?php echo $disp; ?>">Name</a></th>
|
||||
<th><a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=file_created_at&order=<?php echo $disp; ?>">Uploaded</a></th>
|
||||
<th></th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
|
||||
<tbody>
|
||||
|
||||
<?php
|
||||
@@ -290,6 +294,32 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
$file_icon = "file";
|
||||
}
|
||||
$file_created_at = nullable_htmlentities($row['file_created_at']);
|
||||
|
||||
// Check if shared
|
||||
$sql_shared = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT * FROM shared_items
|
||||
WHERE item_client_id = $client_id
|
||||
AND item_active = 1
|
||||
AND item_views != item_view_limit
|
||||
AND item_expire_at > NOW()
|
||||
AND item_type = 'File'
|
||||
AND item_related_id = $file_id
|
||||
LIMIT 1"
|
||||
);
|
||||
$row = mysqli_fetch_array($sql_shared);
|
||||
$item_id = intval($row['item_id']);
|
||||
$item_active = nullable_htmlentities($row['item_active']);
|
||||
$item_key = nullable_htmlentities($row['item_key']);
|
||||
$item_type = nullable_htmlentities($row['item_type']);
|
||||
$item_related_id = intval($row['item_related_id']);
|
||||
$item_note = nullable_htmlentities($row['item_note']);
|
||||
$item_views = nullable_htmlentities($row['item_views']);
|
||||
$item_view_limit = nullable_htmlentities($row['item_view_limit']);
|
||||
$item_created_at = nullable_htmlentities($row['item_created_at']);
|
||||
$item_expire_at = nullable_htmlentities($row['item_expire_at']);
|
||||
$item_expire_at_human = timeAgo($row['item_expire_at']);
|
||||
|
||||
?>
|
||||
|
||||
<tr>
|
||||
@@ -313,6 +343,13 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
</a>
|
||||
</td>
|
||||
<td><?php echo $file_created_at; ?></td>
|
||||
<td>
|
||||
<?php if($item_id) { ?>
|
||||
<div title="Expires <?php echo $item_expire_at_human; ?>">
|
||||
<i class="fas fa-fw fa-link"></i> Shared
|
||||
</div>
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="dropdown dropleft text-center">
|
||||
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
|
||||
@@ -338,10 +375,12 @@ $num_of_files = mysqli_num_rows($sql);
|
||||
<a class="dropdown-item text-danger confirm-link" href="post.php?archive_file=<?php echo $file_id; ?>">
|
||||
<i class="fas fa-fw fa-archive mr-2"></i>Archive
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item text-danger text-bold" href="#" data-toggle="modal" data-target="#deleteFileModal" onclick="populateFileDeleteModal(<?php echo "$file_id , '$file_name'" ?>)">
|
||||
<i class="fas fa-fw fa-trash mr-2"></i>Delete
|
||||
</a>
|
||||
<?php if ($session_user_role == 3) { ?>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item text-danger text-bold" href="#" data-toggle="modal" data-target="#deleteFileModal" onclick="populateFileDeleteModal(<?php echo "$file_id , '$file_name'" ?>)">
|
||||
<i class="fas fa-fw fa-trash mr-2"></i>Delete
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
28
client_import_modal.php
Normal file
28
client_import_modal.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<div class="modal" id="importClientModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content bg-dark">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-users mr-2"></i>Import Clients</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
|
||||
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
|
||||
<div class="modal-body bg-white">
|
||||
<p><strong>Format csv file with headings & data:</strong><br>Client Name, Industry, Referral, Website, Location Name, Location Phone, Location Address, City, State, Postal Code, Country, Contact Name, Title, Contact Phone, Extension, Contact Mobile, Contact Email, Hourly Rate, Currency, Payment Terms, Tax ID, Abbreviation</p>
|
||||
<hr>
|
||||
<div class="form-group my-4">
|
||||
<input type="file" class="form-control-file" name="file" accept=".csv">
|
||||
</div>
|
||||
<hr>
|
||||
<div>Download: <a class="text-bold" href="post.php?download_clients_csv_template">sample csv template</a></div>
|
||||
</div>
|
||||
<div class="modal-footer bg-white">
|
||||
<button type="submit" name="import_clients_csv" class="btn btn-primary text-strong"><i class="fas fa-upload mr-2"></i>Import</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -7,16 +7,32 @@ $order = "ASC";
|
||||
require_once "inc_all_client.php";
|
||||
|
||||
|
||||
// Location Filter
|
||||
if (isset($_GET['location']) & !empty($_GET['location'])) {
|
||||
$location_query = 'AND (a.asset_location_id = ' . intval($_GET['location']) . ')';
|
||||
$location_query_innerjoin = 'INNER JOIN assets a on a.asset_id = l.login_asset_id ';
|
||||
$location = intval($_GET['location']);
|
||||
} else {
|
||||
// Default - any
|
||||
$location_query_innerjoin = '';
|
||||
$location_query = '';
|
||||
$location = '';
|
||||
}
|
||||
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM logins
|
||||
WHERE login_client_id = $client_id
|
||||
AND login_$archive_query
|
||||
AND (login_name LIKE '%$q%' OR login_description LIKE '%$q%' OR login_uri LIKE '%$q%')
|
||||
ORDER BY login_important DESC, $sort $order LIMIT $record_from, $record_to"
|
||||
"SELECT SQL_CALC_FOUND_ROWS *
|
||||
FROM logins l
|
||||
$location_query_innerjoin
|
||||
WHERE l.login_client_id = $client_id
|
||||
AND l.login_$archive_query
|
||||
AND (l.login_name LIKE '%$q%' OR l.login_description LIKE '%$q%' OR l.login_uri LIKE '%$q%')
|
||||
$location_query
|
||||
ORDER BY l.login_important DESC, $sort $order LIMIT $record_from, $record_to"
|
||||
);
|
||||
|
||||
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
@@ -28,7 +44,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<h3 class="card-title mt-2"><i class="fa fa-fw fa-key mr-2"></i>Credentials</h3>
|
||||
<div class="card-tools">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addLoginModal">
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addLoginModal" <?php if (!isset($_COOKIE['user_encryption_session_key'])) { echo "disabled"; } ?>>
|
||||
<i class="fas fa-plus mr-2"></i>New Credential
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
|
||||
@@ -58,7 +74,27 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-2">
|
||||
<div class="input-group">
|
||||
<select class="form-control select2" name="location" onchange="this.form.submit()">
|
||||
<option value="" <?php if ($location == "") { echo "selected"; } ?>>- All Asset Locations -</option>
|
||||
|
||||
<?php
|
||||
$sql_locations_filter = mysqli_query($mysqli, "SELECT * FROM locations WHERE location_client_id = $client_id AND location_archived_at IS NULL ORDER BY location_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql_locations_filter)) {
|
||||
$location_id = intval($row['location_id']);
|
||||
$location_name = nullable_htmlentities($row['location_name']);
|
||||
?>
|
||||
<option <?php if ($location == $location_id) { echo "selected"; } ?> value="<?php echo $location_id; ?>"><?php echo $location_name; ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="btn-group float-right">
|
||||
<a href="?client_id=<?php echo $client_id; ?>&archived=<?php if($archived == 1){ echo 0; } else { echo 1; } ?>"
|
||||
class="btn btn-<?php if($archived == 1){ echo "primary"; } else { echo "default"; } ?>">
|
||||
@@ -109,6 +145,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<th>Password / Key</th>
|
||||
<th>OTP</th>
|
||||
<th><a class="text-secondary" href="?<?php echo $url_query_strings_sort; ?>&sort=login_uri&order=<?php echo $disp; ?>">URI</a></th>
|
||||
<th></th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -149,6 +186,32 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
$login_asset_id = intval($row['login_asset_id']);
|
||||
$login_software_id = intval($row['login_software_id']);
|
||||
|
||||
// Check if shared
|
||||
$sql_shared = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT * FROM shared_items
|
||||
WHERE item_client_id = $client_id
|
||||
AND item_active = 1
|
||||
AND item_views != item_view_limit
|
||||
AND item_expire_at > NOW()
|
||||
AND item_type = 'Login'
|
||||
AND item_related_id = $login_id
|
||||
LIMIT 1"
|
||||
);
|
||||
$row = mysqli_fetch_array($sql_shared);
|
||||
$item_id = intval($row['item_id']);
|
||||
$item_active = nullable_htmlentities($row['item_active']);
|
||||
$item_key = nullable_htmlentities($row['item_key']);
|
||||
$item_type = nullable_htmlentities($row['item_type']);
|
||||
$item_related_id = intval($row['item_related_id']);
|
||||
$item_note = nullable_htmlentities($row['item_note']);
|
||||
$item_views = nullable_htmlentities($row['item_views']);
|
||||
$item_view_limit = nullable_htmlentities($row['item_view_limit']);
|
||||
$item_created_at = nullable_htmlentities($row['item_created_at']);
|
||||
$item_expire_at = nullable_htmlentities($row['item_expire_at']);
|
||||
$item_expire_at_human = timeAgo($row['item_expire_at']);
|
||||
|
||||
|
||||
?>
|
||||
<tr class="<?php if (!empty($login_important)) { echo "text-bold"; } ?>">
|
||||
<td class="pr-0">
|
||||
@@ -173,6 +236,13 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
</td>
|
||||
<td><?php echo $otp_display; ?></td>
|
||||
<td><?php echo $login_uri_display; ?></td>
|
||||
<td>
|
||||
<?php if($item_id) { ?>
|
||||
<div title="Expires <?php echo $item_expire_at_human; ?>">
|
||||
<i class="fas fa-fw fa-link"></i> Shared
|
||||
</div>
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<div class="btn-group">
|
||||
<?php if ( !empty($login_uri) || !empty($login_uri_2) ) { ?>
|
||||
|
||||
114
client_logs.php
114
client_logs.php
@@ -1,114 +0,0 @@
|
||||
<?php
|
||||
|
||||
// Default Column Sortby Filter
|
||||
$sort = "log_id";
|
||||
$order = "DESC";
|
||||
|
||||
require_once "inc_all_client.php";
|
||||
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM logs
|
||||
LEFT JOIN users ON log_user_id = user_id
|
||||
WHERE (log_type LIKE '%$q%' OR log_action LIKE '%$q%' OR log_description LIKE '%$q%' OR log_ip LIKE '%$q%' OR log_user_agent LIKE '%$q%' OR user_name LIKE '%$q%')
|
||||
AND log_client_id = $client_id
|
||||
ORDER BY $sort $order LIMIT $record_from, $record_to"
|
||||
);
|
||||
|
||||
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
?>
|
||||
|
||||
<div class="card card-dark">
|
||||
<div class="card-header py-3">
|
||||
<h3 class="card-title"><i class="fa fa-fw fa-history mr-2"></i>Audit Logs</h3>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form autocomplete="off">
|
||||
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="input-group mb-3 mb-md-0">
|
||||
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search Logs">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-dark"><i class="fa fa-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
<div class="table-responsive-sm border">
|
||||
<table class="table table-hover">
|
||||
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
|
||||
<tr>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_created_at&order=<?php echo $disp; ?>">Timestamp</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=user_name&order=<?php echo $disp; ?>">User</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_type&order=<?php echo $disp; ?>">Type</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_action&order=<?php echo $disp; ?>">Action</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_description&order=<?php echo $disp; ?>">Description</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_ip&order=<?php echo $disp; ?>">IP Address</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_user_agent&order=<?php echo $disp; ?>">User Agent</a></th>
|
||||
<th><a class="text-dark" href="?<?php echo $url_query_strings_sort; ?>&sort=log_entity_id&order=<?php echo $disp; ?>">Entity ID</a></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
$log_id = intval($row['log_id']);
|
||||
$log_type = nullable_htmlentities($row['log_type']);
|
||||
$log_action = nullable_htmlentities($row['log_action']);
|
||||
$log_description = nullable_htmlentities($row['log_description']);
|
||||
$log_ip = nullable_htmlentities($row['log_ip']);
|
||||
$log_user_agent = nullable_htmlentities($row['log_user_agent']);
|
||||
$log_user_os = getOS($log_user_agent);
|
||||
$log_user_browser = getWebBrowser($log_user_agent);
|
||||
$log_created_at = nullable_htmlentities($row['log_created_at']);
|
||||
$user_id = intval($row['user_id']);
|
||||
$user_name = nullable_htmlentities($row['user_name']);
|
||||
if (empty($user_name)) {
|
||||
$user_name_display = "-";
|
||||
} else {
|
||||
$user_name_display = $user_name;
|
||||
}
|
||||
$log_entity_id = intval($row['log_entity_id']);
|
||||
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td><?php echo $log_created_at; ?></td>
|
||||
<td><?php echo $user_name_display; ?></td>
|
||||
<td><?php echo $log_type; ?></td>
|
||||
<td><?php echo $log_action; ?></td>
|
||||
<td><?php echo $log_description; ?></td>
|
||||
<td><?php echo $log_ip; ?></td>
|
||||
<td><?php echo "$log_user_os<br>$log_user_browser"; ?></td>
|
||||
<td><?php echo $log_entity_id; ?></td>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php require_once "pagination.php";
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
require_once "footer.php";
|
||||
|
||||
@@ -7,7 +7,7 @@ $sql_recent_activities = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT * FROM logs
|
||||
WHERE log_client_id = $client_id
|
||||
ORDER BY log_created_at DESC LIMIT 10"
|
||||
ORDER BY log_created_at DESC LIMIT 5"
|
||||
);
|
||||
|
||||
$sql_important_contacts = mysqli_query(
|
||||
@@ -16,7 +16,7 @@ $sql_important_contacts = mysqli_query(
|
||||
WHERE contact_client_id = $client_id
|
||||
AND (contact_important = 1 OR contact_billing = 1 OR contact_technical = 1 OR contact_primary = 1)
|
||||
AND contact_archived_at IS NULL
|
||||
ORDER BY contact_primary DESC, contact_name DESC"
|
||||
ORDER BY contact_primary DESC, contact_name DESC LIMIT 5"
|
||||
);
|
||||
|
||||
$sql_recent_tickets = mysqli_query(
|
||||
@@ -33,6 +33,16 @@ $sql_recent_logins = mysqli_query(
|
||||
ORDER BY login_updated_at DESC LIMIT 5"
|
||||
);
|
||||
|
||||
$sql_shared_items = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT * FROM shared_items
|
||||
WHERE item_client_id = $client_id
|
||||
AND item_active = 1
|
||||
AND item_views != item_view_limit
|
||||
AND item_expire_at > NOW()
|
||||
ORDER BY item_created_at DESC LIMIT 5"
|
||||
);
|
||||
|
||||
/*
|
||||
* EXPIRING/ACTION ITEMS
|
||||
*/
|
||||
@@ -44,7 +54,7 @@ $sql_stale_tickets = mysqli_query(
|
||||
WHERE ticket_client_id = $client_id
|
||||
AND ticket_updated_at < CURRENT_DATE - INTERVAL 3 DAY
|
||||
AND ticket_closed_at IS NULL
|
||||
ORDER BY ticket_updated_at DESC"
|
||||
ORDER BY ticket_updated_at DESC LIMIT 5"
|
||||
);
|
||||
|
||||
// Get Domains Expiring
|
||||
@@ -55,7 +65,7 @@ $sql_domains_expiring = mysqli_query(
|
||||
AND domain_expire IS NOT NULL
|
||||
AND domain_archived_at IS NULL
|
||||
AND domain_expire < CURRENT_DATE + INTERVAL 90 DAY
|
||||
ORDER BY domain_expire DESC"
|
||||
ORDER BY domain_expire DESC LIMIT 5"
|
||||
);
|
||||
|
||||
// Get Licenses Expiring
|
||||
@@ -66,7 +76,7 @@ $sql_licenses_expiring = mysqli_query(
|
||||
AND software_expire IS NOT NULL
|
||||
AND software_archived_at IS NULL
|
||||
AND software_expire < CURRENT_DATE + INTERVAL 90 DAY
|
||||
ORDER BY software_expire DESC"
|
||||
ORDER BY software_expire DESC LIMIT 5"
|
||||
);
|
||||
|
||||
// Get Asset Warranties Expiring
|
||||
@@ -77,7 +87,7 @@ $sql_asset_warranties_expiring = mysqli_query(
|
||||
AND asset_warranty_expire IS NOT NULL
|
||||
AND asset_archived_at IS NULL
|
||||
AND asset_warranty_expire < CURRENT_DATE + INTERVAL 90 DAY
|
||||
ORDER BY asset_warranty_expire DESC"
|
||||
ORDER BY asset_warranty_expire DESC LIMIT 5"
|
||||
);
|
||||
|
||||
// Get Assets Retiring
|
||||
@@ -88,7 +98,7 @@ $sql_asset_retire = mysqli_query(
|
||||
AND asset_install_date IS NOT NULL
|
||||
AND asset_archived_at IS NULL
|
||||
AND asset_install_date + INTERVAL 7 YEAR < CURRENT_DATE + INTERVAL 90 DAY
|
||||
ORDER BY asset_install_date DESC"
|
||||
ORDER BY asset_install_date DESC LIMIT 5"
|
||||
);
|
||||
|
||||
?>
|
||||
@@ -97,7 +107,7 @@ $sql_asset_retire = mysqli_query(
|
||||
|
||||
<!-- Notes -->
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="col-md-4">
|
||||
|
||||
<div class="card card-dark mb-3">
|
||||
<div class="card-header">
|
||||
@@ -159,6 +169,71 @@ $sql_asset_retire = mysqli_query(
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<?php if (mysqli_num_rows($sql_shared_items) > 0) { ?>
|
||||
|
||||
<div class="col-md-4">
|
||||
|
||||
<div class="card card-dark mb-3">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title"><i class="fa fa-fw fa-share-square mr-2"></i>Shared Items</h5>
|
||||
</div>
|
||||
<div class="card-body p-2">
|
||||
<table class="table table-borderless table-sm">
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_shared_items)) {
|
||||
$item_id = intval($row['item_id']);
|
||||
$item_active = nullable_htmlentities($row['item_active']);
|
||||
$item_key = nullable_htmlentities($row['item_key']);
|
||||
$item_type = nullable_htmlentities($row['item_type']);
|
||||
$item_related_id = intval($row['item_related_id']);
|
||||
$item_note = nullable_htmlentities($row['item_note']);
|
||||
$item_views = nullable_htmlentities($row['item_views']);
|
||||
$item_view_limit = nullable_htmlentities($row['item_view_limit']);
|
||||
$item_created_at = nullable_htmlentities($row['item_created_at']);
|
||||
$item_expire_at = nullable_htmlentities($row['item_expire_at']);
|
||||
$item_expire_at_human = timeAgo($row['item_expire_at']);
|
||||
|
||||
if ($item_type == 'Login') {
|
||||
$share_item_sql = mysqli_query($mysqli, "SELECT login_name FROM logins WHERE login_id = $item_related_id AND login_client_id = $client_id");
|
||||
$share_item = mysqli_fetch_array($share_item_sql);
|
||||
$item_name = nullable_htmlentities($share_item['login_name']);
|
||||
$item_icon = "fas fa-key";
|
||||
} elseif ($item_type == 'Document') {
|
||||
$share_item_sql = mysqli_query($mysqli, "SELECT document_name FROM documents WHERE document_id = $item_related_id AND document_client_id = $client_id");
|
||||
$share_item = mysqli_fetch_array($share_item_sql);
|
||||
$item_name = nullable_htmlentities($share_item['document_name']);
|
||||
$item_icon = "fas fa-folder";
|
||||
} elseif ($item_type == 'File') {
|
||||
$share_item_sql = mysqli_query($mysqli, "SELECT file_name FROM files WHERE file_id = $item_related_id AND file_client_id = $client_id");
|
||||
$share_item = mysqli_fetch_array($share_item_sql);
|
||||
$item_name = nullable_htmlentities($share_item['file_name']);
|
||||
$item_icon = "fas fa-paperclip";
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td title="<?php echo $item_type; ?>"><i class="<?php echo $item_icon; ?> mr-2 text-secondary"></i><?php echo $item_name; ?></td>
|
||||
<td>Views: <?php echo "$item_views / $item_view_limit" ?></td>
|
||||
<td title="Expires at <?php echo $item_expire_at; ?>">Expires <?php echo $item_expire_at_human ?></td>
|
||||
<td title="Deactivate Link">
|
||||
<a class="text-danger confirm-link" href="post.php?deactivate_shared_item=<?php echo $item_id; ?>">
|
||||
<i class="fas fa-fw fa-calendar-times mr-2"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<?php
|
||||
if (mysqli_num_rows($sql_domains_expiring) > 0
|
||||
|| mysqli_num_rows($sql_asset_warranties_expiring) > 0
|
||||
@@ -303,7 +378,7 @@ $sql_asset_retire = mysqli_query(
|
||||
|
||||
<!-- Recent Activities -->
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="col-md-4">
|
||||
|
||||
<div class="card card-dark mb-3">
|
||||
<div class="card-header">
|
||||
@@ -332,6 +407,11 @@ $sql_asset_retire = mysqli_query(
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php if ($session_user_role == 3) { ?>
|
||||
<div class="card-footer">
|
||||
<a href="admin_logs.php?client=<?php echo $client_id; ?>">See More...</a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-sort-numeric-up-alt"></i></span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="units" placeholder="Number of Units" min="1" max="44" required>
|
||||
<input type="number" class="form-control" name="units" placeholder="Number of Units" min="1" max="70" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-sort-numeric-up-alt"></i></span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="units" placeholder="Number of Units" min="1" max="44" value="<?php echo $rack_units; ?>" required>
|
||||
<input type="number" class="form-control" name="units" placeholder="Number of Units" min="1" max="70" value="<?php echo $rack_units; ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
<?php
|
||||
|
||||
// Default Column Sortby Filter
|
||||
$sort = "item_created_at";
|
||||
$order = "DESC";
|
||||
|
||||
require_once "inc_all_client.php";
|
||||
|
||||
|
||||
//Rebuild URL
|
||||
$url_query_strings_sort = http_build_query($get_copy);
|
||||
|
||||
$sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT SQL_CALC_FOUND_ROWS * FROM shared_items
|
||||
WHERE item_client_id = $client_id
|
||||
AND item_active = '1'
|
||||
AND item_views != item_view_limit
|
||||
AND item_expire_at > NOW()
|
||||
AND (item_note LIKE '%$q%') ORDER BY $sort $order LIMIT $record_from, $record_to"
|
||||
);
|
||||
|
||||
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
?>
|
||||
|
||||
<div class="card card-dark">
|
||||
<div class="card-header py-3">
|
||||
<h3 class="card-title"><i class="fa fa-fw fa-share mr-2"></i>Shared Items (Links)</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form autocomplete="off">
|
||||
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="input-group mb-3 mb-md-0">
|
||||
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(nullable_htmlentities($q)); } ?>" placeholder="Search Shared Items">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-dark"><i class="fa fa-search"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
<div class="table-responsive-sm">
|
||||
<table class="table table-striped table-borderless table-hover">
|
||||
<thead class="text-dark <?php if ($num_rows[0] == 0) { echo "d-none"; } ?>">
|
||||
<tr>
|
||||
<th>Item Name</th>
|
||||
<th>Item Type</th>
|
||||
<th>Share Note</th>
|
||||
<th>Views</th>
|
||||
<th>Expires</th>
|
||||
<th class="text-center">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
$item_id = intval($row['item_id']);
|
||||
$item_active = nullable_htmlentities($row['item_active']);
|
||||
$item_key = nullable_htmlentities($row['item_key']);
|
||||
$item_type = nullable_htmlentities($row['item_type']);
|
||||
$item_related_id = intval($row['item_related_id']);
|
||||
$item_note = nullable_htmlentities($row['item_note']);
|
||||
$item_views = nullable_htmlentities($row['item_views']);
|
||||
$item_view_limit = nullable_htmlentities($row['item_view_limit']);
|
||||
$item_created_at = nullable_htmlentities($row['item_created_at']);
|
||||
$item_expire_at = nullable_htmlentities($row['item_expire_at']);
|
||||
|
||||
if ($item_type == 'Login') {
|
||||
$share_item_sql = mysqli_query($mysqli, "SELECT login_name FROM logins WHERE login_id = '$item_related_id' AND login_client_id = '$client_id'");
|
||||
$share_item = mysqli_fetch_array($share_item_sql);
|
||||
$item_name = nullable_htmlentities($share_item['login_name']);
|
||||
} elseif ($item_type == 'Document') {
|
||||
$share_item_sql = mysqli_query($mysqli, "SELECT document_name FROM documents WHERE document_id = '$item_related_id' AND document_client_id = '$client_id'");
|
||||
$share_item = mysqli_fetch_array($share_item_sql);
|
||||
$item_name = nullable_htmlentities($share_item['document_name']);
|
||||
} elseif ($item_type == 'File') {
|
||||
$share_item_sql = mysqli_query($mysqli, "SELECT file_name FROM files WHERE file_id = '$item_related_id' AND file_client_id = '$client_id'");
|
||||
$share_item = mysqli_fetch_array($share_item_sql);
|
||||
$item_name = nullable_htmlentities($share_item['file_name']);
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo $item_name; ?></td>
|
||||
<td><?php echo $item_type ?></td>
|
||||
<td><?php echo $item_note ?></td>
|
||||
<td><?php echo "$item_views / $item_view_limit" ?></td>
|
||||
<td><?php echo $item_expire_at ?></td>
|
||||
<td>
|
||||
<?php if ($session_user_role == 3) { ?>
|
||||
<div class="dropdown dropleft text-center">
|
||||
<button class="btn btn-secondary btn-sm" type="button" data-toggle="dropdown">
|
||||
<i class="fas fa-ellipsis-h"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item text-danger confirm-link" href="post.php?deactivate_shared_item=<?php echo $item_id; ?>">
|
||||
<i class="fas fa-fw fa-times mr-2"></i>Deactivate
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php require_once "pagination.php";
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
require_once "footer.php";
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
<aside class="main-sidebar sidebar-dark-<?php echo nullable_htmlentities($config_theme); ?> d-print-none">
|
||||
|
||||
<a class="brand-link pb-1 mt-1" href="clients.php">
|
||||
<p class="h5"><i class="nav-icon fas fa-arrow-left ml-3 mr-2"></i> Back | <strong><?php if($client_abbreviation) { echo $client_abbreviation; } else { echo shortenClient($client_name); } ?></strong></p>
|
||||
<p class="h5">
|
||||
<i class="nav-icon fas fa-arrow-left ml-3 mr-2"></i>
|
||||
Back |
|
||||
<strong>
|
||||
<?php if($client_abbreviation) { echo $client_abbreviation; } else { echo shortenClient($client_name); } ?>
|
||||
</strong>
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<!-- Sidebar -->
|
||||
@@ -22,7 +28,7 @@
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="client_contacts.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "client_contacts.php" || basename($_SERVER["PHP_SELF"]) == "client_contact_details.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-users"></i>
|
||||
<i class="nav-icon fas fa-address-book"></i>
|
||||
<p>
|
||||
Contacts
|
||||
<?php
|
||||
@@ -183,7 +189,7 @@
|
||||
|
||||
<?php
|
||||
if ($num_certificates > 0) { ?>
|
||||
<span class="right badge <?php if ($num_certs_expiring > 0) { ?> badge-warning <?php } ?> text-light"><?php echo $num_certificates; ?></span>
|
||||
<span class="right badge <?php if ($num_certs_expiring > 0) { ?> badge-warning text-dark <?php } ?> text-light"><?php echo $num_certificates; ?></span>
|
||||
<?php } ?>
|
||||
</p>
|
||||
</a>
|
||||
@@ -197,7 +203,7 @@
|
||||
|
||||
<?php
|
||||
if ($num_domains > 0) { ?>
|
||||
<span class="right badge <?php if ($num_domains_expiring > 0) { ?> badge-warning <?php } ?> text-light"><?php echo $num_domains; ?></span>
|
||||
<span class="right badge <?php if ($num_domains_expiring > 0) { ?> badge-warning text-dark<?php } ?> <?php if ($num_domains_expired > 0) { ?> badge-danger <?php } ?> text-white"><?php echo $num_domains; ?></span>
|
||||
<?php } ?>
|
||||
</p>
|
||||
</a>
|
||||
@@ -302,15 +308,6 @@
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="client_statement.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "client_statement.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-file-invoice-dollar"></i>
|
||||
<p>
|
||||
Statement
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="client_trips.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "client_trips.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-route"></i>
|
||||
@@ -326,41 +323,6 @@
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<li class="nav-header mt-3">MISC</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="client_bulk_mail.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "client_bulk_mail.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-envelope-open"></i>
|
||||
<p>Bulk Mail</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="client_shared_items.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "client_shared_items.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-share"></i>
|
||||
<p>
|
||||
Shared Links
|
||||
<?php
|
||||
if ($num_shared_links > 0) { ?>
|
||||
<span class="right badge text-light"><?php echo $num_shared_links; ?></span>
|
||||
<?php } ?>
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a href="client_logs.php?client_id=<?php echo $client_id; ?>" class="nav-link <?php if (basename($_SERVER["PHP_SELF"]) == "client_logs.php") { echo "active"; } ?>">
|
||||
<i class="nav-icon fas fa-history"></i>
|
||||
<p>
|
||||
Audit Logs
|
||||
<?php
|
||||
if ($num_logs > 0) { ?>
|
||||
<span class="right badge text-light"><?php echo $num_logs; ?></span>
|
||||
<?php } ?>
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</nav>
|
||||
<!-- /.sidebar-menu -->
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
|
||||
|
||||
<?php
|
||||
$sql_assets_select = mysqli_query($mysqli, "SELECT * FROM assets LEFT JOIN contacts ON asset_contact_id = contact_id WHERE (asset_archived_at > '$software_created_at' OR asset_archived_at IS NULL) AND asset_client_id = $client_id ORDER BY asset_archived_at ASC, asset_name ASC");
|
||||
$sql_assets_select = mysqli_query($mysqli, "SELECT * FROM assets LEFT JOIN contacts ON asset_contact_id = contact_id WHERE asset_archived_at IS NULL AND asset_client_id = $client_id ORDER BY asset_archived_at ASC, asset_name ASC");
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_assets_select)) {
|
||||
$asset_id_select = intval($row['asset_id']);
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
require_once "inc_all_client.php";
|
||||
|
||||
|
||||
if (isset($_GET['client_id'])) {
|
||||
|
||||
$client_id = intval($_GET['client_id']);
|
||||
|
||||
$sql_client_details = "
|
||||
SELECT
|
||||
client_name,
|
||||
client_type,
|
||||
client_website,
|
||||
client_net_terms
|
||||
FROM
|
||||
clients
|
||||
WHERE
|
||||
client_id = $client_id";
|
||||
|
||||
$result_client_details = mysqli_query($mysqli, $sql_client_details);
|
||||
$row_client_details = mysqli_fetch_assoc($result_client_details);
|
||||
|
||||
$client_name = nullable_htmlentities($row_client_details['client_name']);
|
||||
$client_type = nullable_htmlentities($row_client_details['client_type']);
|
||||
$client_website = nullable_htmlentities($row_client_details['client_website']);
|
||||
$client_net_terms = intval($row_client_details['client_net_terms']);
|
||||
|
||||
$sql_client_unpaid_invoices = "
|
||||
SELECT
|
||||
invoice_id,
|
||||
invoice_number,
|
||||
invoice_prefix,
|
||||
invoice_date,
|
||||
invoice_due,
|
||||
invoice_amount
|
||||
FROM
|
||||
invoices
|
||||
WHERE
|
||||
invoice_client_id = $client_id
|
||||
AND invoice_status NOT LIKE 'Draft'
|
||||
AND invoice_status NOT LIKE 'Cancelled'
|
||||
AND invoice_status NOT LIKE 'Paid'";
|
||||
|
||||
$result_client_unpaid_invoices = mysqli_query($mysqli, $sql_client_unpaid_invoices);
|
||||
|
||||
$currency_code = getSettingValue($mysqli, "company_currency");
|
||||
|
||||
?>
|
||||
|
||||
<ol class="breadcrumb d-print-none">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="clients.php">Clients</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="client_invoices.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div class="card card-dark">
|
||||
<div class="card-header py-2">
|
||||
<h3 class="card-title mt-2"><i class="fas fa-fw fa-balance-scale mr-2"></i>Statement for <?php echo $client_name ?></h3>
|
||||
<div class="card-tools">
|
||||
<button type="button" class="btn btn-primary d-print-none" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div>
|
||||
<div class="table-responsive-sm">
|
||||
<table class="table table-sm">
|
||||
<!-- Past Due Payments -->
|
||||
<thead class="text-dark">
|
||||
<tr>
|
||||
<th>Invoice Number</th>
|
||||
<th>Date</th>
|
||||
<th>Due Date</th>
|
||||
<th>Amount</th>
|
||||
<th>Balance</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
while ($row = mysqli_fetch_assoc($result_client_unpaid_invoices)) {
|
||||
$invoice_number = intval($row['invoice_number']);
|
||||
$invoice_id = intval($row['invoice_id']);
|
||||
$invoice_prefix = nullable_htmlentities($row['invoice_prefix']);
|
||||
$invoice_date = nullable_htmlentities($row['invoice_date']);
|
||||
$invoice_amount = floatval($row['invoice_amount']);
|
||||
$invoice_amount_formatted = numfmt_format_currency($currency_format, $invoice_amount, $currency_code);
|
||||
$invoice_url = "invoice.php?invoice_id=$invoice_id";
|
||||
$invoice_due = nullable_htmlentities($row['invoice_due']);
|
||||
|
||||
$invoice_balance = floatval(calculateInvoiceBalance($mysqli, $invoice_id));
|
||||
$invoice_balance_formatted = numfmt_format_currency($currency_format, $invoice_balance, $currency_code);
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<a href="<?php echo $invoice_url; ?>" target="_blank"><?php echo $invoice_prefix . $invoice_number; ?></a>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $invoice_date; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $invoice_due; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $invoice_amount_formatted; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $invoice_balance_formatted; ?>
|
||||
</td>
|
||||
<?php
|
||||
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="table-responsive-sm">
|
||||
<!-- Previous Payments -->
|
||||
<table class="table table-sm">
|
||||
<thead class="text-dark">
|
||||
<tr>
|
||||
<th>Payment Reference</th>
|
||||
<th>Payment Date</th>
|
||||
<th>Payment Amount</th>
|
||||
<th>Invoice Number</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$sql_client_payments = "
|
||||
SELECT
|
||||
payments.payment_date,
|
||||
payments.payment_amount,
|
||||
payments.payment_reference,
|
||||
invoices.invoice_number,
|
||||
invoices.invoice_prefix,
|
||||
invoices.invoice_client_id
|
||||
FROM
|
||||
payments
|
||||
LEFT JOIN
|
||||
invoices ON payments.payment_invoice_id = invoices.invoice_id
|
||||
WHERE
|
||||
invoice_client_id = $client_id
|
||||
AND payment_archived_at IS NULL
|
||||
ORDER BY
|
||||
payment_date DESC";
|
||||
|
||||
$result_client_payments = mysqli_query($mysqli, $sql_client_payments);
|
||||
|
||||
while ($row = mysqli_fetch_assoc($result_client_payments)) {
|
||||
$payment_date = nullable_htmlentities($row['payment_date']);
|
||||
$payment_amount = floatval($row['payment_amount']);
|
||||
$payment_reference = nullable_htmlentities($row['payment_reference']);
|
||||
$invoice_number = nullable_htmlentities($row['invoice_prefix'].$row['invoice_number']);
|
||||
$payment_amount_formatted = numfmt_format_currency($currency_format, $payment_amount, $currency_code);
|
||||
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<?php echo $payment_reference; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $payment_date; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $payment_amount_formatted; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo $invoice_number; ?>
|
||||
</td>
|
||||
<?php
|
||||
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once "footer.php";
|
||||
|
||||
}
|
||||
?>
|
||||
@@ -9,11 +9,11 @@ require_once "inc_all_client.php";
|
||||
|
||||
if (isset($_GET['status']) && ($_GET['status']) == 'Closed') {
|
||||
$status = 'Closed';
|
||||
$ticket_status_snippet = "ticket_closed_at IS NOT NULL";
|
||||
$ticket_status_snippet = "ticket_resolved_at IS NOT NULL";
|
||||
} else {
|
||||
// Default - Show open tickets
|
||||
$status = 'Open';
|
||||
$ticket_status_snippet = "ticket_closed_at IS NULL";
|
||||
$ticket_status_snippet = "ticket_resolved_at IS NULL";
|
||||
}
|
||||
|
||||
if (isset($_GET['billable']) && ($_GET['billable']) == '1') {
|
||||
@@ -49,12 +49,12 @@ $sql = mysqli_query(
|
||||
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
|
||||
//Get Total tickets open
|
||||
$sql_total_tickets_open = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS total_tickets_open FROM tickets WHERE ticket_client_id = $client_id AND ticket_closed_at IS NULL");
|
||||
$sql_total_tickets_open = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS total_tickets_open FROM tickets WHERE ticket_client_id = $client_id AND ticket_resolved_at IS NULL");
|
||||
$row = mysqli_fetch_array($sql_total_tickets_open);
|
||||
$total_tickets_open = intval($row['total_tickets_open']);
|
||||
|
||||
//Get Total tickets closed
|
||||
$sql_total_tickets_closed = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS total_tickets_closed FROM tickets WHERE ticket_client_id = $client_id AND ticket_closed_at IS NOT NULL");
|
||||
$sql_total_tickets_closed = mysqli_query($mysqli, "SELECT COUNT(ticket_id) AS total_tickets_closed FROM tickets WHERE ticket_client_id = $client_id AND ticket_resolved_at IS NOT NULL");
|
||||
$row = mysqli_fetch_array($sql_total_tickets_closed);
|
||||
$total_tickets_closed = intval($row['total_tickets_closed']);
|
||||
|
||||
@@ -215,7 +215,7 @@ $total_tickets_closed = intval($row['total_tickets_closed']);
|
||||
|
||||
?>
|
||||
|
||||
<tr class="<?php if(empty($ticket_reply_created_at)) { echo "text-bold"; }?> <?php if ($ticket_reply_type == "Client") { echo "table-warning"; } ?>">
|
||||
<tr class="<?php if(empty($ticket_reply_created_at)) { echo "text-bold"; }?> <?php if (empty($ticket_closed_at) && $ticket_reply_type == "Client") { echo "table-warning"; } ?>">
|
||||
|
||||
<!-- Ticket Number -->
|
||||
<td>
|
||||
@@ -263,15 +263,15 @@ $total_tickets_closed = intval($row['total_tickets_closed']);
|
||||
|
||||
<!-- Ticket Last Response -->
|
||||
<td>
|
||||
<div title="<?php echo $ticket_reply_created_at; ?>"><?php echo $ticket_reply_created_at_time_ago; ?></div>
|
||||
<div><?php echo $ticket_reply_by_display; ?></div>
|
||||
<?php if (!empty($ticket_reply_created_at)) { ?>
|
||||
<div title="<?php echo $ticket_reply_created_at; ?>"><?php echo $ticket_reply_created_at_time_ago; ?></div>
|
||||
<div><?php echo $ticket_reply_by_display; ?></div>
|
||||
<?php } ?>
|
||||
</td>
|
||||
|
||||
<!-- Ticket Created At -->
|
||||
<td>
|
||||
<td title="<?php echo $ticket_created_at; ?>">
|
||||
<?php echo $ticket_created_at_time_ago; ?>
|
||||
<br>
|
||||
<small class="text-secondary"><?php echo $ticket_created_at; ?></small>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
|
||||
@@ -101,6 +101,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"></button>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#importClientModal">
|
||||
<i class="fa fa-fw fa-upload mr-2"></i>Import
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item text-dark" href="#" data-toggle="modal" data-target="#exportClientModal">
|
||||
<i class="fa fa-fw fa-download mr-2"></i>Export
|
||||
</a>
|
||||
@@ -351,7 +355,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<a class="font-weight-bold" href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a>
|
||||
<a data-toggle="tooltip" data-placement="right" title="Client ID: <?php echo $client_id; ?>" class="font-weight-bold" href="client_overview.php?client_id=<?php echo $client_id; ?>"><?php echo $client_name; ?></a>
|
||||
|
||||
<?php
|
||||
if (!empty($client_type)) {
|
||||
@@ -466,6 +470,8 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
||||
<?php
|
||||
require_once "client_add_modal.php";
|
||||
|
||||
require_once "client_import_modal.php";
|
||||
|
||||
require_once "client_export_modal.php";
|
||||
|
||||
require_once "footer.php";
|
||||
|
||||
99
cron.php
99
cron.php
@@ -51,7 +51,6 @@ $config_ticket_prefix = sanitizeInput($row['config_ticket_prefix']);
|
||||
$config_ticket_from_name = sanitizeInput($row['config_ticket_from_name']);
|
||||
$config_ticket_from_email = sanitizeInput($row['config_ticket_from_email']);
|
||||
$config_ticket_client_general_notifications = intval($row['config_ticket_client_general_notifications']);
|
||||
$config_ticket_autoclose = intval($row['config_ticket_autoclose']);
|
||||
$config_ticket_autoclose_hours = intval($row['config_ticket_autoclose_hours']);
|
||||
$config_ticket_new_ticket_notification_email = sanitizeInput($row['config_ticket_new_ticket_notification_email']);
|
||||
|
||||
@@ -380,86 +379,32 @@ if (mysqli_num_rows($sql_scheduled_tickets) > 0) {
|
||||
//mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Cron', log_action = 'Task', log_description = 'Cron created sent out recurring tickets'");
|
||||
|
||||
|
||||
// AUTO CLOSE TICKET - CLOSE
|
||||
// Automatically silently closes tickets 22 hrs after the last chase
|
||||
// TICKET RESOLUTION/CLOSURE PROCESS
|
||||
// Changes tickets status from 'Resolved' >> 'Closed' after a defined interval
|
||||
|
||||
// Check to make sure auto-close is enabled
|
||||
if ($config_ticket_autoclose == 1) {
|
||||
$sql_tickets_to_chase = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT * FROM tickets
|
||||
WHERE ticket_status = 4
|
||||
AND ticket_updated_at < NOW() - INTERVAL $config_ticket_autoclose_hours HOUR"
|
||||
);
|
||||
$sql_resolved_tickets_to_close = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT * FROM tickets
|
||||
WHERE ticket_status = 4
|
||||
AND ticket_updated_at < NOW() - INTERVAL $config_ticket_autoclose_hours HOUR"
|
||||
);
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_tickets_to_chase)) {
|
||||
while ($row = mysqli_fetch_array($sql_resolved_tickets_to_close)) {
|
||||
|
||||
$ticket_id = $row['ticket_id'];
|
||||
$ticket_prefix = sanitizeInput($row['ticket_prefix']);
|
||||
$ticket_number = intval($row['ticket_number']);
|
||||
$ticket_subject = sanitizeInput($row['ticket_subject']);
|
||||
$ticket_status = sanitizeInput($row['ticket_status']);
|
||||
$ticket_assigned_to = sanitizeInput($row['ticket_assigned_to']);
|
||||
$client_id = intval($row['ticket_client_id']);
|
||||
$ticket_id = $row['ticket_id'];
|
||||
$ticket_prefix = sanitizeInput($row['ticket_prefix']);
|
||||
$ticket_number = intval($row['ticket_number']);
|
||||
$ticket_subject = sanitizeInput($row['ticket_subject']);
|
||||
$ticket_status = sanitizeInput($row['ticket_status']);
|
||||
$ticket_assigned_to = sanitizeInput($row['ticket_assigned_to']);
|
||||
$client_id = intval($row['ticket_client_id']);
|
||||
|
||||
mysqli_query($mysqli,"UPDATE tickets SET ticket_status = 5, ticket_closed_at = NOW(), ticket_closed_by = $ticket_assigned_to WHERE ticket_id = $ticket_id");
|
||||
mysqli_query($mysqli,"UPDATE tickets SET ticket_status = 5, ticket_closed_at = NOW(), ticket_closed_by = $ticket_assigned_to WHERE ticket_id = $ticket_id");
|
||||
|
||||
//Logging
|
||||
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Closed', log_description = '$ticket_prefix$ticket_number auto closed', log_entity_id = $ticket_id");
|
||||
//Logging
|
||||
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket', log_action = 'Closed', log_description = '$ticket_prefix$ticket_number auto closed', log_entity_id = $ticket_id");
|
||||
|
||||
}
|
||||
|
||||
|
||||
// AUTO CLOSE TICKETS - CHASE
|
||||
// Automatically sends a chaser email after approx 48 hrs/2 days
|
||||
$sql_tickets_to_chase = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT contact_name, contact_email, ticket_id, ticket_prefix, ticket_number, ticket_subject, ticket_status, ticket_client_id FROM tickets
|
||||
LEFT JOIN clients ON ticket_client_id = client_id
|
||||
LEFT JOIN contacts ON ticket_contact_id = contact_id
|
||||
WHERE ticket_status = 4
|
||||
AND ticket_updated_at < NOW() - INTERVAL 48 HOUR"
|
||||
);
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_tickets_to_chase)) {
|
||||
|
||||
$contact_name = sanitizeInput($row['contact_name']);
|
||||
$contact_email = sanitizeInput($row['contact_email']);
|
||||
$ticket_id = intval($row['ticket_id']);
|
||||
$ticket_prefix = sanitizeInput($row['ticket_prefix']);
|
||||
$ticket_number = intval($row['ticket_number']);
|
||||
$ticket_subject = sanitizeInput($row['ticket_subject']);
|
||||
$ticket_status = sanitizeInput( getTicketStatusName($row['ticket_status']));
|
||||
$client_id = intval($row['ticket_client_id']);
|
||||
|
||||
$sql_ticket_reply = mysqli_query($mysqli, "SELECT ticket_reply FROM ticket_replies WHERE ticket_reply_type = 'Public' AND ticket_reply_ticket_id = $ticket_id ORDER BY ticket_reply_created_at DESC LIMIT 1");
|
||||
$ticket_reply_row = mysqli_fetch_array($sql_ticket_reply);
|
||||
$ticket_reply = $ticket_reply_row['ticket_reply'];
|
||||
|
||||
$subject = "Ticket pending closure - [$ticket_prefix$ticket_number] - $ticket_subject";
|
||||
|
||||
$body = "<i style=\'color: #808080\'>##- Please type your reply above this line -##</i><br><br>Hello, $contact_name<br><br>This is an automatic friendly reminder that your ticket regarding \"$ticket_subject\" will be closed, unless you respond.<br><br>--------------------------------<br>$ticket_reply--------------------------------<br><br>If your issue is resolved, you can ignore this email - the ticket will automatically close. If you need further assistance, please respond to this email. <br><br>Ticket: $ticket_prefix$ticket_number<br>Subject: $ticket_subject<br>Status: $ticket_status <br>Portal: https://$config_base_url/portal/ticket.php?id=$ticket_id<br><br>--<br>$company_name - Support<br>$config_ticket_from_email<br>$company_phone";
|
||||
|
||||
$data = [
|
||||
[
|
||||
'from' => $config_ticket_from_email,
|
||||
'from_name' => $config_ticket_from_name,
|
||||
'recipient' => $contact_email,
|
||||
'recipient_name' => $contact_name,
|
||||
'subject' => $subject,
|
||||
'body' => $body
|
||||
]
|
||||
];
|
||||
$mail = addToMailQueue($mysqli, $data);
|
||||
|
||||
if ($mail !== true) {
|
||||
mysqli_query($mysqli,"INSERT INTO notifications SET notification_type = 'Mail', notification = 'Failed to send email to $contact_email'");
|
||||
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Mail', log_action = 'Error', log_description = 'Failed to send email to $contact_email regarding $subject. $mail'");
|
||||
}
|
||||
|
||||
mysqli_query($mysqli,"INSERT INTO logs SET log_type = 'Ticket Reply', log_action = 'Create', log_description = 'Auto close chaser email sent to $contact_email for ticket $ticket_prefix$ticket_number - $ticket_subject', log_client_id = $client_id");
|
||||
|
||||
}
|
||||
//TODO: Add client notifs if $config_ticket_client_general_notifications is on
|
||||
}
|
||||
|
||||
if ($config_send_invoice_reminders == 1) {
|
||||
@@ -518,7 +463,7 @@ if ($config_send_invoice_reminders == 1) {
|
||||
|
||||
mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Invoice Overdue', notification = 'Invoice $invoice_prefix$invoice_number for $client_name in the amount of $invoice_amount is overdue by $day days', notification_action = 'invoice.php?invoice_id=$invoice_id', notification_client_id = $client_id, notification_entity_id = $invoice_id");
|
||||
|
||||
$subject = "$company_name Overdue Invoice $invoice_prefix$invoice_number";
|
||||
$subject = "Overdue Invoice $invoice_prefix$invoice_number";
|
||||
$body = "Hello $contact_name,<br><br>Our records indicate that we have not yet received payment for the invoice $invoice_prefix$invoice_number. We kindly request that you submit your payment as soon as possible. If you have any questions or concerns, please do not hesitate to contact us at $company_email or $company_phone.
|
||||
<br><br>
|
||||
Kindly review the invoice details mentioned below.<br><br>Invoice: $invoice_prefix$invoice_number<br>Issue Date: $invoice_date<br>Total: " . numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code) . "<br>Due Date: $invoice_due<br>Over Due By: $day Days<br><br><br>To view your invoice, please click <a href=\'https://$config_base_url/guest_view_invoice.php?invoice_id=$invoice_id&url_key=$invoice_url_key\'>here</a>.<br><br><br>--<br>$company_name - Billing<br>$config_invoice_from_email<br>$company_phone";
|
||||
@@ -639,7 +584,7 @@ while ($row = mysqli_fetch_array($sql_recurring)) {
|
||||
$contact_name = sanitizeInput($row['contact_name']);
|
||||
$contact_email = sanitizeInput($row['contact_email']);
|
||||
|
||||
$subject = "$company_name Invoice $invoice_prefix$invoice_number";
|
||||
$subject = "Invoice $invoice_prefix$invoice_number";
|
||||
$body = "Hello $contact_name,<br><br>An invoice regarding \"$invoice_scope\" has been generated. Please view the details below.<br><br>Invoice: $invoice_prefix$invoice_number<br>Issue Date: $invoice_date<br>Total: " . numfmt_format_currency($currency_format, $invoice_amount, $recurring_currency_code) . "<br>Due Date: $invoice_due<br><br><br>To view your invoice, please click <a href=\'https://$config_base_url/guest_view_invoice.php?invoice_id=$new_invoice_id&url_key=$invoice_url_key\'>here</a>.<br><br><br>--<br>$company_name - Billing<br>$config_invoice_from_email<br>$company_phone";
|
||||
|
||||
$mail = addToMailQueue($mysqli, [
|
||||
|
||||
@@ -22,6 +22,7 @@ require_once "get_settings.php";
|
||||
|
||||
$config_ticket_prefix = sanitizeInput($config_ticket_prefix);
|
||||
$config_ticket_from_name = sanitizeInput($config_ticket_from_name);
|
||||
$config_ticket_email_parse_unknown_senders = intval($row['config_ticket_email_parse_unknown_senders']);
|
||||
|
||||
// Get company name & phone & timezone
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1");
|
||||
@@ -94,7 +95,10 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date
|
||||
$contact_email_esc = mysqli_real_escape_string($mysqli, $contact_email);
|
||||
$client_id_esc = intval($client_id);
|
||||
|
||||
mysqli_query($mysqli, "INSERT INTO tickets SET ticket_prefix = '$ticket_prefix_esc', ticket_number = $ticket_number, ticket_subject = '$subject_esc', ticket_details = '$message_esc', ticket_priority = 'Low', ticket_status = 1, ticket_created_by = 0, ticket_contact_id = $contact_id, ticket_client_id = $client_id_esc");
|
||||
//Generate a unique URL key for clients to access
|
||||
$url_key = randomString(156);
|
||||
|
||||
mysqli_query($mysqli, "INSERT INTO tickets SET ticket_prefix = '$ticket_prefix_esc', ticket_number = $ticket_number, ticket_subject = '$subject_esc', ticket_details = '$message_esc', ticket_priority = 'Low', ticket_status = 1, ticket_created_by = 0, ticket_contact_id = $contact_id, ticket_url_key = '$url_key', ticket_client_id = $client_id_esc");
|
||||
$id = mysqli_insert_id($mysqli);
|
||||
|
||||
echo "Created new ticket.<br>";
|
||||
@@ -132,7 +136,7 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date
|
||||
}
|
||||
|
||||
$data = [];
|
||||
if ($config_ticket_client_general_notifications == 1) {
|
||||
if ($config_ticket_client_general_notifications == 1 && $client_id != 0) {
|
||||
$subject_email = "Ticket created - [$config_ticket_prefix$ticket_number] - $subject";
|
||||
$body = "<i style='color: #808080'>##- Please type your reply above this line -##</i><br><br>Hello $contact_name,<br><br>Thank you for your email. A ticket regarding \"$subject\" has been automatically created for you.<br><br>Ticket: $config_ticket_prefix$ticket_number<br>Subject: $subject<br>Status: New<br>https://$config_base_url/portal/ticket.php?id=$id<br><br>--<br>$company_name - Support<br>$config_ticket_from_email<br>$company_phone";
|
||||
|
||||
@@ -212,7 +216,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac
|
||||
mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Ticket', notification = 'Email parser: $from_email attempted to re-open ticket $config_ticket_prefix_esc$ticket_number_esc (ID $ticket_id_esc) - check inbox manually to see email', notification_action = 'ticket.php?ticket_id=$ticket_id_esc', notification_client_id = $client_id_esc");
|
||||
|
||||
$email_subject = "Action required: This ticket is already closed";
|
||||
$email_body = "Hi there, <br><br>You've tried to reply to a ticket that is closed - we won't see your response. <br><br>Please raise a new ticket by sending a fresh e-mail to our support address below. <br><br>--<br>$company_name - Support<br>$config_ticket_from_email<br>$company_phone";
|
||||
$email_body = "Hi there, <br><br>You've tried to reply to a ticket that is closed - we won't see your response. <br><br>Please raise a new ticket by sending a new e-mail to our support address below. <br><br>--<br>$company_name - Support<br>$config_ticket_from_email<br>$company_phone";
|
||||
|
||||
$data = [
|
||||
[
|
||||
@@ -300,7 +304,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac
|
||||
}
|
||||
}
|
||||
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 2 WHERE ticket_id = $ticket_id AND ticket_client_id = $client_id LIMIT 1");
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 2, ticket_resolved_at = NULL WHERE ticket_id = $ticket_id AND ticket_client_id = $client_id LIMIT 1");
|
||||
|
||||
echo "Updated existing ticket.<br>";
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Ticket', log_action = 'Update', log_description = 'Email parser: Client contact $from_email_esc updated ticket $config_ticket_prefix$ticket_number_esc ($subject)', log_client_id = $client_id");
|
||||
@@ -311,12 +315,71 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare connection string with encryption (TLS/SSL/<blank>)
|
||||
$imap_mailbox = "$config_imap_host:$config_imap_port/imap/$config_imap_encryption";
|
||||
|
||||
// Function to create a folder in the mailbox if it doesn't exist
|
||||
function createMailboxFolder($client, $folderName) {
|
||||
try {
|
||||
// Attempt to get the folder
|
||||
$folder = $client->getFolder($folderName);
|
||||
|
||||
// If the folder doesn't exist, create it
|
||||
if (!$folder) {
|
||||
$client->createFolder($folderName);
|
||||
echo "Folder '$folderName' created successfully.";
|
||||
|
||||
// Disconnect and reconnect to ensure the server registers the new folder
|
||||
$client->disconnect();
|
||||
sleep(1); // Pause before reconnecting
|
||||
$client->connect();
|
||||
} else {
|
||||
echo "Folder '$folderName' already exists.";
|
||||
}
|
||||
|
||||
// Re-fetch the folder after reconnecting
|
||||
return $client->getFolder($folderName);
|
||||
|
||||
} catch (Exception $e) {
|
||||
echo "Error creating folder '$folderName': " . $e->getMessage();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to subscribe to a folder in the mailbox
|
||||
function subscribeMailboxFolder($client, $folder) {
|
||||
if ($folder) {
|
||||
try {
|
||||
// Subscribe to the folder
|
||||
$folder->subscribe();
|
||||
echo "Folder '{$folder->name}' subscribed successfully.";
|
||||
} catch (Exception $e) {
|
||||
echo "Error subscribing to folder '{$folder->name}': " . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
echo "Cannot subscribe to folder because it does not exist.";
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the client manager and create the client
|
||||
$clientManager = new ClientManager();
|
||||
$client = $clientManager->make([
|
||||
'host' => $config_imap_host,
|
||||
'port' => $config_imap_port,
|
||||
'encryption' => $config_imap_encryption,
|
||||
'validate_cert' => true,
|
||||
'username' => $config_imap_username,
|
||||
'password' => $config_imap_password,
|
||||
'protocol' => 'imap'
|
||||
]);
|
||||
|
||||
// Connect to the IMAP server
|
||||
$client->connect();
|
||||
|
||||
// Create the "ITFlow" mailbox folder if it doesn't exist
|
||||
$folder = createMailboxFolder($client, 'ITFlow');
|
||||
|
||||
// Subscribe to the "ITFlow" mailbox folder
|
||||
subscribeMailboxFolder($client, $folder);
|
||||
|
||||
// Possible names for the inbox folder
|
||||
$inboxNames = ['Inbox', 'INBOX', 'inbox'];
|
||||
|
||||
@@ -407,6 +470,12 @@ if ($messages->count() > 0) {
|
||||
if (addTicket($contact_id, $contact_name, $contact_email, $client_id, $date, $subject, $message_body, $message->getAttachments(), $original_message_file)) {
|
||||
$email_processed = true;
|
||||
}
|
||||
} elseif ($config_ticket_email_parse_unknown_senders) {
|
||||
// Parse even if the sender is unknown
|
||||
|
||||
if (addTicket(0, 'Guest', $from_email, 0, $date, $subject, $message_body, $message->getAttachments(), $original_message_file)) {
|
||||
$email_processed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -571,7 +571,7 @@ if ($user_config_dashboard_technical_enable == 1) {
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-6">
|
||||
<!-- small box -->
|
||||
<a class="small-box bg-secondary" href="clients.php?date_from=<?php echo $year; ?>-01-01&date_to=<?php echo $year; ?>-12-31">
|
||||
<a class="small-box bg-secondary" href="clients.php?dtf=<?php echo $year; ?>-01-01&dtt=<?php echo $year; ?>-12-31">
|
||||
<div class="inner">
|
||||
<h3><?php echo $clients_added; ?></h3>
|
||||
<p>New Clients</p>
|
||||
|
||||
@@ -2084,10 +2084,57 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.4.2'");
|
||||
}
|
||||
|
||||
// if (CURRENT_DATABASE_VERSION == '1.4.2') {
|
||||
// // Insert queries here required to update to DB version 1.4.3
|
||||
if (CURRENT_DATABASE_VERSION == '1.4.2') {
|
||||
mysqli_query($mysqli, "ALTER TABLE `settings` ADD `config_ticket_email_parse_unknown_senders` INT(1) NOT NULL DEFAULT '0' AFTER `config_ticket_email_parse`");
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.4.3'");
|
||||
}
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '1.4.3') {
|
||||
|
||||
// Add ticket URL key column
|
||||
mysqli_query($mysqli, "ALTER TABLE `tickets` ADD `ticket_url_key` VARCHAR(200) DEFAULT NULL AFTER `ticket_feedback`");
|
||||
// Populate pre-existing columns for open tickets
|
||||
$sql_tickets_1 = mysqli_query($mysqli, "SELECT ticket_id FROM tickets WHERE tickets.ticket_closed_at IS NULL");
|
||||
foreach ($sql_tickets_1 as $row) {
|
||||
$ticket_id = intval($row['ticket_id']);
|
||||
$url_key = randomString(156);
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_url_key = '$url_key' WHERE ticket_id = '$ticket_id'");
|
||||
}
|
||||
|
||||
// Add ticket resolved at column
|
||||
mysqli_query($mysqli, "ALTER TABLE `tickets` ADD `ticket_resolved_at` DATETIME DEFAULT NULL AFTER `ticket_updated_at`");
|
||||
// Populate pre-existing columns for closed tickets
|
||||
$sql_tickets_2 = mysqli_query($mysqli, "SELECT ticket_id, ticket_updated_at, ticket_closed_at FROM tickets WHERE tickets.ticket_closed_at IS NOT NULL");
|
||||
foreach ($sql_tickets_2 as $row) {
|
||||
$ticket_id = intval($row['ticket_id']);
|
||||
$ticket_updated_at = sanitizeInput($row['ticket_updated_at']); // To keep old updated_at time
|
||||
$ticket_closed_at = sanitizeInput($row['ticket_closed_at']);
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_resolved_at = '$ticket_closed_at', ticket_updated_at = '$ticket_updated_at' WHERE ticket_id = '$ticket_id'");
|
||||
}
|
||||
|
||||
// Change ticket status 'Auto close' to 'Resolved'
|
||||
mysqli_query($mysqli, "UPDATE `ticket_statuses` SET `ticket_status_name` = 'Resolved' WHERE `ticket_statuses`.`ticket_status_id` = 4");
|
||||
|
||||
// Auto-close is no longer optional
|
||||
mysqli_query($mysqli, "ALTER TABLE `settings` DROP `config_ticket_autoclose`");
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_ticket_autoclose_hours` = '72'");
|
||||
|
||||
// DB Version
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.4.4'");
|
||||
|
||||
}
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '1.4.4') {
|
||||
mysqli_query($mysqli, "ALTER TABLE `api_keys` ADD `api_key_decrypt_hash` VARCHAR(200) NOT NULL AFTER `api_key_secret`");
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.4.5'");
|
||||
}
|
||||
|
||||
// if (CURRENT_DATABASE_VERSION == '1.4.5') {
|
||||
// // Insert queries here required to update to DB version 1.4.6
|
||||
// // Then, update the database to the next sequential version
|
||||
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.4.3'");
|
||||
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '1.4.6'");
|
||||
// }
|
||||
|
||||
} else {
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
* It is used in conjunction with database_updates.php
|
||||
*/
|
||||
|
||||
DEFINE("LATEST_DATABASE_VERSION", "1.4.2");
|
||||
DEFINE("LATEST_DATABASE_VERSION", "1.4.5");
|
||||
|
||||
5
db.sql
5
db.sql
@@ -66,6 +66,7 @@ CREATE TABLE `api_keys` (
|
||||
`api_key_id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`api_key_name` varchar(255) NOT NULL,
|
||||
`api_key_secret` varchar(255) NOT NULL,
|
||||
`api_key_decrypt_hash` varchar(255) NULL,
|
||||
`api_key_created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
||||
`api_key_expire` date NOT NULL,
|
||||
`api_key_client_id` int(11) NOT NULL DEFAULT 0,
|
||||
@@ -1467,8 +1468,8 @@ CREATE TABLE `settings` (
|
||||
`config_ticket_from_name` varchar(200) DEFAULT NULL,
|
||||
`config_ticket_from_email` varchar(200) DEFAULT NULL,
|
||||
`config_ticket_email_parse` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`config_ticket_email_parse_unknown_senders` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`config_ticket_client_general_notifications` tinyint(1) NOT NULL DEFAULT 1,
|
||||
`config_ticket_autoclose` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`config_ticket_autoclose_hours` int(5) NOT NULL DEFAULT 72,
|
||||
`config_ticket_new_ticket_notification_email` varchar(200) DEFAULT NULL,
|
||||
`config_ticket_default_billable` tinyint(1) NOT NULL DEFAULT 0,
|
||||
@@ -1845,8 +1846,10 @@ CREATE TABLE `tickets` (
|
||||
`ticket_onsite` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`ticket_vendor_ticket_number` varchar(255) DEFAULT NULL,
|
||||
`ticket_feedback` varchar(200) DEFAULT NULL,
|
||||
`ticket_url_key` varchar(200) DEFAULT NULL,
|
||||
`ticket_created_at` datetime NOT NULL DEFAULT current_timestamp(),
|
||||
`ticket_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(),
|
||||
`ticket_resolved_at` datetime DEFAULT NULL,
|
||||
`ticket_archived_at` datetime DEFAULT NULL,
|
||||
`ticket_closed_at` datetime DEFAULT NULL,
|
||||
`ticket_created_by` int(11) NOT NULL,
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
<script src="plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Custom js-->
|
||||
<script src="js/header_timers.js"></script>
|
||||
<script src="plugins/moment/moment.min.js"></script>
|
||||
<script src="plugins/chart.js/Chart.min.js"></script>
|
||||
<script src="plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js"></script>
|
||||
|
||||
@@ -271,7 +271,7 @@ function setupFirstUserSpecificKey($user_password, $site_encryption_master_key)
|
||||
}
|
||||
|
||||
/*
|
||||
* For additional users / password changes
|
||||
* For additional users / password changes (and now the API)
|
||||
* New Users: Requires the admin setting up their account have a Specific/Session key configured
|
||||
* Password Changes: Will use the current info in the session.
|
||||
*/
|
||||
@@ -282,7 +282,7 @@ function encryptUserSpecificKey($user_password)
|
||||
|
||||
// Get the session info.
|
||||
$user_encryption_session_ciphertext = $_SESSION['user_encryption_session_ciphertext'];
|
||||
$user_encryption_session_iv = $_SESSION['user_encryption_session_iv'];
|
||||
$user_encryption_session_iv = $_SESSION['user_encryption_session_iv'];
|
||||
$user_encryption_session_key = $_COOKIE['user_encryption_session_key'];
|
||||
|
||||
// Decrypt the session key to get the master key
|
||||
@@ -297,7 +297,7 @@ function encryptUserSpecificKey($user_password)
|
||||
return $salt . $iv . $ciphertext;
|
||||
}
|
||||
|
||||
// Given a ciphertext (incl. IV) and the user's password, returns the site master key
|
||||
// Given a ciphertext (incl. IV) and the user's (or API key) password, returns the site master key
|
||||
// Ran at login, to facilitate generateUserSessionKey
|
||||
function decryptUserSpecificKey($user_encryption_ciphertext, $user_password)
|
||||
{
|
||||
@@ -380,6 +380,32 @@ function encryptLoginEntry($login_password_cleartext)
|
||||
return $iv . $ciphertext;
|
||||
}
|
||||
|
||||
function apiDecryptLoginEntry($login_ciphertext, $api_key_decrypt_hash, #[\SensitiveParameter]$api_key_decrypt_password)
|
||||
{
|
||||
// Split the login entry (username/password) into IV and Ciphertext
|
||||
$login_iv = substr($login_ciphertext, 0, 16);
|
||||
$login_ciphertext = $salt = substr($login_ciphertext, 16);
|
||||
|
||||
// Decrypt the api hash to get the master key
|
||||
$site_encryption_master_key = decryptUserSpecificKey($api_key_decrypt_hash, $api_key_decrypt_password);
|
||||
|
||||
// Decrypt the login password using the master key
|
||||
return openssl_decrypt($login_ciphertext, 'aes-128-cbc', $site_encryption_master_key, 0, $login_iv);
|
||||
}
|
||||
|
||||
function apiEncryptLoginEntry(#[\SensitiveParameter]$credential_cleartext, $api_key_decrypt_hash, #[\SensitiveParameter]$api_key_decrypt_password)
|
||||
{
|
||||
$iv = randomString();
|
||||
|
||||
// Decrypt the api hash to get the master key
|
||||
$site_encryption_master_key = decryptUserSpecificKey($api_key_decrypt_hash, $api_key_decrypt_password);
|
||||
|
||||
// Encrypt the credential using the master key
|
||||
$ciphertext = openssl_encrypt($credential_cleartext, 'aes-128-cbc', $site_encryption_master_key, 0, $iv);
|
||||
|
||||
return $iv . $ciphertext;
|
||||
}
|
||||
|
||||
// Get domain general info (whois + NS/A/MX records)
|
||||
function getDomainRecords($name)
|
||||
{
|
||||
@@ -738,6 +764,10 @@ function sanitizeForEmail($data)
|
||||
|
||||
function timeAgo($datetime)
|
||||
{
|
||||
if (is_null($datetime)) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
$time = strtotime($datetime);
|
||||
$difference = $time - time(); // Changed to handle future dates
|
||||
|
||||
@@ -1193,36 +1223,6 @@ function fetchUpdates() {
|
||||
|
||||
}
|
||||
|
||||
// Get domain expiration date -- Remove in the future Replace with PHP function
|
||||
function getDomainExpirationDateOLD($name)
|
||||
{
|
||||
|
||||
// Only run if we think the domain is valid
|
||||
if (!filter_var($name, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) {
|
||||
return "NULL";
|
||||
}
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, "http://lookup.itflow.org:8080/$name");
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$response = json_decode(curl_exec($ch), 1);
|
||||
|
||||
if ($response) {
|
||||
if (is_array($response['expiration_date'])) {
|
||||
$expiry = new DateTime($response['expiration_date'][1]);
|
||||
} elseif (isset($response['expiration_date'])) {
|
||||
$expiry = new DateTime($response['expiration_date']);
|
||||
} else {
|
||||
return "NULL";
|
||||
}
|
||||
|
||||
return $expiry->format('Y-m-d');
|
||||
}
|
||||
|
||||
// Default return
|
||||
return "NULL";
|
||||
}
|
||||
|
||||
function getDomainExpirationDate($domain) {
|
||||
// Execute the whois command
|
||||
$result = shell_exec("whois " . escapeshellarg($domain));
|
||||
|
||||
@@ -68,12 +68,13 @@ $config_ticket_next_number = intval($row['config_ticket_next_number']);
|
||||
$config_ticket_from_name = $row['config_ticket_from_name'];
|
||||
$config_ticket_from_email = $row['config_ticket_from_email'];
|
||||
$config_ticket_email_parse = intval($row['config_ticket_email_parse']);
|
||||
$config_ticket_email_parse_unknown_senders = intval($row['config_ticket_email_parse_unknown_senders']);
|
||||
$config_ticket_client_general_notifications = intval($row['config_ticket_client_general_notifications']);
|
||||
$config_ticket_autoclose = intval($row['config_ticket_autoclose']);
|
||||
$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_default_billable = intval($row['config_ticket_default_billable']);
|
||||
|
||||
|
||||
// Cron
|
||||
$config_enable_cron = intval($row['config_enable_cron']);
|
||||
$config_cron_key = $row['config_cron_key'];
|
||||
|
||||
@@ -55,3 +55,83 @@ if (isset($_GET['decline_quote'], $_GET['url_key'])) {
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['reopen_ticket'], $_GET['url_key'])) {
|
||||
|
||||
$ticket_id = intval($_GET['ticket_id']);
|
||||
$url_key = sanitizeInput($_GET['url_key']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id AND ticket_url_key = '$url_key' AND ticket_resolved_at IS NOT NULL and ticket_closed_at IS NULL");
|
||||
|
||||
if (mysqli_num_rows($sql) == 1) {
|
||||
|
||||
// Update the ticket
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 2, ticket_resolved_at = NULL WHERE ticket_id = $ticket_id AND ticket_url_key = '$url_key'");
|
||||
|
||||
// Add reply
|
||||
mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket reopened by client (guest URL).', ticket_reply_type = 'Internal', ticket_reply_by = 0, ticket_reply_ticket_id = $ticket_id");
|
||||
|
||||
//Logging
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Ticket', log_action = 'Replied', log_description = '$ticket_id reopened by client (guest)', log_ip = '$session_ip', log_user_agent = '$session_user_agent'");
|
||||
|
||||
$_SESSION['alert_message'] = "Ticket reopened";
|
||||
header("Location: " . $_SERVER["HTTP_REFERER"]);
|
||||
|
||||
} else {
|
||||
echo "Invalid!!";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['close_ticket'], $_GET['url_key'])) {
|
||||
|
||||
$ticket_id = intval($_GET['ticket_id']);
|
||||
$url_key = sanitizeInput($_GET['url_key']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id AND ticket_url_key = '$url_key' AND ticket_resolved_at IS NOT NULL and ticket_closed_at IS NULL");
|
||||
|
||||
if (mysqli_num_rows($sql) == 1) {
|
||||
|
||||
// Update the ticket
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 5, ticket_closed_at = NOW() WHERE ticket_id = $ticket_id AND ticket_url_key = '$url_key'");
|
||||
|
||||
// Add reply
|
||||
mysqli_query($mysqli, "INSERT INTO ticket_replies SET ticket_reply = 'Ticket closed by client (guest URL).', ticket_reply_type = 'Internal', ticket_reply_by = 0, ticket_reply_ticket_id = $ticket_id");
|
||||
|
||||
//Logging
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Ticket', log_action = 'Replied', log_description = '$ticket_id closed by client (guest)', log_ip = '$session_ip', log_user_agent = '$session_user_agent'");
|
||||
|
||||
$_SESSION['alert_message'] = "Ticket closed";
|
||||
header("Location: " . $_SERVER["HTTP_REFERER"]);
|
||||
|
||||
} else {
|
||||
echo "Invalid!!";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['add_ticket_feedback'], $_GET['url_key'])) {
|
||||
|
||||
$ticket_id = intval($_GET['ticket_id']);
|
||||
$url_key = sanitizeInput($_GET['url_key']);
|
||||
$feedback = sanitizeInput($_GET['feedback']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM tickets WHERE ticket_id = $ticket_id AND ticket_url_key = '$url_key' AND ticket_closed_at IS NOT NULL");
|
||||
|
||||
if (mysqli_num_rows($sql) == 1) {
|
||||
|
||||
// Add feedback
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_feedback = '$feedback' WHERE ticket_id = $ticket_id AND ticket_url_key = '$url_key'");
|
||||
|
||||
// Notify on bad feedback
|
||||
if ($feedback == "Bad") {
|
||||
mysqli_query($mysqli, "INSERT INTO notifications SET notification_type = 'Feedback', notification = 'Guest rated ticket ID $ticket_id as bad'");
|
||||
}
|
||||
|
||||
$_SESSION['alert_message'] = "Feedback recorded - thank you";
|
||||
header("Location: " . $_SERVER["HTTP_REFERER"]);
|
||||
|
||||
} else {
|
||||
echo "Invalid!!";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -135,18 +135,45 @@ if ($invoice_status !== "Paid" && $invoice_status !== "Draft" && $invoice_status
|
||||
// Invoice individual items
|
||||
$sql_invoice_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE item_invoice_id = $invoice_id ORDER BY item_order ASC");
|
||||
|
||||
|
||||
// Get Total Account Balance
|
||||
//Add up all the payments for the invoice and get the total amount paid to the invoice
|
||||
$sql_invoice_amounts = mysqli_query($mysqli, "SELECT SUM(invoice_amount) AS invoice_amounts FROM invoices WHERE invoice_client_id = $client_id AND invoice_status NOT LIKE 'Draft' AND invoice_status NOT LIKE 'Cancelled' ");
|
||||
$row = mysqli_fetch_array($sql_invoice_amounts);
|
||||
|
||||
$account_balance = floatval($row['invoice_amounts']);
|
||||
|
||||
$sql_amount_paid = mysqli_query($mysqli, "SELECT SUM(payment_amount) AS amount_paid FROM payments, invoices WHERE payment_invoice_id = invoice_id AND invoice_client_id = $client_id");
|
||||
$row = mysqli_fetch_array($sql_amount_paid);
|
||||
|
||||
$account_amount_paid = floatval($row['amount_paid']);
|
||||
|
||||
$account_balance = $account_balance - $account_amount_paid;
|
||||
//set Text color on balance
|
||||
if ($balance > 0) {
|
||||
$balance_text_color = "text-danger font-weight-bold";
|
||||
} else {
|
||||
$balance_text_color = "";
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-light d-print-none">
|
||||
<div class="float-right">
|
||||
<a class="btn btn-secondary" data-toggle="collapse" href="#collapsePreviousInvoices"><i class="fas fa-fw fa-history mr-2"></i>Invoice History</a>
|
||||
<a class="btn btn-primary" href="#" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</a>
|
||||
<a class="btn btn-primary" href="#" onclick="pdfMake.createPdf(docDefinition).download('<?php echo strtoAZaz09(html_entity_decode("$invoice_date-$company_name-Invoice-$invoice_prefix$invoice_number")); ?>');"><i class="fa fa-fw fa-download mr-2"></i>Download</a>
|
||||
<?php
|
||||
if ($invoice_status !== "Paid" && $invoice_status !== "Cancelled" && $invoice_status !== "Draft" && $config_stripe_enable == 1) { ?>
|
||||
<a class="btn btn-success" href="guest_pay_invoice_stripe.php?invoice_id=<?php echo $invoice_id; ?>&url_key=<?php echo $url_key; ?>"><i class="fa fa-fw fa-credit-card mr-2"></i>Pay Online <?php if($config_stripe_client_pays_fees == 1) { echo "(Gateway Fee: " . numfmt_format_currency($currency_format, $gateway_fee, $invoice_currency_code) . ")"; } ?></a>
|
||||
<?php } ?>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<h4 class="mt-1">Account Balance: <b><?php echo numfmt_format_currency($currency_format, $account_balance, $invoice_currency_code); ?></b></h4>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="float-right">
|
||||
<a class="btn btn-default" href="#" onclick="window.print();"><i class="fas fa-fw fa-print mr-2"></i>Print</a>
|
||||
<a class="btn btn-default" href="#" onclick="pdfMake.createPdf(docDefinition).download('<?php echo strtoAZaz09(html_entity_decode("$invoice_date-$company_name-Invoice-$invoice_prefix$invoice_number")); ?>');"><i class="fa fa-fw fa-download mr-2"></i>Download</a>
|
||||
<?php
|
||||
if ($invoice_status !== "Paid" && $invoice_status !== "Cancelled" && $invoice_status !== "Draft" && $config_stripe_enable == 1) { ?>
|
||||
<a class="btn btn-success" href="guest_pay_invoice_stripe.php?invoice_id=<?php echo $invoice_id; ?>&url_key=<?php echo $url_key; ?>"><i class="fa fa-fw fa-credit-card mr-2"></i>Pay Now <?php if($config_stripe_client_pays_fees == 1) { echo "(Gateway Fee: " . numfmt_format_currency($currency_format, $gateway_fee, $invoice_currency_code) . ")"; } ?></a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@@ -773,79 +800,23 @@ $sql_invoice_items = mysqli_query($mysqli, "SELECT * FROM invoice_items WHERE it
|
||||
|
||||
<?php
|
||||
|
||||
// PREVIOUS UNPAID INVOICES
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $client_id AND invoice_due < CURDATE() AND(invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial') ORDER BY invoice_date DESC");
|
||||
|
||||
if (mysqli_num_rows($sql) > 1) { ?>
|
||||
|
||||
<div class="card d-print-none card-danger">
|
||||
<div class="card-header">
|
||||
<strong><i class="fa fa-fw fa-exclamation-triangle mr-2"></i>Previous Unpaid Invoices</strong>
|
||||
</div>
|
||||
<div card="card-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">Invoice #</th>
|
||||
<th>Date</th>
|
||||
<th>Due Date</th>
|
||||
<th class="text-right">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
$invoice_id = intval($row['invoice_id']);
|
||||
$invoice_prefix = nullable_htmlentities($row['invoice_prefix']);
|
||||
$invoice_number = intval($row['invoice_number']);
|
||||
$invoice_date = nullable_htmlentities($row['invoice_date']);
|
||||
$invoice_due = nullable_htmlentities($row['invoice_due']);
|
||||
$invoice_amount = floatval($row['invoice_amount']);
|
||||
$invoice_currency_code = nullable_htmlentities($row['invoice_currency_code']);
|
||||
$invoice_url_key = nullable_htmlentities($row['invoice_url_key']);
|
||||
$invoice_tally_total = $invoice_amount + $invoice_tally_total;
|
||||
$difference = time() - strtotime($invoice_due);
|
||||
$days = floor($difference / (60*60*24));
|
||||
|
||||
?>
|
||||
|
||||
<tr <?php if ($_GET['invoice_id'] == $invoice_id) { echo "class='table-active'"; } ?>>
|
||||
<th class="text-center"><a href="guest_view_invoice.php?invoice_id=<?php echo $invoice_id; ?>&url_key=<?php echo $invoice_url_key; ?>"><?php echo "$invoice_prefix$invoice_number"; ?></a></th>
|
||||
<td><?php echo $invoice_date; ?></td>
|
||||
<td class="text-danger text-bold"><?php echo $invoice_due; ?> (<?php echo $days; ?> Days Late)</td>
|
||||
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code); ?></td>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php } // End previous unpaid invoices
|
||||
|
||||
|
||||
// CURRENT INVOICES
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $client_id AND invoice_due > CURDATE() AND(invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial') ORDER BY invoice_number DESC");
|
||||
$sql_current_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $client_id AND invoice_due > CURDATE() AND(invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial') ORDER BY invoice_number DESC");
|
||||
|
||||
if (mysqli_num_rows($sql) > 1) { ?>
|
||||
$current_invoices_count = mysqli_num_rows($sql_current_invoices);
|
||||
|
||||
if ($current_invoices_count > 0) { ?>
|
||||
|
||||
<div class="card d-print-none card-light">
|
||||
<div class="card d-print-none card-dark">
|
||||
<div class="card-header">
|
||||
<strong><i class="fas fa-fw fa-clock mr-2"></i>Current Invoices</strong>
|
||||
<strong><i class="fas fa-fw fa-clock mr-2"></i><b><?php echo $current_invoices_count; ?></b> Current Invoices</strong>
|
||||
</div>
|
||||
<div card="card-body">
|
||||
<table class="table">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">Invoice #</th>
|
||||
<th class="text-center">Invoice</th>
|
||||
<th>Date</th>
|
||||
<th>Due</th>
|
||||
<th class="text-right">Amount</th>
|
||||
@@ -854,7 +825,7 @@ if (mysqli_num_rows($sql) > 1) { ?>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_array($sql_current_invoices)) {
|
||||
$invoice_id = intval($row['invoice_id']);
|
||||
$invoice_prefix = nullable_htmlentities($row['invoice_prefix']);
|
||||
$invoice_number = intval($row['invoice_number']);
|
||||
@@ -869,11 +840,11 @@ if (mysqli_num_rows($sql) > 1) { ?>
|
||||
|
||||
?>
|
||||
|
||||
<tr <?php if ($_GET['invoice_id'] == $invoice_id) { echo "class='table-active'"; } ?>>
|
||||
<tr <?php if ($_GET['invoice_id'] == $invoice_id) { echo "class='table-primary'"; } ?>>
|
||||
<th class="text-center"><a href="guest_view_invoice.php?invoice_id=<?php echo $invoice_id; ?>&url_key=<?php echo $invoice_url_key; ?>"><?php echo "$invoice_prefix$invoice_number"; ?></a></th>
|
||||
<td><?php echo $invoice_date; ?></td>
|
||||
<td><?php echo $invoice_due; ?> (Due in <?php echo $days; ?> Days)</td>
|
||||
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code); ?></td>
|
||||
<td class="text-right text-bold"><?php echo numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code); ?></td>
|
||||
</tr>
|
||||
|
||||
<?php } ?>
|
||||
@@ -882,37 +853,41 @@ if (mysqli_num_rows($sql) > 1) { ?>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<?php
|
||||
|
||||
// PREVIOUS PAID INVOICES
|
||||
// OUTSTANDING INVOICES
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $client_id AND invoice_status = 'Paid' ORDER BY invoice_date DESC");
|
||||
$sql_outstanding_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_client_id = $client_id AND invoice_due < CURDATE() AND(invoice_status = 'Sent' OR invoice_status = 'Viewed' OR invoice_status = 'Partial') ORDER BY invoice_date DESC");
|
||||
|
||||
if (mysqli_num_rows($sql) > 1) { ?>
|
||||
$outstanding_invoices_count = mysqli_num_rows($sql_outstanding_invoices);
|
||||
|
||||
<div class="card d-print-none collapse" id="collapsePreviousInvoices">
|
||||
<div class="card-header bg-dark">
|
||||
<strong><i class="fas fa-fw fa-history mr-2"></i>Previous Invoices Paid</strong>
|
||||
if ($outstanding_invoices_count > 0) { ?>
|
||||
|
||||
<div class="card d-print-none card-danger">
|
||||
<div class="card-header">
|
||||
<strong><i class="fa fa-fw fa-exclamation-triangle mr-2"></i><b><?php echo $outstanding_invoices_count; ?></b> Outstanding Invoices</strong>
|
||||
</div>
|
||||
<div card="card-body">
|
||||
<table class="table">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">Invoice #</th>
|
||||
<th class="text-center">Invoice</th>
|
||||
<th>Date</th>
|
||||
<th>Due Date</th>
|
||||
<th>Due</th>
|
||||
<th></th>
|
||||
<th class="text-right">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
while ($row = mysqli_fetch_array($sql_outstanding_invoices)) {
|
||||
$invoice_id = intval($row['invoice_id']);
|
||||
$invoice_prefix = nullable_htmlentities($row['invoice_prefix']);
|
||||
$invoice_number = intval($row['invoice_number']);
|
||||
@@ -922,60 +897,27 @@ if (mysqli_num_rows($sql) > 1) { ?>
|
||||
$invoice_currency_code = nullable_htmlentities($row['invoice_currency_code']);
|
||||
$invoice_url_key = nullable_htmlentities($row['invoice_url_key']);
|
||||
$invoice_tally_total = $invoice_amount + $invoice_tally_total;
|
||||
$difference = time() - strtotime($invoice_due);
|
||||
$days = floor($difference / (60*60*24));
|
||||
|
||||
?>
|
||||
|
||||
<tr <?php if ($_GET['invoice_id'] == $invoice_id) { echo "class='table-active'"; } ?>>
|
||||
<tr <?php if ($_GET['invoice_id'] == $invoice_id) { echo "class='table-primary'"; } ?>>
|
||||
<th class="text-center"><a href="guest_view_invoice.php?invoice_id=<?php echo $invoice_id; ?>&url_key=<?php echo $invoice_url_key; ?>"><?php echo "$invoice_prefix$invoice_number"; ?></a></th>
|
||||
<td><?php echo $invoice_date; ?></td>
|
||||
<td><?php echo $invoice_due; ?></td>
|
||||
<td class="text-right"><?php echo numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code); ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th colspan="4">Payments</th>
|
||||
<td class="text-danger"><?php echo $invoice_due; ?> (Over Due by <?php echo $days; ?> Days)</td>
|
||||
<td class="text-right text-bold"><?php echo numfmt_format_currency($currency_format, $invoice_amount, $invoice_currency_code); ?></td>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
|
||||
$sql_payments = mysqli_query($mysqli, "SELECT * FROM payments WHERE payment_invoice_id = $invoice_id ORDER BY payment_date DESC");
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_payments)) {
|
||||
$payment_id = intval($row['payment_id']);
|
||||
$payment_date = nullable_htmlentities($row['payment_date']);
|
||||
$payment_amount = floatval($row['payment_amount']);
|
||||
$payment_currency_code = nullable_htmlentities($row['payment_currency_code']);
|
||||
$payment_method = nullable_htmlentities($row['payment_method']);
|
||||
$payment_reference = nullable_htmlentities($row['payment_reference']);
|
||||
if (strtotime($payment_date) > strtotime($invoice_due)) {
|
||||
$payment_note = "Late";
|
||||
$difference = strtotime($payment_date) - strtotime($invoice_due);
|
||||
$days = floor($difference / (60*60*24)) . " Days";
|
||||
} else {
|
||||
$payment_note = "";
|
||||
$days = "";
|
||||
}
|
||||
|
||||
|
||||
$invoice_tally_total = $invoice_amount + $invoice_tally_total;
|
||||
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td colspan="4"><?php echo $payment_date; ?> - <?php echo numfmt_format_currency($currency_format, $payment_amount, $payment_currency_code); ?> - <?php echo $payment_method; ?> - <?php echo $payment_reference; ?> - <?php echo $days; ?> <?php echo $payment_note; ?></td>
|
||||
</tr>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<?php } ?>
|
||||
}
|
||||
?>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php } // End previous paid invoices
|
||||
|
||||
<?php } // End previous unpaid invoices
|
||||
|
||||
require_once "guest_footer.php";
|
||||
|
||||
|
||||
220
guest_view_ticket.php
Normal file
220
guest_view_ticket.php
Normal file
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
require_once "guest_header.php";
|
||||
|
||||
//Initialize the HTML Purifier to prevent XSS
|
||||
require "plugins/htmlpurifier/HTMLPurifier.standalone.php";
|
||||
|
||||
$purifier_config = HTMLPurifier_Config::createDefault();
|
||||
$purifier_config->set('URI.AllowedSchemes', ['data' => true, 'src' => true, 'http' => true, 'https' => true]);
|
||||
$purifier = new HTMLPurifier($purifier_config);
|
||||
|
||||
if (!isset($_GET['ticket_id'], $_GET['url_key'])) {
|
||||
echo "<br><h2>Oops, something went wrong! Please raise a ticket if you believe this is an error.</h2>";
|
||||
require_once "guest_footer.php";
|
||||
exit();
|
||||
}
|
||||
|
||||
// Company info
|
||||
$company_sql_row = mysqli_fetch_array(mysqli_query($mysqli, "SELECT company_phone, company_website FROM companies, settings WHERE companies.company_id = settings.company_id AND companies.company_id = 1"));
|
||||
$company_phone = formatPhoneNumber($company_sql_row['company_phone']);
|
||||
$company_website = nullable_htmlentities($company_sql_row['company_website']);
|
||||
|
||||
$url_key = sanitizeInput($_GET['url_key']);
|
||||
$ticket_id = intval($_GET['ticket_id']);
|
||||
|
||||
$ticket_sql = mysqli_query($mysqli,
|
||||
"SELECT * FROM tickets
|
||||
LEFT JOIN users on ticket_assigned_to = user_id
|
||||
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
|
||||
WHERE ticket_id = $ticket_id AND ticket_url_key = '$url_key'"
|
||||
);
|
||||
|
||||
if (mysqli_num_rows($ticket_sql) !== 1) {
|
||||
// Invalid invoice/key
|
||||
echo "<br><h2>Oops, something went wrong! Please raise a ticket if you believe this is an error.</h2>";
|
||||
require_once "guest_footer.php";
|
||||
|
||||
exit();
|
||||
}
|
||||
|
||||
$ticket_row = mysqli_fetch_array($ticket_sql);
|
||||
|
||||
if ($ticket_row) {
|
||||
|
||||
$ticket_prefix = nullable_htmlentities($ticket_row['ticket_prefix']);
|
||||
$ticket_number = intval($ticket_row['ticket_number']);
|
||||
$ticket_status = nullable_htmlentities($ticket_row['ticket_status_name']);
|
||||
$ticket_priority = nullable_htmlentities($ticket_row['ticket_priority']);
|
||||
$ticket_subject = nullable_htmlentities($ticket_row['ticket_subject']);
|
||||
$ticket_details = $purifier->purify($ticket_row['ticket_details']);
|
||||
$ticket_assigned_to = nullable_htmlentities($ticket_row['user_name']);
|
||||
$ticket_resolved_at = nullable_htmlentities($ticket_row['ticket_resolved_at']);
|
||||
$ticket_closed_at = nullable_htmlentities($ticket_row['ticket_closed_at']);
|
||||
$ticket_feedback = nullable_htmlentities($ticket_row['ticket_feedback']);
|
||||
|
||||
?>
|
||||
|
||||
<ol class="breadcrumb d-print-none">
|
||||
<li class="breadcrumb-item">
|
||||
<a href="portal/index.php">Portal Home</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="portal/tickets.php">Tickets</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active">Ticket <?php echo $ticket_prefix . $ticket_number; ?></li>
|
||||
</ol>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark text-center">
|
||||
<h4 class="mt-1">
|
||||
Ticket <?php echo $ticket_prefix, $ticket_number ?>
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="card-body prettyContent">
|
||||
<h5><strong>Subject:</strong> <?php echo $ticket_subject ?></h5>
|
||||
<hr>
|
||||
<p>
|
||||
<strong>State:</strong> <?php echo $ticket_status ?>
|
||||
<br>
|
||||
<strong>Priority:</strong> <?php echo $ticket_priority ?>
|
||||
<br>
|
||||
<?php if (empty($ticket_closed_at)) { ?>
|
||||
<strong>Assigned to: </strong> <?php echo $ticket_assigned_to ?>
|
||||
<?php } ?>
|
||||
</p>
|
||||
<?php echo $ticket_details ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Either show the reply comments box, option to re-open ticket, show ticket smiley feedback or thanks for feedback -->
|
||||
|
||||
<?php if (empty($ticket_resolved_at)) { ?>
|
||||
<!-- Reply - guest users should email or login so we know exactly who replied -->
|
||||
<h6><i>Please <a href="portal">log in</a> or reply to the ticket via email to respond</i></h6>
|
||||
|
||||
<?php } elseif (empty($ticket_closed_at)) { ?>
|
||||
<!-- Re-open -->
|
||||
|
||||
<h4>Your ticket has been resolved</h4>
|
||||
|
||||
<div class="col-4">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="guest_post.php?reopen_ticket&ticket_id=<?php echo $ticket_id; ?>&url_key=<?php echo $url_key ?>" class="btn btn-secondary btn-lg"><i class="fas fa-fw fa-redo text-white"></i> Reopen ticket</a>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<a href="guest_post.php?close_ticket=&ticket_id=<?php echo $ticket_id; ?>&url_key=<?php echo $url_key ?>" class="btn btn-success btn-lg"><i class="fas fa-fw fa-gavel text-white"></i> Close ticket</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<?php } elseif (empty($ticket_feedback)) { ?>
|
||||
|
||||
<h4>Ticket closed. Please rate your ticket</h4>
|
||||
|
||||
<div class="col-4">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="guest_post.php?add_ticket_feedback&ticket_id=<?php echo $ticket_id; ?>&url_key=<?php echo $url_key ?>&feedback=Good" class="btn btn-success btn-lg"><i class="fas fa-fw fa-smile text-white"></i> Good</a>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<a href="guest_post.php?add_ticket_feedback&ticket_id=<?php echo $ticket_id; ?>&url_key=<?php echo $url_key ?>&feedback=Bad" class="btn btn-danger btn-lg"><i class="fas fa-fw fa-frown text-white"></i> Bad</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<?php } else { ?>
|
||||
|
||||
<h4>Rated <?php echo $ticket_feedback ?> -- Thanks for your feedback!</h4>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<!-- End comments/reopen/feedback -->
|
||||
|
||||
<hr>
|
||||
<br>
|
||||
|
||||
<?php
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ticket_replies LEFT JOIN users ON ticket_reply_by = user_id LEFT JOIN contacts ON ticket_reply_by = contact_id WHERE ticket_reply_ticket_id = $ticket_id AND ticket_reply_archived_at IS NULL AND ticket_reply_type != 'Internal' ORDER BY ticket_reply_id DESC");
|
||||
|
||||
while ($row = mysqli_fetch_array($sql)) {
|
||||
$ticket_reply_id = intval($row['ticket_reply_id']);
|
||||
$ticket_reply = $purifier->purify($row['ticket_reply']);
|
||||
$ticket_reply_created_at = nullable_htmlentities($row['ticket_reply_created_at']);
|
||||
$ticket_reply_updated_at = nullable_htmlentities($row['ticket_reply_updated_at']);
|
||||
$ticket_reply_by = intval($row['ticket_reply_by']);
|
||||
$ticket_reply_type = $row['ticket_reply_type'];
|
||||
|
||||
if ($ticket_reply_type == "Client") {
|
||||
$ticket_reply_by_display = nullable_htmlentities($row['contact_name']);
|
||||
$user_initials = initials($row['contact_name']);
|
||||
$user_avatar = $row['contact_photo'];
|
||||
$avatar_link = "../uploads/clients/$ticket_reply_by/$user_avatar";
|
||||
} else {
|
||||
$ticket_reply_by_display = nullable_htmlentities($row['user_name']);
|
||||
$user_id = intval($row['user_id']);
|
||||
$user_avatar = $row['user_avatar'];
|
||||
$user_initials = initials($row['user_name']);
|
||||
$avatar_link = "../uploads/users/$user_id/$user_avatar";
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="card card-outline <?php if ($ticket_reply_type == 'Client') { echo "card-warning"; } else { echo "card-info"; } ?> mb-3">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">
|
||||
<div class="media">
|
||||
<?php
|
||||
if (!empty($user_avatar)) {
|
||||
?>
|
||||
<img src="<?php echo $avatar_link ?>" alt="User Avatar" class="img-size-50 mr-3 img-circle">
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<span class="fa-stack fa-2x">
|
||||
<i class="fa fa-circle fa-stack-2x text-secondary"></i>
|
||||
<span class="fa fa-stack-1x text-white"><?php echo $user_initials; ?></span>
|
||||
</span>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="media-body">
|
||||
<?php echo $ticket_reply_by_display; ?>
|
||||
<br>
|
||||
<small class="text-muted"><?php echo $ticket_reply_created_at; ?> <?php if (!empty($ticket_reply_updated_at)) { echo "(edited: $ticket_reply_updated_at)"; } ?></small>
|
||||
</div>
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="card-body prettyContent">
|
||||
<?php echo $ticket_reply; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<script src="../js/pretty_content.js"></script>
|
||||
|
||||
<?php } else {
|
||||
echo "Ticket ID not found!";
|
||||
} ?>
|
||||
|
||||
<div class="card-footer">
|
||||
<?php echo "<i class='fas fa-phone fa-fw mr-2'></i>$company_phone | <i class='fas fa-globe fa-fw mr-2 ml-2'></i>$company_website"; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
require_once "guest_footer.php";
|
||||
@@ -210,12 +210,6 @@ if (isset($_GET['client_id'])) {
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('trip_id') AS num FROM trips WHERE trip_archived_at IS NULL AND trip_client_id = $client_id"));
|
||||
$num_trips = $row['num'];
|
||||
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('item_id') AS num FROM shared_items WHERE item_client_id = $client_id"));
|
||||
$num_shared_links = $row['num'];
|
||||
|
||||
$row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COUNT('log_id') AS num FROM logs WHERE log_client_id = $client_id"));
|
||||
$num_logs = $row['num'];
|
||||
|
||||
// Expiring Items
|
||||
|
||||
// Count Domains Expiring within 30 Days
|
||||
@@ -229,6 +223,20 @@ if (isset($_GET['client_id'])) {
|
||||
));
|
||||
$num_domains_expiring = intval($row['num']);
|
||||
|
||||
// Count Domains Expired or within 5 days
|
||||
$row = mysqli_fetch_assoc(mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT COUNT('domain_id') AS num FROM domains
|
||||
WHERE domain_client_id = $client_id
|
||||
AND domain_expire IS NOT NULL
|
||||
AND (
|
||||
domain_expire < CURRENT_DATE
|
||||
OR domain_expire < CURRENT_DATE + INTERVAL 5 DAY
|
||||
)
|
||||
AND domain_archived_at IS NULL"
|
||||
));
|
||||
$num_domains_expired = intval($row['num']);
|
||||
|
||||
// Count Certificates Expiring within 30 Days
|
||||
$row = mysqli_fetch_assoc(mysqli_query(
|
||||
$mysqli,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="card-body py-2">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="#" data-toggle="collapse" data-target="#clientHeader"><h4 class="text-secondary"><strong><?php echo $client_name; ?></strong> <?php if ($client_archived_at) { echo "(archived)"; } ?></h4></a>
|
||||
<a href="#" data-toggle="collapse" data-target="#clientHeader"><h4 class="text-secondary" data-toggle="tooltip" data-placement="right" title="Client ID: <?php echo $client_id; ?>"><strong><?php echo $client_name; ?></strong> <?php if ($client_archived_at) { echo "(archived)"; } ?></h4></a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<?php if ($session_user_role == 3) { ?>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
}
|
||||
timerInterval = setInterval(countTime, 1000);
|
||||
isPaused = false;
|
||||
document.getElementById("startStopTimer").innerText = "Pause";
|
||||
document.getElementById("startStopTimer").innerHTML = "<i class='fas fa-pause'></i>";
|
||||
localStorage.setItem("ticket-timer-running-" + ticketID, "true");
|
||||
|
||||
}
|
||||
@@ -66,7 +66,7 @@
|
||||
localStorage.setItem(getLocalStorageKey("pausedTime"), currentElapsed.toString());
|
||||
localStorage.removeItem(getLocalStorageKey("startTime"));
|
||||
isPaused = true;
|
||||
document.getElementById("startStopTimer").innerText = "Start";
|
||||
document.getElementById("startStopTimer").innerHTML = "<i class='fas fa-play'></i>";
|
||||
localStorage.setItem("ticket-timer-running-" + ticketID, "false");
|
||||
|
||||
}
|
||||
@@ -84,7 +84,7 @@
|
||||
elapsedSecs = 0;
|
||||
clearTimeStorage();
|
||||
displayTime();
|
||||
document.getElementById("startStopTimer").innerText = "Start";
|
||||
document.getElementById("startStopTimer").innerHTML = "<i class='fas fa-play'></i>";
|
||||
}
|
||||
localStorage.setItem("ticket-timer-running-" + ticketID, "false");
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
elapsedSecs = 0;
|
||||
clearTimeStorage();
|
||||
displayTime();
|
||||
document.getElementById("startStopTimer").innerText = "Start";
|
||||
document.getElementById("startStopTimer").innerHTML = "<i class='fas fa-play'></i>";
|
||||
}
|
||||
|
||||
function handleInputFocus() {
|
||||
|
||||
@@ -121,7 +121,10 @@ function addTicket($contact_id, $contact_name, $contact_email, $client_id, $date
|
||||
$message = nl2br($message);
|
||||
$message = mysqli_escape_string($mysqli, "<i>Email from: $contact_email at $date:-</i> <br><br>$message");
|
||||
|
||||
mysqli_query($mysqli, "INSERT INTO tickets SET ticket_prefix = '$config_ticket_prefix', ticket_number = $ticket_number, ticket_subject = '$subject', ticket_details = '$message', ticket_priority = 'Low', ticket_status = 1, ticket_created_by = 0, ticket_contact_id = $contact_id, ticket_client_id = $client_id");
|
||||
//Generate a unique URL key for clients to access
|
||||
$url_key = randomString(156);
|
||||
|
||||
mysqli_query($mysqli, "INSERT INTO tickets SET ticket_prefix = '$config_ticket_prefix', ticket_number = $ticket_number, ticket_subject = '$subject', ticket_details = '$message', ticket_priority = 'Low', ticket_status = 1, ticket_created_by = 0, ticket_contact_id = $contact_id, ticket_url_key = '$url_key', ticket_client_id = $client_id");
|
||||
$id = mysqli_insert_id($mysqli);
|
||||
|
||||
// Logging
|
||||
@@ -366,7 +369,7 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac
|
||||
}
|
||||
|
||||
// Update Ticket Last Response Field & set ticket to open as client has replied
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 2 WHERE ticket_id = $ticket_id AND ticket_client_id = $client_id LIMIT 1");
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_status = 2, ticket_resolved_at = NULL WHERE ticket_id = $ticket_id AND ticket_client_id = $client_id LIMIT 1");
|
||||
|
||||
echo "Updated existing ticket.<br>";
|
||||
mysqli_query($mysqli, "INSERT INTO logs SET log_type = 'Ticket', log_action = 'Update', log_description = 'Email parser: Client contact $from_email updated ticket $config_ticket_prefix$ticket_number ($subject)', log_client_id = $client_id");
|
||||
|
||||
@@ -145,7 +145,7 @@ if (isset($_POST['login'])) {
|
||||
}
|
||||
|
||||
// Validate MFA code
|
||||
if (TokenAuth6238::verify($token, $current_code)) {
|
||||
if (!empty($current_code) && TokenAuth6238::verify($token, $current_code)) {
|
||||
$mfa_is_complete = true;
|
||||
$extended_log = 'with 2FA';
|
||||
}
|
||||
|
||||
2
plugins/tinymce/icons/default/icons.min.js
vendored
2
plugins/tinymce/icons/default/icons.min.js
vendored
File diff suppressed because one or more lines are too long
4
plugins/tinymce/models/dom/model.min.js
vendored
4
plugins/tinymce/models/dom/model.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=(t,e,s)=>{const r="UL"===e?"InsertUnorderedList":"InsertOrderedList";t.execCommand(r,!1,!1===s?null:{"list-style-type":s})},s=t=>e=>e.options.get(t),r=s("advlist_number_styles"),n=s("advlist_bullet_styles"),i=t=>null==t,l=t=>!i(t);var o=tinymce.util.Tools.resolve("tinymce.util.Tools");class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return l(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=t=>e=>l(e)&&t.test(e.nodeName),d=u(/^(OL|UL|DL)$/),g=u(/^(TH|TD)$/),c=t=>i(t)||"default"===t?"":t,h=(t,e)=>s=>((t,e)=>{const s=t.selection.getNode();return e({parents:t.dom.getParents(s),element:s}),t.on("NodeChange",e),()=>t.off("NodeChange",e)})(t,(r=>((t,r)=>{const n=t.selection.getStart(!0);s.setActive(((t,e,s)=>((t,e,s)=>{for(let e=0,n=t.length;e<n;e++){const n=t[e];if(d(r=n)&&!/\btox\-/.test(r.className))return a.some(n);if(s(n,e))break}var r;return a.none()})(e,0,g).exists((e=>e.nodeName===s&&((t,e)=>t.dom.isChildOf(e,t.getBody()))(t,e))))(t,r,e)),s.setEnabled(!((t,e)=>{const s=t.dom.getParent(e,"ol,ul,dl");return((t,e)=>null!==e&&!t.dom.isEditable(e))(t,s)&&t.selection.isEditable()})(t,n)&&t.selection.isEditable())})(t,r.parents))),m=(t,s,r,n,i,l)=>{l.length>1?((t,s,r,n,i,l)=>{t.ui.registry.addSplitButton(s,{tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",presets:"listpreview",columns:3,fetch:t=>{t(o.map(l,(t=>{const e="OL"===i?"num":"bull",s="disc"===t||"decimal"===t?"default":t,r=c(t),n=(t=>t.replace(/\-/g," ").replace(/\b\w/g,(t=>t.toUpperCase())))(t);return{type:"choiceitem",value:r,icon:"list-"+e+"-"+s,text:n}})))},onAction:()=>t.execCommand(n),onItemAction:(s,r)=>{e(t,i,r)},select:e=>{const s=(t=>{const e=t.dom.getParent(t.selection.getNode(),"ol,ul"),s=t.dom.getStyle(e,"listStyleType");return a.from(s)})(t);return s.map((t=>e===t)).getOr(!1)},onSetup:h(t,i)})})(t,s,r,n,i,l):((t,s,r,n,i,l)=>{t.ui.registry.addToggleButton(s,{active:!1,tooltip:r,icon:"OL"===i?"ordered-list":"unordered-list",onSetup:h(t,i),onAction:()=>t.queryCommandState(n)||""===l?t.execCommand(n):e(t,i,l)})})(t,s,r,n,i,c(l[0]))};t.add("advlist",(t=>{t.hasPlugin("lists")?((t=>{const e=t.options.register;e("advlist_number_styles",{processor:"string[]",default:"default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman".split(",")}),e("advlist_bullet_styles",{processor:"string[]",default:"default,circle,square".split(",")})})(t),(t=>{m(t,"numlist","Numbered list","InsertOrderedList","OL",r(t)),m(t,"bullist","Bullet list","InsertUnorderedList","UL",n(t))})(t),(t=>{t.addCommand("ApplyUnorderedListStyle",((s,r)=>{e(t,"UL",r["list-style-type"])})),t.addCommand("ApplyOrderedListStyle",((s,r)=>{e(t,"OL",r["list-style-type"])}))})(t)):console.error("Please use the Lists plugin together with the List Styles plugin.")}))}();
|
||||
2
plugins/tinymce/plugins/anchor/plugin.min.js
vendored
2
plugins/tinymce/plugins/anchor/plugin.min.js
vendored
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.dom.RangeUtils"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=("allow_html_in_named_anchor",e=>e.options.get("allow_html_in_named_anchor"));const a="a:not([href])",r=e=>!e,i=e=>e.getAttribute("id")||e.getAttribute("name")||"",l=e=>(e=>"a"===e.nodeName.toLowerCase())(e)&&!e.getAttribute("href")&&""!==i(e),s=e=>e.dom.getParent(e.selection.getStart(),a),d=(e,a)=>{const r=s(e);r?((e,t,o)=>{o.removeAttribute("name"),o.id=t,e.addVisual(),e.undoManager.add()})(e,a,r):((e,a)=>{e.undoManager.transact((()=>{n(e)||e.selection.collapse(!0),e.selection.isCollapsed()?e.insertContent(e.dom.createHTML("a",{id:a})):((e=>{const n=e.dom;t(n).walk(e.selection.getRng(),(e=>{o.each(e,(e=>{var t;l(t=e)&&!t.firstChild&&n.remove(e,!1)}))}))})(e),e.formatter.remove("namedAnchor",void 0,void 0,!0),e.formatter.apply("namedAnchor",{value:a}),e.addVisual())}))})(e,a),e.focus()},c=e=>(e=>r(e.attr("href"))&&!r(e.attr("id")||e.attr("name")))(e)&&!e.firstChild,m=e=>t=>{for(let o=0;o<t.length;o++){const n=t[o];c(n)&&n.attr("contenteditable",e)}},u=e=>t=>{const o=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",o),o(),()=>{e.off("NodeChange",o)}};e.add("anchor",(e=>{(e=>{(0,e.options.register)("allow_html_in_named_anchor",{processor:"boolean",default:!1})})(e),(e=>{e.on("PreInit",(()=>{e.parser.addNodeFilter("a",m("false")),e.serializer.addNodeFilter("a",m(null))}))})(e),(e=>{e.addCommand("mceAnchor",(()=>{(e=>{const t=(e=>{const t=s(e);return t?i(t):""})(e);e.windowManager.open({title:"Anchor",size:"normal",body:{type:"panel",items:[{name:"id",type:"input",label:"ID",placeholder:"example"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{id:t},onSubmit:t=>{((e,t)=>/^[A-Za-z][A-Za-z0-9\-:._]*$/.test(t)?(d(e,t),!0):(e.windowManager.alert("ID should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores."),!1))(e,t.getData().id)&&t.close()}})})(e)}))})(e),(e=>{const t=()=>e.execCommand("mceAnchor");e.ui.registry.addToggleButton("anchor",{icon:"bookmark",tooltip:"Anchor",onAction:t,onSetup:t=>{const o=e.selection.selectorChangedWithUnbind("a:not([href])",t.setActive).unbind,n=u(e)(t);return()=>{o(),n()}}}),e.ui.registry.addMenuItem("anchor",{icon:"bookmark",text:"Anchor...",onAction:t,onSetup:u(e)})})(e),e.on("PreInit",(()=>{(e=>{e.formatter.register("namedAnchor",{inline:"a",selector:a,remove:"all",split:!0,deep:!0,attributes:{id:"%value"},onmatch:(e,t,o)=>l(e)})})(e)}))}))}();
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),n=t("autolink_pattern"),o=t("link_default_target"),r=t("link_default_protocol"),a=t("allow_unsafe_link_target"),s=("string",e=>"string"===(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(n=o=e,(r=String).prototype.isPrototypeOf(n)||(null===(a=o.constructor)||void 0===a?void 0:a.name)===r.name)?"string":t;var n,o,r,a})(e));const l=(void 0,e=>undefined===e);const i=e=>!(e=>null==e)(e),c=Object.hasOwnProperty,d=e=>"\ufeff"===e;var u=tinymce.util.Tools.resolve("tinymce.dom.TextSeeker");const f=e=>/^[(\[{ \u00a0]$/.test(e),g=(e,t,n)=>{for(let o=t-1;o>=0;o--){const t=e.charAt(o);if(!d(t)&&n(t))return o}return-1},m=(e,t)=>{var o;const a=e.schema.getVoidElements(),s=n(e),{dom:i,selection:d}=e;if(null!==i.getParent(d.getNode(),"a[href]"))return null;const m=d.getRng(),k=u(i,(e=>{return i.isBlock(e)||(t=a,n=e.nodeName.toLowerCase(),c.call(t,n))||"false"===i.getContentEditable(e);var t,n})),{container:p,offset:y}=((e,t)=>{let n=e,o=t;for(;1===n.nodeType&&n.childNodes[o];)n=n.childNodes[o],o=3===n.nodeType?n.data.length:n.childNodes.length;return{container:n,offset:o}})(m.endContainer,m.endOffset),w=null!==(o=i.getParent(p,i.isBlock))&&void 0!==o?o:i.getRoot(),h=k.backwards(p,y+t,((e,t)=>{const n=e.data,o=g(n,t,(r=f,e=>!r(e)));var r,a;return-1===o||(a=n[o],/[?!,.;:]/.test(a))?o:o+1}),w);if(!h)return null;let v=h.container;const _=k.backwards(h.container,h.offset,((e,t)=>{v=e;const n=g(e.data,t,f);return-1===n?n:n+1}),w),A=i.createRng();_?A.setStart(_.container,_.offset):A.setStart(v,0),A.setEnd(h.container,h.offset);const C=A.toString().replace(/\uFEFF/g,"").match(s);if(C){let t=C[0];return $="www.",(b=t).length>=4&&b.substr(0,4)===$?t=r(e)+"://"+t:((e,t,n=0,o)=>{const r=e.indexOf(t,n);return-1!==r&&(!!l(o)||r+t.length<=o)})(t,"@")&&!(e=>/^([A-Za-z][A-Za-z\d.+-]*:\/\/)|mailto:/.test(e))(t)&&(t="mailto:"+t),{rng:A,url:t}}var b,$;return null},k=(e,t)=>{const{dom:n,selection:r}=e,{rng:l,url:i}=t,c=r.getBookmark();r.setRng(l);const d="createlink",u={command:d,ui:!1,value:i};if(!e.dispatch("BeforeExecCommand",u).isDefaultPrevented()){e.getDoc().execCommand(d,!1,i),e.dispatch("ExecCommand",u);const t=o(e);if(s(t)){const o=r.getNode();n.setAttrib(o,"target",t),"_blank"!==t||a(e)||n.setAttrib(o,"rel","noopener")}}r.moveToBookmark(c),e.nodeChanged()},p=e=>{const t=m(e,-1);i(t)&&k(e,t)},y=p;e.add("autolink",(e=>{(e=>{const t=e.options.register;t("autolink_pattern",{processor:"regexp",default:new RegExp("^"+/(?:[A-Za-z][A-Za-z\d.+-]{0,14}:\/\/(?:[-.~*+=!&;:'%@?^${}(),\w]+@)?|www\.|[-;:&=+$,.\w]+@)[A-Za-z\d-]+(?:\.[A-Za-z\d-]+)*(?::\d+)?(?:\/(?:[-.~*+=!;:'%@$(),\/\w]*[-~*+=%@$()\/\w])?)?(?:\?(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?(?:#(?:[-.~*+=!&;:'%@?^${}(),\/\w]+))?/g.source+"$","i")}),t("link_default_target",{processor:"string"}),t("link_default_protocol",{processor:"string",default:"https"})})(e),(e=>{e.on("keydown",(t=>{13!==t.keyCode||t.isDefaultPrevented()||(e=>{const t=m(e,0);i(t)&&k(e,t)})(e)})),e.on("keyup",(t=>{32===t.keyCode?p(e):(48===t.keyCode&&t.shiftKey||221===t.keyCode)&&y(e)}))})(e)}))}();
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),s=o("min_height"),i=o("max_height"),n=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),l=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},g=(e,t,o,s)=>{var i;const n=parseInt(null!==(i=e.getStyle(t,o,s))&&void 0!==i?i:"",10);return isNaN(n)?0:n},a=(e,o,r,c)=>{var d;const f=e.dom,u=e.getDoc();if(!u)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void l(e,!0);const m=u.documentElement,h=c?c():n(e),p=null!==(d=s(e))&&void 0!==d?d:e.getElement().offsetHeight;let y=p;const S=g(f,m,"margin-top",!0),v=g(f,m,"margin-bottom",!0);let C=m.offsetHeight+S+v+h;C<0&&(C=0);const b=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+b>p&&(y=C+b);const w=i(e);if(w&&y>w?(y=w,l(e,!0)):l(e,!1),y!==o.get()){const s=y-o.get();if(f.setStyle(e.getContainer(),"height",y+"px"),o.set(y),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(r)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&s<0&&a(e,o,r,c)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const o=(e=>{let t=0;return{get:()=>t,set:e=>{t=e}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{a(e,t)}))})(e,o),((e,o)=>{let s,i,l=()=>r(e);e.on("init",(i=>{s=0;const r=n(e),g=e.dom;g.setStyles(e.getDoc().documentElement,{height:"auto"}),t.browser.isEdge()||t.browser.isIE()?g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r,"min-height":0}):g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r}),a(e,o,i,l),s+=1})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(t=>{if(1===s)i=e.getContainer().offsetHeight,a(e,o,t,l),s+=1;else if(2===s){const t=i<e.getContainer().offsetHeight;if(t){const t=e.dom,o=e.getDoc();t.setStyles(o.documentElement,{"min-height":0}),t.setStyles(e.getBody(),{"min-height":"inherit"})}l=t?(0,()=>0):l,s+=1}else a(e,o,t,l)}))})(e,o)}}))}();
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env");const o=e=>t=>t.options.get(e),n=o("min_height"),s=o("max_height"),i=o("autoresize_overflow_padding"),r=o("autoresize_bottom_margin"),g=(e,t)=>{const o=e.getBody();o&&(o.style.overflowY=t?"":"hidden",t||(o.scrollTop=0))},l=(e,t,o,n)=>{var s;const i=parseInt(null!==(s=e.getStyle(t,o,n))&&void 0!==s?s:"",10);return isNaN(i)?0:i},a=(e,o,r,c)=>{var d;const u=e.dom,h=e.getDoc();if(!h)return;if((e=>e.plugins.fullscreen&&e.plugins.fullscreen.isFullscreen())(e))return void g(e,!0);const m=h.documentElement,f=c?c():i(e),p=null!==(d=n(e))&&void 0!==d?d:e.getElement().offsetHeight;let y=p;const S=l(u,m,"margin-top",!0),v=l(u,m,"margin-bottom",!0);let C=m.offsetHeight+S+v+f;C<0&&(C=0);const H=e.getContainer().offsetHeight-e.getContentAreaContainer().offsetHeight;C+H>p&&(y=C+H);const b=s(e);b&&y>b?(y=b,g(e,!0)):g(e,!1);const w=o.get();if(w.set&&(e.dom.setStyles(e.getDoc().documentElement,{"min-height":0}),e.dom.setStyles(e.getBody(),{"min-height":"inherit"})),y!==w.totalHeight&&(C-f!==w.contentHeight||!w.set)){const n=y-w.totalHeight;if(u.setStyle(e.getContainer(),"height",y+"px"),o.set({totalHeight:y,contentHeight:C,set:!0}),(e=>{e.dispatch("ResizeEditor")})(e),t.browser.isSafari()&&(t.os.isMacOS()||t.os.isiOS())){const t=e.getWin();t.scrollTo(t.pageXOffset,t.pageYOffset)}e.hasFocus()&&(e=>{if("setcontent"===(null==e?void 0:e.type.toLowerCase())){const t=e;return!0===t.selection||!0===t.paste}return!1})(r)&&e.selection.scrollIntoView(),(t.browser.isSafari()||t.browser.isChromium())&&n<0&&a(e,o,r,c)}};e.add("autoresize",(e=>{if((e=>{const t=e.options.register;t("autoresize_overflow_padding",{processor:"number",default:1}),t("autoresize_bottom_margin",{processor:"number",default:50})})(e),e.options.isSet("resize")||e.options.set("resize",!1),!e.inline){const o=(e=>{let t={totalHeight:0,contentHeight:0,set:!1};return{get:()=>t,set:e=>{t=e}}})();((e,t)=>{e.addCommand("mceAutoResize",(()=>{a(e,t)}))})(e,o),((e,o)=>{const n=()=>r(e);e.on("init",(s=>{const r=i(e),g=e.dom;g.setStyles(e.getDoc().documentElement,{height:"auto"}),t.browser.isEdge()||t.browser.isIE()?g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r,"min-height":0}):g.setStyles(e.getBody(),{paddingLeft:r,paddingRight:r}),a(e,o,s,n)})),e.on("NodeChange SetContent keyup FullscreenStateChanged ResizeContent",(t=>{a(e,o,t,n)}))})(e,o)}}))}();
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=("string",t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(r=o=t,(a=String).prototype.isPrototypeOf(r)||(null===(s=o.constructor)||void 0===s?void 0:s.name)===a.name)?"string":e;var r,o,a,s})(t));const r=(void 0,t=>undefined===t);var o=tinymce.util.Tools.resolve("tinymce.util.Delay"),a=tinymce.util.Tools.resolve("tinymce.util.LocalStorage"),s=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=t=>{const e=/^(\d+)([ms]?)$/.exec(t);return(e&&e[2]?{s:1e3,m:6e4}[e[2]]:1)*parseInt(t,10)},i=t=>e=>e.options.get(t),u=i("autosave_ask_before_unload"),l=i("autosave_restore_when_empty"),c=i("autosave_interval"),d=i("autosave_retention"),m=t=>{const e=document.location;return t.options.get("autosave_prefix").replace(/{path}/g,e.pathname).replace(/{query}/g,e.search).replace(/{hash}/g,e.hash).replace(/{id}/g,t.id)},v=(t,e)=>{if(r(e))return t.dom.isEmpty(t.getBody());{const r=s.trim(e);if(""===r)return!0;{const e=(new DOMParser).parseFromString(r,"text/html");return t.dom.isEmpty(e)}}},f=t=>{var e;const r=parseInt(null!==(e=a.getItem(m(t)+"time"))&&void 0!==e?e:"0",10)||0;return!((new Date).getTime()-r>d(t)&&(p(t,!1),1))},p=(t,e)=>{const r=m(t);a.removeItem(r+"draft"),a.removeItem(r+"time"),!1!==e&&(t=>{t.dispatch("RemoveDraft")})(t)},g=t=>{const e=m(t);!v(t)&&t.isDirty()&&(a.setItem(e+"draft",t.getContent({format:"raw",no_events:!0})),a.setItem(e+"time",(new Date).getTime().toString()),(t=>{t.dispatch("StoreDraft")})(t))},y=t=>{var e;const r=m(t);f(t)&&(t.setContent(null!==(e=a.getItem(r+"draft"))&&void 0!==e?e:"",{format:"raw"}),(t=>{t.dispatch("RestoreDraft")})(t))};var D=tinymce.util.Tools.resolve("tinymce.EditorManager");const h=t=>e=>{e.setEnabled(f(t));const r=()=>e.setEnabled(f(t));return t.on("StoreDraft RestoreDraft RemoveDraft",r),()=>t.off("StoreDraft RestoreDraft RemoveDraft",r)};t.add("autosave",(t=>((t=>{const r=t.options.register,o=t=>{const r=e(t);return r?{value:n(t),valid:r}:{valid:!1,message:"Must be a string."}};r("autosave_ask_before_unload",{processor:"boolean",default:!0}),r("autosave_prefix",{processor:"string",default:"tinymce-autosave-{path}{query}{hash}-{id}-"}),r("autosave_restore_when_empty",{processor:"boolean",default:!1}),r("autosave_interval",{processor:o,default:"30s"}),r("autosave_retention",{processor:o,default:"20m"})})(t),(t=>{t.editorManager.on("BeforeUnload",(t=>{let e;s.each(D.get(),(t=>{t.plugins.autosave&&t.plugins.autosave.storeDraft(),!e&&t.isDirty()&&u(t)&&(e=t.translate("You have unsaved changes are you sure you want to navigate away?"))})),e&&(t.preventDefault(),t.returnValue=e)}))})(t),(t=>{(t=>{const e=c(t);o.setEditorInterval(t,(()=>{g(t)}),e)})(t);const e=()=>{(t=>{t.undoManager.transact((()=>{y(t),p(t)})),t.focus()})(t)};t.ui.registry.addButton("restoredraft",{tooltip:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)}),t.ui.registry.addMenuItem("restoredraft",{text:"Restore last draft",icon:"restore-draft",onAction:e,onSetup:h(t)})})(t),t.on("init",(()=>{l(t)&&t.dom.isEmpty(t.getBody())&&y(t)})),(t=>({hasDraft:()=>f(t),storeDraft:()=>g(t),restoreDraft:()=>y(t),removeDraft:e=>p(t,e),isEmpty:e=>v(t,e)}))(t))))}();
|
||||
File diff suppressed because one or more lines are too long
2
plugins/tinymce/plugins/code/plugin.min.js
vendored
2
plugins/tinymce/plugins/code/plugin.min.js
vendored
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";tinymce.util.Tools.resolve("tinymce.PluginManager").add("code",(e=>((e=>{e.addCommand("mceCodeEditor",(()=>{(e=>{const o=(e=>e.getContent({source_view:!0}))(e);e.windowManager.open({title:"Source Code",size:"large",body:{type:"panel",items:[{type:"textarea",name:"code"}]},buttons:[{type:"cancel",name:"cancel",text:"Cancel"},{type:"submit",name:"save",text:"Save",primary:!0}],initialData:{code:o},onSubmit:o=>{((e,o)=>{e.focus(),e.undoManager.transact((()=>{e.setContent(o)})),e.selection.setCursorLocation(),e.nodeChanged()})(e,o.getData().code),o.close()}})})(e)}))})(e),(e=>{const o=()=>e.execCommand("mceCodeEditor");e.ui.registry.addButton("code",{icon:"sourcecode",tooltip:"Source code",onAction:o}),e.ui.registry.addMenuItem("code",{icon:"sourcecode",text:"Source code",onAction:o})})(e),{})))}();
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=r=t,(n=String).prototype.isPrototypeOf(o)||(null===(i=r.constructor)||void 0===i?void 0:i.name)===n.name)?"string":e;var o,r,n,i})(t),r=e("boolean"),n=t=>!(t=>null==t)(t),i=e("function"),s=e("number"),l=(!1,()=>false);class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return n(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=(t,e)=>{for(let o=0,r=t.length;o<r;o++)e(t[o],o)},c=t=>{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},d=c,h=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}};"undefined"!=typeof window?window:Function("return this;")();const m=t=>e=>(t=>t.dom.nodeType)(e)===t,g=m(1),f=m(3),v=m(9),y=m(11),p=(t,e)=>{t.dom.removeAttribute(e)},w=i(Element.prototype.attachShadow)&&i(Node.prototype.getRootNode)?t=>d(t.dom.getRootNode()):t=>v(t)?t:d(t.dom.ownerDocument),b=t=>d(t.dom.host),N=t=>{const e=f(t)?t.dom.parentNode:t.dom;if(null==e||null===e.ownerDocument)return!1;const o=e.ownerDocument;return(t=>{const e=w(t);return y(o=e)&&n(o.dom.host)?a.some(e):a.none();var o})(d(e)).fold((()=>o.body.contains(e)),(r=N,i=b,t=>r(i(t))));var r,i},S=t=>"rtl"===((t,e)=>{const o=t.dom,r=window.getComputedStyle(o).getPropertyValue(e);return""!==r||N(t)?r:((t,e)=>(t=>void 0!==t.style&&i(t.style.getPropertyValue))(t)?t.style.getPropertyValue(e):"")(o,e)})(t,"direction")?"rtl":"ltr",A=(t,e)=>((t,o)=>((t,e)=>{const o=[];for(let r=0,n=t.length;r<n;r++){const n=t[r];e(n,r)&&o.push(n)}return o})(((t,e)=>{const o=t.length,r=new Array(o);for(let n=0;n<o;n++){const o=t[n];r[n]=e(o,n)}return r})(t.dom.childNodes,d),(t=>h(t,e))))(t),E=("li",t=>g(t)&&"li"===t.dom.nodeName.toLowerCase());const T=(t,e,n)=>{u(e,(e=>{const c=d(e),m=E(c),f=((t,e)=>{return(e?(o=t,r="ol,ul",((t,e,o)=>{let n=t.dom;const s=i(o)?o:l;for(;n.parentNode;){n=n.parentNode;const t=d(n);if(h(t,r))return a.some(t);if(s(t))break}return a.none()})(o,0,n)):a.some(t)).getOr(t);var o,r,n})(c,m);var v;(v=f,(t=>a.from(t.dom.parentNode).map(d))(v).filter(g)).each((e=>{if(t.setStyle(f.dom,"direction",null),S(e)===n?p(f,"dir"):((t,e,n)=>{((t,e,n)=>{if(!(o(n)||r(n)||s(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)})(f,"dir",n),S(f)!==n&&t.setStyle(f.dom,"direction",n),m){const e=A(f,"li[dir],li[style]");u(e,(e=>{p(e,"dir"),t.setStyle(e.dom,"direction",null)}))}}))}))},C=(t,e)=>{t.selection.isEditable()&&(T(t.dom,t.selection.getSelectedBlocks(),e),t.nodeChanged())},D=(t,e)=>o=>{const r=r=>{const n=d(r.element);o.setActive(S(n)===e),o.setEnabled(t.selection.isEditable())};return t.on("NodeChange",r),o.setEnabled(t.selection.isEditable()),()=>t.off("NodeChange",r)};t.add("directionality",(t=>{(t=>{t.addCommand("mceDirectionLTR",(()=>{C(t,"ltr")})),t.addCommand("mceDirectionRTL",(()=>{C(t,"rtl")}))})(t),(t=>{t.ui.registry.addToggleButton("ltr",{tooltip:"Left to right",icon:"ltr",onAction:()=>t.execCommand("mceDirectionLTR"),onSetup:D(t,"ltr")}),t.ui.registry.addToggleButton("rtl",{tooltip:"Right to left",icon:"rtl",onAction:()=>t.execCommand("mceDirectionRTL"),onSetup:D(t,"rtl")})})(t)}))}();
|
||||
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=t=>e=>typeof e===t,o=t=>"string"===(t=>{const e=typeof t;return null===t?"null":"object"===e&&Array.isArray(t)?"array":"object"===e&&(o=r=t,(n=String).prototype.isPrototypeOf(o)||(null===(i=r.constructor)||void 0===i?void 0:i.name)===n.name)?"string":e;var o,r,n,i})(t),r=e("boolean"),n=t=>!(t=>null==t)(t),i=e("function"),s=e("number"),l=(!1,()=>false);class a{constructor(t,e){this.tag=t,this.value=e}static some(t){return new a(!0,t)}static none(){return a.singletonNone}fold(t,e){return this.tag?e(this.value):t()}isSome(){return this.tag}isNone(){return!this.tag}map(t){return this.tag?a.some(t(this.value)):a.none()}bind(t){return this.tag?t(this.value):a.none()}exists(t){return this.tag&&t(this.value)}forall(t){return!this.tag||t(this.value)}filter(t){return!this.tag||t(this.value)?this:a.none()}getOr(t){return this.tag?this.value:t}or(t){return this.tag?this:t}getOrThunk(t){return this.tag?this.value:t()}orThunk(t){return this.tag?this:t()}getOrDie(t){if(this.tag)return this.value;throw new Error(null!=t?t:"Called getOrDie on None")}static from(t){return n(t)?a.some(t):a.none()}getOrNull(){return this.tag?this.value:null}getOrUndefined(){return this.value}each(t){this.tag&&t(this.value)}toArray(){return this.tag?[this.value]:[]}toString(){return this.tag?`some(${this.value})`:"none()"}}a.singletonNone=new a(!1);const u=(t,e)=>{for(let o=0,r=t.length;o<r;o++)e(t[o],o)},c=t=>{if(null==t)throw new Error("Node cannot be null or undefined");return{dom:t}},d=c,h=(t,e)=>{const o=t.dom;if(1!==o.nodeType)return!1;{const t=o;if(void 0!==t.matches)return t.matches(e);if(void 0!==t.msMatchesSelector)return t.msMatchesSelector(e);if(void 0!==t.webkitMatchesSelector)return t.webkitMatchesSelector(e);if(void 0!==t.mozMatchesSelector)return t.mozMatchesSelector(e);throw new Error("Browser lacks native selectors")}};"undefined"!=typeof window?window:Function("return this;")();const m=t=>e=>(t=>t.dom.nodeType)(e)===t,g=m(1),f=m(3),v=m(11),y=(t,e)=>{t.dom.removeAttribute(e)},p=t=>d(t.dom.host),w=t=>{const e=f(t)?t.dom.parentNode:t.dom;if(null==e||null===e.ownerDocument)return!1;const o=e.ownerDocument;return(t=>{const e=(t=>d(t.dom.getRootNode()))(t);return v(o=e)&&n(o.dom.host)?a.some(e):a.none();var o})(d(e)).fold((()=>o.body.contains(e)),(r=w,i=p,t=>r(i(t))));var r,i},b=t=>"rtl"===((t,e)=>{const o=t.dom,r=window.getComputedStyle(o).getPropertyValue(e);return""!==r||w(t)?r:((t,e)=>(t=>void 0!==t.style&&i(t.style.getPropertyValue))(t)?t.style.getPropertyValue(e):"")(o,e)})(t,"direction")?"rtl":"ltr",S=(t,e)=>((t,o)=>((t,e)=>{const o=[];for(let r=0,n=t.length;r<n;r++){const n=t[r];e(n,r)&&o.push(n)}return o})(((t,e)=>{const o=t.length,r=new Array(o);for(let n=0;n<o;n++){const o=t[n];r[n]=e(o,n)}return r})(t.dom.childNodes,d),(t=>h(t,e))))(t),N=("li",t=>g(t)&&"li"===t.dom.nodeName.toLowerCase());const A=(t,e,n)=>{u(e,(e=>{const c=d(e),m=N(c),f=((t,e)=>{return(e?(o=t,r="ol,ul",((t,e,o)=>{let n=t.dom;const s=i(o)?o:l;for(;n.parentNode;){n=n.parentNode;const t=d(n);if(h(t,r))return a.some(t);if(s(t))break}return a.none()})(o,0,n)):a.some(t)).getOr(t);var o,r,n})(c,m);var v;(v=f,(t=>a.from(t.dom.parentNode).map(d))(v).filter(g)).each((e=>{if(t.setStyle(f.dom,"direction",null),b(e)===n?y(f,"dir"):((t,e,n)=>{((t,e,n)=>{if(!(o(n)||r(n)||s(n)))throw console.error("Invalid call to Attribute.set. Key ",e,":: Value ",n,":: Element ",t),new Error("Attribute value was not simple");t.setAttribute(e,n+"")})(t.dom,e,n)})(f,"dir",n),b(f)!==n&&t.setStyle(f.dom,"direction",n),m){const e=S(f,"li[dir],li[style]");u(e,(e=>{y(e,"dir"),t.setStyle(e.dom,"direction",null)}))}}))}))},T=(t,e)=>{t.selection.isEditable()&&(A(t.dom,t.selection.getSelectedBlocks(),e),t.nodeChanged())},C=(t,e)=>o=>{const r=r=>{const n=d(r.element);o.setActive(b(n)===e),o.setEnabled(t.selection.isEditable())};return t.on("NodeChange",r),o.setEnabled(t.selection.isEditable()),()=>t.off("NodeChange",r)};t.add("directionality",(t=>{(t=>{t.addCommand("mceDirectionLTR",(()=>{T(t,"ltr")})),t.addCommand("mceDirectionRTL",(()=>{T(t,"rtl")}))})(t),(t=>{t.ui.registry.addToggleButton("ltr",{tooltip:"Left to right",icon:"ltr",onAction:()=>t.execCommand("mceDirectionLTR"),onSetup:C(t,"ltr")}),t.ui.registry.addToggleButton("rtl",{tooltip:"Right to left",icon:"rtl",onAction:()=>t.execCommand("mceDirectionRTL"),onSetup:C(t,"rtl")})})(t)}))}();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
plugins/tinymce/plugins/help/plugin.min.js
vendored
4
plugins/tinymce/plugins/help/plugin.min.js
vendored
File diff suppressed because one or more lines are too long
2
plugins/tinymce/plugins/image/plugin.min.js
vendored
2
plugins/tinymce/plugins/image/plugin.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>(e=>{const t=typeof e;return null===e?"null":"object"===t&&Array.isArray(e)?"array":"object"===t&&(s=r=e,(o=String).prototype.isPrototypeOf(s)||(null===(n=r.constructor)||void 0===n?void 0:n.name)===o.name)?"string":t;var s,r,o,n})(t)===e,s=t("string"),r=t("object"),o=t("array"),n=("function",e=>"function"==typeof e);var c=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),i=tinymce.util.Tools.resolve("tinymce.EditorManager"),l=tinymce.util.Tools.resolve("tinymce.Env"),a=tinymce.util.Tools.resolve("tinymce.util.Tools");const p=e=>t=>t.options.get(e),u=p("importcss_merge_classes"),m=p("importcss_exclusive"),f=p("importcss_selector_converter"),y=p("importcss_selector_filter"),d=p("importcss_groups"),h=p("importcss_append"),g=p("importcss_file_filter"),_=p("skin"),v=p("skin_url"),b=Array.prototype.push,x=/^\.(?:ephox|tiny-pageembed|mce)(?:[.-]+\w+)+$/,T=e=>s(e)?t=>-1!==t.indexOf(e):e instanceof RegExp?t=>e.test(t):e,S=(e,t)=>{let s={};const r=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(t);if(!r)return;const o=r[1],n=r[2].substr(1).split(".").join(" "),c=a.makeMap("a,img");return r[1]?(s={title:t},e.schema.getTextBlockElements()[o]?s.block=o:e.schema.getBlockElements()[o]||c[o.toLowerCase()]?s.selector=o:s.inline=o):r[2]&&(s={inline:"span",title:t.substr(1),classes:n}),u(e)?s.classes=n:s.attributes={class:n},s},k=(e,t)=>null===t||m(e),M=e=>{e.on("init",(()=>{const t=(()=>{const e=[],t=[],s={};return{addItemToGroup:(e,r)=>{s[e]?s[e].push(r):(t.push(e),s[e]=[r])},addItem:t=>{e.push(t)},toFormats:()=>{return(r=t,n=e=>{const t=s[e];return 0===t.length?[]:[{title:e,items:t}]},(e=>{const t=[];for(let s=0,r=e.length;s<r;++s){if(!o(e[s]))throw new Error("Arr.flatten item "+s+" was not an array, input: "+e);b.apply(t,e[s])}return t})(((e,t)=>{const s=e.length,r=new Array(s);for(let o=0;o<s;o++){const s=e[o];r[o]=t(s,o)}return r})(r,n))).concat(e);var r,n}}})(),r={},n=T(y(e)),p=(e=>a.map(e,(e=>a.extend({},e,{original:e,selectors:{},filter:T(e.filter)}))))(d(e)),u=(t,s)=>{if(((e,t,s,r)=>!(k(e,s)?t in r:t in s.selectors))(e,t,s,r)){((e,t,s,r)=>{k(e,s)?r[t]=!0:s.selectors[t]=!0})(e,t,s,r);const o=((e,t,s,r)=>{let o;const n=f(e);return o=r&&r.selector_converter?r.selector_converter:n||(()=>S(e,s)),o.call(t,s,r)})(e,e.plugins.importcss,t,s);if(o){const t=o.name||c.DOM.uniqueId();return e.formatter.register(t,o),{title:o.title,format:t}}}return null};a.each(((e,t,r)=>{const o=[],n={},c=(t,n)=>{let p,u=t.href;if(u=(e=>{const t=l.cacheSuffix;return s(e)&&(e=e.replace("?"+t,"").replace("&"+t,"")),e})(u),u&&(!r||r(u,n))&&!((e,t)=>{const s=_(e);if(s){const r=v(e),o=r?e.documentBaseURI.toAbsolute(r):i.baseURL+"/skins/ui/"+s,n=i.baseURL+"/skins/content/",c=e.editorManager.suffix;return t===o+"/content"+(e.inline?".inline":"")+`${c}.css`||-1!==t.indexOf(n)}return!1})(e,u)){a.each(t.imports,(e=>{c(e,!0)}));try{p=t.cssRules||t.rules}catch(e){}a.each(p,(e=>{e.styleSheet&&e.styleSheet?c(e.styleSheet,!0):e.selectorText&&a.each(e.selectorText.split(","),(e=>{o.push(a.trim(e))}))}))}};a.each(e.contentCSS,(e=>{n[e]=!0})),r||(r=(e,t)=>t||n[e]);try{a.each(t.styleSheets,(e=>{c(e)}))}catch(e){}return o})(e,e.getDoc(),T(g(e))),(e=>{if(!x.test(e)&&(!n||n(e))){const s=((e,t)=>a.grep(e,(e=>!e.filter||e.filter(t))))(p,e);if(s.length>0)a.each(s,(s=>{const r=u(e,s);r&&t.addItemToGroup(s.title,r)}));else{const s=u(e,null);s&&t.addItem(s)}}}));const m=t.toFormats();e.dispatch("addStyleModifications",{items:m,replace:!h(e)})}))};e.add("importcss",(e=>((e=>{const t=e.options.register,o=e=>s(e)||n(e)||r(e);t("importcss_merge_classes",{processor:"boolean",default:!0}),t("importcss_exclusive",{processor:"boolean",default:!0}),t("importcss_selector_converter",{processor:"function"}),t("importcss_selector_filter",{processor:o}),t("importcss_file_filter",{processor:o}),t("importcss_groups",{processor:"object[]"}),t("importcss_append",{processor:"boolean",default:!1})})(e),M(e),(e=>({convertSelectorToFormat:t=>S(e,t)}))(e))))}();
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const t=e=>t=>t.options.get(e),a=t("insertdatetime_dateformat"),n=t("insertdatetime_timeformat"),r=t("insertdatetime_formats"),s=t("insertdatetime_element"),i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),o="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),l="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),m="January February March April May June July August September October November December".split(" "),c=(e,t)=>{if((e=""+e).length<t)for(let a=0;a<t-e.length;a++)e="0"+e;return e},d=(e,t,a=new Date)=>(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=(t=t.replace("%D","%m/%d/%Y")).replace("%r","%I:%M:%S %p")).replace("%Y",""+a.getFullYear())).replace("%y",""+a.getYear())).replace("%m",c(a.getMonth()+1,2))).replace("%d",c(a.getDate(),2))).replace("%H",""+c(a.getHours(),2))).replace("%M",""+c(a.getMinutes(),2))).replace("%S",""+c(a.getSeconds(),2))).replace("%I",""+((a.getHours()+11)%12+1))).replace("%p",a.getHours()<12?"AM":"PM")).replace("%B",""+e.translate(m[a.getMonth()]))).replace("%b",""+e.translate(l[a.getMonth()]))).replace("%A",""+e.translate(o[a.getDay()]))).replace("%a",""+e.translate(i[a.getDay()]))).replace("%%","%"),u=(e,t)=>{if(s(e)){const a=d(e,t);let n;n=/%[HMSIp]/.test(t)?d(e,"%Y-%m-%dT%H:%M"):d(e,"%Y-%m-%d");const r=e.dom.getParent(e.selection.getStart(),"time");r?((e,t,a,n)=>{const r=e.dom.create("time",{datetime:a},n);e.dom.replace(r,t),e.selection.select(r,!0),e.selection.collapse(!1)})(e,r,n,a):e.insertContent('<time datetime="'+n+'">'+a+"</time>")}else e.insertContent(d(e,t))};var p=tinymce.util.Tools.resolve("tinymce.util.Tools");const g=e=>t=>{const a=()=>{t.setEnabled(e.selection.isEditable())};return e.on("NodeChange",a),a(),()=>{e.off("NodeChange",a)}};e.add("insertdatetime",(e=>{(e=>{const t=e.options.register;t("insertdatetime_dateformat",{processor:"string",default:e.translate("%Y-%m-%d")}),t("insertdatetime_timeformat",{processor:"string",default:e.translate("%H:%M:%S")}),t("insertdatetime_formats",{processor:"string[]",default:["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"]}),t("insertdatetime_element",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mceInsertDate",((t,n)=>{u(e,null!=n?n:a(e))})),e.addCommand("mceInsertTime",((t,a)=>{u(e,null!=a?a:n(e))}))})(e),(e=>{const t=r(e),a=(e=>{let t=e;return{get:()=>t,set:e=>{t=e}}})((e=>{const t=r(e);return t.length>0?t[0]:n(e)})(e)),s=t=>e.execCommand("mceInsertDate",!1,t);e.ui.registry.addSplitButton("insertdatetime",{icon:"insert-time",tooltip:"Insert date/time",select:e=>e===a.get(),fetch:a=>{a(p.map(t,(t=>({type:"choiceitem",text:d(e,t),value:t}))))},onAction:e=>{s(a.get())},onItemAction:(e,t)=>{a.set(t),s(t)},onSetup:g(e)});const i=e=>()=>{a.set(e),s(e)};e.ui.registry.addNestedMenuItem("insertdatetime",{icon:"insert-time",text:"Date/time",getSubmenuItems:()=>p.map(t,(t=>({type:"menuitem",text:d(e,t),onAction:i(t)}))),onSetup:g(e)})})(e)}))}();
|
||||
4
plugins/tinymce/plugins/link/plugin.min.js
vendored
4
plugins/tinymce/plugins/link/plugin.min.js
vendored
File diff suppressed because one or more lines are too long
4
plugins/tinymce/plugins/lists/plugin.min.js
vendored
4
plugins/tinymce/plugins/lists/plugin.min.js
vendored
File diff suppressed because one or more lines are too long
4
plugins/tinymce/plugins/media/plugin.min.js
vendored
4
plugins/tinymce/plugins/media/plugin.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var n=tinymce.util.Tools.resolve("tinymce.PluginManager");const e=n=>e=>typeof e===n,o=e("boolean"),a=e("number"),t=n=>e=>e.options.get(n),i=t("nonbreaking_force_tab"),s=t("nonbreaking_wrap"),r=(n,e)=>{let o="";for(let a=0;a<e;a++)o+=n;return o},c=(n,e)=>{const o=s(n)||n.plugins.visualchars?`<span class="${(n=>!!n.plugins.visualchars&&n.plugins.visualchars.isEnabled())(n)?"mce-nbsp-wrap mce-nbsp":"mce-nbsp-wrap"}" contenteditable="false">${r(" ",e)}</span>`:r(" ",e);n.undoManager.transact((()=>n.insertContent(o)))};var l=tinymce.util.Tools.resolve("tinymce.util.VK");const u=n=>e=>{const o=()=>{e.setEnabled(n.selection.isEditable())};return n.on("NodeChange",o),o(),()=>{n.off("NodeChange",o)}};n.add("nonbreaking",(n=>{(n=>{const e=n.options.register;e("nonbreaking_force_tab",{processor:n=>o(n)?{value:n?3:0,valid:!0}:a(n)?{value:n,valid:!0}:{valid:!1,message:"Must be a boolean or number."},default:!1}),e("nonbreaking_wrap",{processor:"boolean",default:!0})})(n),(n=>{n.addCommand("mceNonBreaking",(()=>{c(n,1)}))})(n),(n=>{const e=()=>n.execCommand("mceNonBreaking");n.ui.registry.addButton("nonbreaking",{icon:"non-breaking",tooltip:"Nonbreaking space",onAction:e,onSetup:u(n)}),n.ui.registry.addMenuItem("nonbreaking",{icon:"non-breaking",text:"Nonbreaking space",onAction:e,onSetup:u(n)})})(n),(n=>{const e=i(n);e>0&&n.on("keydown",(o=>{if(o.keyCode===l.TAB&&!o.isDefaultPrevented()){if(o.shiftKey)return;o.preventDefault(),o.stopImmediatePropagation(),c(n,e)}}))})(n)}))}();
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),a=tinymce.util.Tools.resolve("tinymce.Env");const t=e=>a=>a.options.get(e),n=t("pagebreak_separator"),o=t("pagebreak_split_block"),r="mce-pagebreak",s=e=>{const t=`<img src="${a.transparentSrc}" class="${r}" data-mce-resize="false" data-mce-placeholder />`;return e?`<p>${t}</p>`:t},c=e=>a=>{const t=()=>{a.setEnabled(e.selection.isEditable())};return e.on("NodeChange",t),t(),()=>{e.off("NodeChange",t)}};e.add("pagebreak",(e=>{(e=>{const a=e.options.register;a("pagebreak_separator",{processor:"string",default:"\x3c!-- pagebreak --\x3e"}),a("pagebreak_split_block",{processor:"boolean",default:!1})})(e),(e=>{e.addCommand("mcePageBreak",(()=>{e.insertContent(s(o(e)))}))})(e),(e=>{const a=()=>e.execCommand("mcePageBreak");e.ui.registry.addButton("pagebreak",{icon:"page-break",tooltip:"Page break",onAction:a,onSetup:c(e)}),e.ui.registry.addMenuItem("pagebreak",{text:"Page break",icon:"page-break",onAction:a,onSetup:c(e)})})(e),(e=>{const a=n(e),t=()=>o(e),c=new RegExp(a.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,(e=>"\\"+e)),"gi");e.on("BeforeSetContent",(e=>{e.content=e.content.replace(c,s(t()))})),e.on("PreInit",(()=>{e.serializer.addNodeFilter("img",(n=>{let o,s,c=n.length;for(;c--;)if(o=n[c],s=o.attr("class"),s&&-1!==s.indexOf(r)){const n=o.parent;if(n&&e.schema.getBlockElements()[n.name]&&t()){n.type=3,n.value=a,n.raw=!0,o.remove();continue}o.type=3,o.value=a,o.raw=!0}}))}))})(e),(e=>{e.on("ResolveName",(a=>{"IMG"===a.target.nodeName&&e.dom.hasClass(a.target,r)&&(a.name="pagebreak")}))})(e)}))}();
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager"),t=tinymce.util.Tools.resolve("tinymce.Env"),o=tinymce.util.Tools.resolve("tinymce.util.Tools");const n=e=>t=>t.options.get(e),i=n("content_style"),s=n("content_css_cors"),c=n("body_class"),r=n("body_id");e.add("preview",(e=>{(e=>{e.addCommand("mcePreview",(()=>{(e=>{const n=(e=>{var n;let l="";const a=e.dom.encode,d=null!==(n=i(e))&&void 0!==n?n:"";l+='<base href="'+a(e.documentBaseURI.getURI())+'">';const m=s(e)?' crossorigin="anonymous"':"";o.each(e.contentCSS,(t=>{l+='<link type="text/css" rel="stylesheet" href="'+a(e.documentBaseURI.toAbsolute(t))+'"'+m+">"})),d&&(l+='<style type="text/css">'+d+"</style>");const y=r(e),u=c(e),v='<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A" && !('+(t.os.isMacOS()||t.os.isiOS()?"e.metaKey":"e.ctrlKey && !e.altKey")+")) {e.preventDefault();}}}, false);<\/script> ",p=e.getBody().dir,w=p?' dir="'+a(p)+'"':"";return"<!DOCTYPE html><html><head>"+l+'</head><body id="'+a(y)+'" class="mce-content-body '+a(u)+'"'+w+">"+e.getContent()+v+"</body></html>"})(e);e.windowManager.open({title:"Preview",size:"large",body:{type:"panel",items:[{name:"preview",type:"iframe",sandboxed:!0,transparent:!1}]},buttons:[{type:"cancel",name:"close",text:"Close",primary:!0}],initialData:{preview:n}}).focus("close")})(e)}))})(e),(e=>{const t=()=>e.execCommand("mcePreview");e.ui.registry.addButton("preview",{icon:"preview",tooltip:"Preview",onAction:t}),e.ui.registry.addMenuItem("preview",{icon:"preview",text:"Preview",onAction:t})})(e)}))}();
|
||||
File diff suppressed because one or more lines are too long
2
plugins/tinymce/plugins/save/plugin.min.js
vendored
2
plugins/tinymce/plugins/save/plugin.min.js
vendored
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var e=tinymce.util.Tools.resolve("tinymce.PluginManager");const o=("function",e=>"function"==typeof e);var n=tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),t=tinymce.util.Tools.resolve("tinymce.util.Tools");const a=e=>o=>o.options.get(e),c=a("save_enablewhendirty"),i=a("save_onsavecallback"),s=a("save_oncancelcallback"),r=(e,o)=>{e.notificationManager.open({text:o,type:"error"})},l=e=>o=>{const n=()=>{o.setEnabled(!c(e)||e.isDirty())};return n(),e.on("NodeChange dirty",n),()=>e.off("NodeChange dirty",n)};e.add("save",(e=>{(e=>{const o=e.options.register;o("save_enablewhendirty",{processor:"boolean",default:!0}),o("save_onsavecallback",{processor:"function"}),o("save_oncancelcallback",{processor:"function"})})(e),(e=>{e.ui.registry.addButton("save",{icon:"save",tooltip:"Save",enabled:!1,onAction:()=>e.execCommand("mceSave"),onSetup:l(e),shortcut:"Meta+S"}),e.ui.registry.addButton("cancel",{icon:"cancel",tooltip:"Cancel",enabled:!1,onAction:()=>e.execCommand("mceCancel"),onSetup:l(e)}),e.addShortcut("Meta+S","","mceSave")})(e),(e=>{e.addCommand("mceSave",(()=>{(e=>{const t=n.DOM.getParent(e.id,"form");if(c(e)&&!e.isDirty())return;e.save();const a=i(e);if(o(a))return a.call(e,e),void e.nodeChanged();t?(e.setDirty(!1),t.onsubmit&&!t.onsubmit()||("function"==typeof t.submit?t.submit():r(e,"Error: Form submit field collision.")),e.nodeChanged()):r(e,"Error: No form element found.")})(e)})),e.addCommand("mceCancel",(()=>{(e=>{const n=t.trim(e.startContent),a=s(e);o(a)?a.call(e,e):e.resetContent(n)})(e)}))})(e)}))}();
|
||||
File diff suppressed because one or more lines are too long
4
plugins/tinymce/plugins/table/plugin.min.js
vendored
4
plugins/tinymce/plugins/table/plugin.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
* TinyMCE version 7.1.1 (2024-05-22)
|
||||
* TinyMCE version 7.3.0 (2024-08-07)
|
||||
*/
|
||||
!function(){"use strict";var t=tinymce.util.Tools.resolve("tinymce.PluginManager");const s=(t,s,o)=>{t.dom.toggleClass(t.getBody(),"mce-visualblocks"),o.set(!o.get()),((t,s)=>{t.dispatch("VisualBlocks",{state:s})})(t,o.get())},o=("visualblocks_default_state",t=>t.options.get("visualblocks_default_state"));const e=(t,s)=>o=>{o.setActive(s.get());const e=t=>o.setActive(t.state);return t.on("VisualBlocks",e),()=>t.off("VisualBlocks",e)};t.add("visualblocks",((t,l)=>{(t=>{(0,t.options.register)("visualblocks_default_state",{processor:"boolean",default:!1})})(t);const a=(t=>{let s=!1;return{get:()=>s,set:t=>{s=t}}})();((t,o,e)=>{t.addCommand("mceVisualBlocks",(()=>{s(t,0,e)}))})(t,0,a),((t,s)=>{const o=()=>t.execCommand("mceVisualBlocks");t.ui.registry.addToggleButton("visualblocks",{icon:"visualblocks",tooltip:"Show blocks",onAction:o,onSetup:e(t,s)}),t.ui.registry.addToggleMenuItem("visualblocks",{text:"Show blocks",icon:"visualblocks",onAction:o,onSetup:e(t,s)})})(t,a),((t,e,l)=>{t.on("PreviewFormats AfterPreviewFormats",(s=>{l.get()&&t.dom.toggleClass(t.getBody(),"mce-visualblocks","afterpreviewformats"===s.type)})),t.on("init",(()=>{o(t)&&s(t,0,l)}))})(t,0,a)}))}();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1 @@
|
||||
tinymce.Resource.add('content/dark/content.css', "body{background-color:#222f3e;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}")
|
||||
//# sourceMappingURL=content.js.map
|
||||
tinymce.Resource.add('content/dark/content.css', `body{background-color:#222f3e;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}`)
|
||||
@@ -1,2 +1 @@
|
||||
tinymce.Resource.add('content/default/content.css', "body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}")
|
||||
//# sourceMappingURL=content.js.map
|
||||
tinymce.Resource.add('content/default/content.css', `body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}`)
|
||||
@@ -1,2 +1 @@
|
||||
tinymce.Resource.add('content/document/content.css', "@media screen{html{background:#f4f4f4;min-height:100%}}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}@media screen{body{background-color:#fff;box-shadow:0 0 4px rgba(0,0,0,.15);box-sizing:border-box;margin:1rem auto 0;max-width:820px;min-height:calc(100vh - 1rem);padding:4rem 6rem 6rem 6rem}}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#ccc}figure figcaption{color:#999;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}")
|
||||
//# sourceMappingURL=content.js.map
|
||||
tinymce.Resource.add('content/document/content.css', `@media screen{html{background:#f4f4f4;min-height:100%}}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}@media screen{body{background-color:#fff;box-shadow:0 0 4px rgba(0,0,0,.15);box-sizing:border-box;margin:1rem auto 0;max-width:820px;min-height:calc(100vh - 1rem);padding:4rem 6rem 6rem 6rem}}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure figcaption{color:#999;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}`)
|
||||
@@ -1,2 +1 @@
|
||||
tinymce.Resource.add('content/tinymce-5-dark/content.css', "body{background-color:#2f3742;color:#dfe0e4;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}")
|
||||
//# sourceMappingURL=content.js.map
|
||||
tinymce.Resource.add('content/tinymce-5-dark/content.css', `body{background-color:#2f3742;color:#dfe0e4;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}`)
|
||||
@@ -1,2 +1 @@
|
||||
tinymce.Resource.add('content/tinymce-5/content.css', "body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}")
|
||||
//# sourceMappingURL=content.js.map
|
||||
tinymce.Resource.add('content/tinymce-5/content.css', `body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}`)
|
||||
@@ -1,2 +1 @@
|
||||
tinymce.Resource.add('content/writer/content.css', "body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem auto;max-width:900px}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border=\"0\"]):not([style*=border-width]) td,table[border]:not([border=\"0\"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border=\"0\"]):not([style*=border-style]) td,table[border]:not([border=\"0\"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border=\"0\"]):not([style*=border-color]) td,table[border]:not([border=\"0\"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}")
|
||||
//# sourceMappingURL=content.js.map
|
||||
tinymce.Resource.add('content/writer/content.css', `body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem auto;max-width:900px}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}`)
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1 @@
|
||||
tinymce.Resource.add('ui/dark/skin.shadowdom.css', "body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}")
|
||||
//# sourceMappingURL=skin.shadowdom.js.map
|
||||
tinymce.Resource.add('ui/dark/skin.shadowdom.css', `body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;margin:0;overflow:hidden;overscroll-behavior:none;padding:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox-shadowhost.tox-fullscreen,.tox.tox-tinymce.tox-fullscreen{left:0;position:fixed;top:0;z-index:1200}.tox.tox-tinymce.tox-fullscreen{background-color:transparent}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}`)
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user