Debugs config items management

main
Yasen Pramatarov 2025-01-22 22:52:50 +02:00
parent 53b3965a32
commit 5b24d098e4
5 changed files with 162 additions and 68 deletions

View File

@ -186,18 +186,23 @@ class Agent {
try { try {
$sql = 'UPDATE jilo_agents $sql = 'UPDATE jilo_agents
SET SET
agent_type_id = :agent_type_id,
url = :url, url = :url,
secret_key = :secret_key, secret_key = :secret_key,
check_period = :check_period check_period = :check_period
WHERE WHERE
id = :agent_id'; id = :agent_id';
// Convert empty secret key to NULL
$secretKey = !empty($updatedAgent['secret_key']) ? $updatedAgent['secret_key'] : null;
$query = $this->db->prepare($sql); $query = $this->db->prepare($sql);
$query->execute([ $query->execute([
':agent_id' => $agent_id, ':agent_id' => $agent_id,
':url' => $updatedAgent['url'], ':agent_type_id' => $updatedAgent['agent_type_id'],
':secret_key' => $updatedAgent['secret_key'], ':url' => $updatedAgent['url'],
':check_period' => $updatedAgent['check_period'], ':secret_key' => $secretKey,
':check_period' => $updatedAgent['check_period'],
]); ]);
return true; return true;

View File

@ -136,17 +136,28 @@ class Host {
*/ */
public function deleteHost($host_id) { public function deleteHost($host_id) {
try { try {
$sql = 'DELETE FROM hosts // Start transaction
WHERE $this->db->beginTransaction();
id = :host_id';
// First delete all agents associated with this host
$sql = 'DELETE FROM jilo_agents WHERE host_id = :host_id';
$query = $this->db->prepare($sql); $query = $this->db->prepare($sql);
$query->bindParam(':host_id', $host_id); $query->bindParam(':host_id', $host_id);
$query->execute(); $query->execute();
// Then delete the host
$sql = 'DELETE FROM hosts WHERE id = :host_id';
$query = $this->db->prepare($sql);
$query->bindParam(':host_id', $host_id);
$query->execute();
// Commit transaction
$this->db->commit();
return true; return true;
} catch (Exception $e) { } catch (Exception $e) {
// Rollback transaction on error
$this->db->rollBack();
return $e->getMessage(); return $e->getMessage();
} }
} }

View File

@ -28,6 +28,13 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
* Handles form submissions from editing * Handles form submissions from editing
*/ */
// Get hash from URL if present
$hash = parse_url($_SERVER['REQUEST_URI'], PHP_URL_FRAGMENT) ?? '';
$redirectUrl = htmlspecialchars($app_root) . '?page=config';
if ($hash) {
$redirectUrl .= '#' . $hash;
}
// editing the config file // editing the config file
if (isset($_POST['item']) && $_POST['item'] === 'config_file') { if (isset($_POST['item']) && $_POST['item'] === 'config_file') {
// check if file is writable // check if file is writable
@ -41,6 +48,8 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$_SESSION['error'] = "Editing the config file failed. Error: $result"; $_SESSION['error'] = "Editing the config file failed. Error: $result";
} }
} }
header('Location: ' . $redirectUrl);
exit;
// host operations // host operations
} elseif (isset($_POST['item']) && $_POST['item'] === 'host') { } elseif (isset($_POST['item']) && $_POST['item'] === 'host') {
@ -79,6 +88,8 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$_SESSION['error'] = "Editing the host failed. Error: $result"; $_SESSION['error'] = "Editing the host failed. Error: $result";
} }
} }
header('Location: ' . $redirectUrl);
exit;
// agent operations // agent operations
} elseif (isset($_POST['item']) && $_POST['item'] === 'agent') { } elseif (isset($_POST['item']) && $_POST['item'] === 'agent') {
@ -94,8 +105,8 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$newAgent = [ $newAgent = [
'type_id' => $_POST['type'], 'type_id' => $_POST['type'],
'url' => $_POST['url'], 'url' => $_POST['url'],
'secret_key' => $_POST['secret_key'], 'secret_key' => empty($_POST['secret_key']) ? null : $_POST['secret_key'],
'check_period' => $_POST['check_period'], 'check_period' => empty($_POST['check_period']) ? 0 : $_POST['check_period'],
]; ];
$result = $agentObject->addAgent($_POST['host'], $newAgent); $result = $agentObject->addAgent($_POST['host'], $newAgent);
if ($result === true) { if ($result === true) {
@ -106,9 +117,10 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
} else { // This is an edit of existing agent } else { // This is an edit of existing agent
$agent_id = $_POST['agent']; $agent_id = $_POST['agent'];
$updatedAgent = [ $updatedAgent = [
'url' => $_POST['url'], 'agent_type_id' => $_POST['agent_type_id'],
'secret_key' => $_POST['secret_key'], 'url' => $_POST['url'],
'check_period' => $_POST['check_period'], 'secret_key' => empty($_POST['secret_key']) ? null : $_POST['secret_key'],
'check_period' => empty($_POST['check_period']) ? 0 : $_POST['check_period'],
]; ];
$result = $agentObject->editAgent($agent_id, $updatedAgent); $result = $agentObject->editAgent($agent_id, $updatedAgent);
if ($result === true) { if ($result === true) {
@ -117,6 +129,8 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$_SESSION['error'] = "Editing the agent failed. Error: $result"; $_SESSION['error'] = "Editing the agent failed. Error: $result";
} }
} }
header('Location: ' . $redirectUrl);
exit;
// platform operations // platform operations
} elseif (isset($_POST['item']) && $_POST['item'] === 'platform') { } elseif (isset($_POST['item']) && $_POST['item'] === 'platform') {
@ -155,12 +169,10 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$_SESSION['error'] = "Editing the platform failed. Error: $result"; $_SESSION['error'] = "Editing the platform failed. Error: $result";
} }
} }
header('Location: ' . $redirectUrl);
exit;
} }
// After any POST operation, redirect back to the main config page
header("Location: $app_root?page=config");
exit();
} else { } else {
/** /**
* Handles GET requests to display templates. * Handles GET requests to display templates.
@ -182,6 +194,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
default: default:
if ($userObject->hasRight($user_id, 'view config file')) { if ($userObject->hasRight($user_id, 'view config file')) {
$jilo_agent_types = $agentObject->getAgentTypes();
include '../app/templates/config-jilo.php'; include '../app/templates/config-jilo.php';
} else { } else {
include '../app/templates/error-unauthorized.php'; include '../app/templates/error-unauthorized.php';

View File

@ -50,7 +50,7 @@
<button type="button" class="btn btn-outline-primary edit-platform platform-view-mode"> <button type="button" class="btn btn-outline-primary edit-platform platform-view-mode">
<i class="fas fa-edit me-1"></i>Edit platform <i class="fas fa-edit me-1"></i>Edit platform
</button> </button>
<button type="button" class="btn btn-outline-primary save-platform platform-edit-mode" style="display: none;"> <button type="button" class="btn btn-outline-success save-platform platform-edit-mode" style="display: none;">
<i class="fas fa-save me-1"></i>Save <i class="fas fa-save me-1"></i>Save
</button> </button>
<button type="button" class="btn btn-outline-secondary cancel-edit platform-edit-mode" style="display: none;"> <button type="button" class="btn btn-outline-secondary cancel-edit platform-edit-mode" style="display: none;">
@ -146,15 +146,15 @@
<div class="row g-2"> <div class="row g-2">
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label small text-muted">Host description</label> <label class="form-label small text-muted">Host description</label>
<input type="text" class="form-control form-control-sm text-break" name="name" <input type="text" class="form-control form-control-sm text-break" name="name"
value="<?= htmlspecialchars($host['name']) ?>" value="<?= htmlspecialchars($host['name']) ?>"
placeholder="Optional description"> placeholder="Optional description">
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label class="form-label small text-muted">DNS name or IP</label> <label class="form-label small text-muted">DNS name or IP</label>
<input type="text" class="form-control form-control-sm text-break" name="address" <input type="text" class="form-control form-control-sm text-break" name="address"
value="<?= htmlspecialchars($host['address']) ?>" value="<?= htmlspecialchars($host['address']) ?>"
placeholder="e.g., server.example.com or 192.168.1.100" required> placeholder="e.g., server.example.com or 192.168.1.100" required>
</div> </div>
</div> </div>
</div> </div>
@ -165,7 +165,7 @@
<button type="button" class="btn btn-outline-primary btn-sm edit-host host-view-mode"> <button type="button" class="btn btn-outline-primary btn-sm edit-host host-view-mode">
<i class="fas fa-edit me-1"></i>Edit host <i class="fas fa-edit me-1"></i>Edit host
</button> </button>
<button type="button" class="btn btn-outline-primary btn-sm save-host host-edit-mode" style="display: none;"> <button type="button" class="btn btn-outline-success btn-sm save-host host-edit-mode" style="display: none;">
<i class="fas fa-save me-1"></i>Save <i class="fas fa-save me-1"></i>Save
</button> </button>
<button type="button" class="btn btn-outline-secondary btn-sm cancel-host-edit host-edit-mode" style="display: none;"> <button type="button" class="btn btn-outline-secondary btn-sm cancel-host-edit host-edit-mode" style="display: none;">
@ -201,6 +201,7 @@
<tr> <tr>
<th>Agent type</th> <th>Agent type</th>
<th>Endpoint URL</th> <th>Endpoint URL</th>
<th>Secret key</th>
<th>Check period</th> <th>Check period</th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
@ -214,6 +215,15 @@
<span class="agent-view-mode"> <span class="agent-view-mode">
<?= htmlspecialchars($agent['agent_description']) ?> <?= htmlspecialchars($agent['agent_description']) ?>
</span> </span>
<div class="agent-edit-mode" style="display: none;">
<select name="agent_type_id" class="form-select">
<?php foreach ($jilo_agent_types as $type): ?>
<option value="<?= htmlspecialchars($type['id']) ?>" <?= $type['id'] == $agent['agent_type_id'] ? 'selected' : '' ?>>
<?= htmlspecialchars($type['description']) ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div> </div>
</td> </td>
<td> <td>
@ -221,19 +231,32 @@
<?= htmlspecialchars($agent['url']) ?> <?= htmlspecialchars($agent['url']) ?>
</span> </span>
<div class="agent-edit-mode" style="display: none;"> <div class="agent-edit-mode" style="display: none;">
<input type="text" class="form-control" name="url" value="<?= htmlspecialchars($agent['url']) ?>" required> <input type="text" name="url" class="form-control"
value="<?= htmlspecialchars($agent['url']) ?>"
placeholder="https://address[:port]">
</div> </div>
</td> </td>
<td> <td>
<span class="agent-view-mode"> <span class="agent-view-mode">
<?php if (isset($agent['check_period']) && $agent['check_period'] !== 0): ?> <?= isset($agent['secret_key']) ? '••••••' : '' ?>
<?= htmlspecialchars($agent['check_period']) ?> <?= ($agent['check_period'] == 1 ? 'minute' : 'minutes') ?>
<?php else: ?>
Not monitored
<?php endif; ?>
</span> </span>
<div class="agent-edit-mode" style="display: none;"> <div class="agent-edit-mode" style="display: none;">
<input type="number" class="form-control" name="check_period" value="<?= htmlspecialchars($agent['check_period']) ?>" min="0"> <input type="text" name="secret_key" class="form-control"
value="<?= isset($agent['secret_key']) ? htmlspecialchars($agent['secret_key']) : '' ?>">
</div>
</td>
<td>
<span class="agent-view-mode">
<?= $agent['check_period'] > 0 ?
htmlspecialchars($agent['check_period']) . ' ' .
($agent['check_period'] == 1 ? 'minute' : 'minutes') :
'Not monitored' ?>
</span>
<div class="agent-edit-mode" style="display: none;">
<input type="number" name="check_period" class="form-control form-control-sm" style="width: 80px;"
value="<?= htmlspecialchars($agent['check_period']) ?>"
min="0" max="9999" maxlength="4"
placeholder="">
</div> </div>
</td> </td>
<td> <td>
@ -384,12 +407,12 @@
<input type="text" class="form-control" id="agentUrl" name="url" required> <input type="text" class="form-control" id="agentUrl" name="url" required>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="agentSecretKey" class="form-label">Secret key <span class="text-danger">*</span></label> <label for="agentSecretKey" class="form-label">Secret key</label>
<input type="text" class="form-control" id="agentSecretKey" name="secret_key" required> <input type="text" class="form-control" id="agentSecretKey" name="secret_key">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="agentCheckPeriod" class="form-label">Check period (minutes) <span class="text-danger">*</span></label> <label for="agentCheckPeriod" class="form-label">Check period in minutes (0 to disable)</label>
<input type="number" class="form-control" id="agentCheckPeriod" name="check_period" min="1" required> <input type="number" class="form-control" id="agentCheckPeriod" name="check_period" min="0">
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@ -492,24 +515,26 @@
<h5 class="modal-title" id="deleteAgentModalLabel">Delete agent</h5> <h5 class="modal-title" id="deleteAgentModalLabel">Delete agent</h5>
<button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-dismiss="modal" aria-label="Close"></button>
</div> </div>
<form method="POST" action="<?= htmlspecialchars($app_root) ?>?page=config" id="deleteAgentForm"> <form id="deleteAgentForm" method="post">
<input type="hidden" name="item" value="agent"> <input type="hidden" name="item" value="agent">
<input type="hidden" name="platform" id="deleteAgentPlatformId">
<input type="hidden" name="host" id="deleteAgentHostId">
<input type="hidden" name="agent" id="deleteAgentId">
<input type="hidden" name="delete" value="true"> <input type="hidden" name="delete" value="true">
<input type="hidden" name="agent" id="deleteAgentId">
<div class="modal-body"> <div class="modal-body">
<div class="alert alert-danger"> <div class="alert alert-danger">
<h6>Are you sure you want to delete this agent?</h6> <h6>Are you sure you want to delete this agent?</h6>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-label">Agent type</label> <label class="form-label small text-muted">Agent type</label>
<div id="deleteAgentType" class="form-control-plaintext"></div> <div class="form-control-plaintext"><span id="deleteAgentType"></span></div>
</div>
<div class="mb-3">
<label class="form-label small text-muted">Endpoint URL</label>
<div class="form-control-plaintext"><span id="deleteAgentUrl"></span></div>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-danger">Delete agent</button> <button type="submit" form="deleteAgentForm" class="btn btn-danger">Delete</button>
</div> </div>
</form> </form>
</div> </div>
@ -518,6 +543,38 @@
<script> <script>
$(function() { $(function() {
// Handle platform tab changes
$('#platformTabs a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
e.preventDefault();
const platformId = $(e.target).attr('href');
// Update hash without triggering scroll
history.replaceState(null, null, platformId);
});
// On page load, activate tab from URL hash if present
if (window.location.hash) {
const hash = window.location.hash;
const tab = $(`#platformTabs a[href="${hash}"]`);
if (tab.length) {
tab.tab('show');
// Prevent scroll on page load
setTimeout(() => {
window.scrollTo(0, 0);
}, 1);
}
}
// Add platform ID to form actions to maintain tab after submit
$('form').submit(function() {
const currentHash = window.location.hash;
if (currentHash) {
const action = $(this).attr('action');
if (action && action.indexOf('#') === -1) {
$(this).attr('action', action + currentHash);
}
}
});
// Edit platform // Edit platform
$('.edit-platform').click(function() { $('.edit-platform').click(function() {
const platformId = $(this).closest('.platform-actions').data('platform-id'); const platformId = $(this).closest('.platform-actions').data('platform-id');
@ -816,7 +873,6 @@ $(function() {
$('.save-agent').click(function() { $('.save-agent').click(function() {
const agentActions = $(this).closest('.agent-actions'); const agentActions = $(this).closest('.agent-actions');
const agentId = agentActions.data('agent-id'); const agentId = agentActions.data('agent-id');
const platformId = agentActions.data('platform-id');
const hostId = agentActions.data('host-id'); const hostId = agentActions.data('host-id');
const row = agentActions.closest('tr'); const row = agentActions.closest('tr');
@ -824,7 +880,6 @@ $(function() {
const formData = new FormData(); const formData = new FormData();
formData.append('item', 'agent'); formData.append('item', 'agent');
formData.append('agent', agentId); formData.append('agent', agentId);
formData.append('platform', platformId);
formData.append('host', hostId); formData.append('host', hostId);
row.find('.agent-edit-mode input, .agent-edit-mode select').each(function() { row.find('.agent-edit-mode input, .agent-edit-mode select').each(function() {
@ -857,20 +912,27 @@ $(function() {
// Update view mode with new values // Update view mode with new values
const type = row.find('select[name="agent_type_id"] option:selected').text(); const type = row.find('select[name="agent_type_id"] option:selected').text();
const url = row.find('input[name="url"]').val(); const url = row.find('input[name="url"]').val();
const endpoint = row.find('select[name="agent_type_id"] option:selected').data('endpoint');
const checkPeriod = row.find('input[name="check_period"]').val(); const checkPeriod = row.find('input[name="check_period"]').val();
const secretKey = row.find('input[name="secret_key"]').val();
row.find('td:first-child .agent-view-mode').text(type); row.find('td:first-child .agent-view-mode').text(type);
row.find('td:nth-child(2) .agent-view-mode').text(url + endpoint); row.find('td:nth-child(2) .agent-view-mode').text(url);
row.find('td:nth-child(3) .agent-view-mode').text( row.find('td:nth-child(3) .agent-view-mode').text(secretKey ? '••••••' : '');
row.find('td:nth-child(4) .agent-view-mode').text(
checkPeriod > 0 ? checkPeriod > 0 ?
`${checkPeriod} ${checkPeriod == 1 ? 'minute' : 'minutes'}` : `${checkPeriod} ${checkPeriod == 1 ? 'minute' : 'minutes'}` :
'-' 'Not monitored'
); );
// Switch back to view mode // Switch back to view mode
row.find('.agent-view-mode').show(); row.find('.agent-view-mode').show();
row.find('.agent-edit-mode').hide(); row.find('.agent-edit-mode').hide();
// Show success message
const alert = $('<div class="alert alert-success alert-dismissible fade show" role="alert">')
.text('Agent updated successfully')
.append('<button type="button" class="btn-close" data-dismiss="alert" aria-label="Close"></button>');
$('.content-wrapper').prepend(alert);
} else { } else {
alert('Error saving agent: ' + (data.message || 'Unknown error')); alert('Error saving agent: ' + (data.message || 'Unknown error'));
} }
@ -881,6 +943,19 @@ $(function() {
}); });
}); });
// Delete agent
$('.delete-agent').click(function() {
const row = $(this).closest('tr');
const agentId = row.data('agent-id');
const agentType = row.find('td:first-child .agent-view-mode').text().trim();
const agentUrl = row.find('td:nth-child(2) .agent-view-mode').text().trim();
$('#deleteAgentId').val(agentId);
$('#deleteAgentType').text(agentType);
$('#deleteAgentUrl').text(agentUrl);
$('#deleteAgentModal').modal('show');
});
// Run the delete platform modal // Run the delete platform modal
function showDeletePlatformModal(platformId, name, url, database) { function showDeletePlatformModal(platformId, name, url, database) {
document.getElementById('deletePlatformId').value = platformId; document.getElementById('deletePlatformId').value = platformId;
@ -937,6 +1012,7 @@ $(function() {
document.getElementById('deleteHostId').value = hostId; document.getElementById('deleteHostId').value = hostId;
document.getElementById('deleteHostName').textContent = name || '(no description)'; document.getElementById('deleteHostName').textContent = name || '(no description)';
document.getElementById('deleteHostAddress').textContent = address; document.getElementById('deleteHostAddress').textContent = address;
document.getElementById('deleteHostModalLabel').textContent = `Delete host "${name}"`;
// Get agents for this host // Get agents for this host
const platformPane = document.getElementById(`platform-${platformId}`); const platformPane = document.getElementById(`platform-${platformId}`);
@ -976,12 +1052,11 @@ $(function() {
} }
// Run the delete agent modal // Run the delete agent modal
function showDeleteAgentModal(platformId, hostId, agentId, type) { function showDeleteAgentModal(agentId, type, url) {
document.getElementById('deleteAgentPlatformId').value = platformId; $('#deleteAgentId').val(agentId);
document.getElementById('deleteAgentHostId').value = hostId; $('#deleteAgentType').text(type);
document.getElementById('deleteAgentId').value = agentId; $('#deleteAgentUrl').text(url);
document.getElementById('deleteAgentType').textContent = type; $('#deleteAgentModal').modal('show');
$('#deleteAgentModal').modal();
} }
// Handle confirmation inputs // Handle confirmation inputs

View File

@ -67,19 +67,9 @@ $timeNow = new DateTime('now', new DateTimeZone($userTimezone));
<li class="list-group-item bg-light" style="border: none;"><p class="text-end mb-0"><small>jitsi platforms config</small></p></li> <li class="list-group-item bg-light" style="border: none;"><p class="text-end mb-0"><small>jitsi platforms config</small></p></li>
<a href="<?= htmlspecialchars($app_root) ?>?page=config&item=platform"> <a href="<?= htmlspecialchars($app_root) ?>?page=config">
<li class="list-group-item<?php if ($page === 'config' && $item === 'platform') echo ' list-group-item-secondary'; else echo ' list-group-item-action'; ?>"> <li class="list-group-item<?php if ($page === 'config') echo ' list-group-item-secondary'; else echo ' list-group-item-action'; ?>">
<i class="fas fa-sitemap" data-toggle="tooltip" data-placement="right" data-offset="30.0" title="platforms config"></i>platforms <i class="fas fa-cog" data-toggle="tooltip" data-placement="right" data-offset="30.0" title="jilo config"></i>config
</li>
</a>
<a href="<?= htmlspecialchars($app_root) ?>?page=config&item=host">
<li class="list-group-item<?php if ($page === 'config' && $item === 'host') echo ' list-group-item-secondary'; else echo ' list-group-item-action'; ?>">
<i class="fas fa-laptop" data-toggle="tooltip" data-placement="right" data-offset="30.0" title="hosts config"></i>hosts
</li>
</a>
<a href="<?= htmlspecialchars($app_root) ?>?page=config&item=agent">
<li class="list-group-item<?php if ($page === 'config' && $item === 'agent') echo ' list-group-item-secondary'; else echo ' list-group-item-action'; ?>">
<i class="fas fa-stethoscope" data-toggle="tooltip" data-placement="right" data-offset="30.0" title="agents config"></i>agents
</li> </li>
</a> </a>