PHP Classes

File: templates/admin/insecure_nodes.twig

Recommend this page to a friend!
  Packages of Matthew Asham   Binkterm PHP   templates/admin/insecure_nodes.twig   Download  
File: templates/admin/insecure_nodes.twig
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: Binkterm PHP
Bulletin board system based on the Web
Author: By
Last change:
Date: 5 days ago
Size: 17,699 bytes
 

Contents

Class file image Download
{% extends "base.twig" %} {% block title %}{{ t('ui.admin.insecure_nodes.page_title', {}, locale, ['common']) }}{% endblock %} {% block content %} <div class="container-fluid"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <h1 class="h2"><i class="fas fa-shield-alt me-2"></i>{{ t('ui.admin.insecure_nodes.heading', {}, locale, ['common']) }}</h1> <div class="btn-toolbar"> <button class="btn btn-primary me-2" data-bs-toggle="modal" data-bs-target="#addNodeModal"> <i class="fas fa-plus me-1"></i>{{ t('ui.admin.insecure_nodes.add_node', {}, locale, ['common']) }} </button> <a href="/admin" class="btn btn-outline-secondary"> <i class="fas fa-arrow-left me-1"></i>{{ t('ui.admin.insecure_nodes.back_to_dashboard', {}, locale, ['common']) }} </a> </div> </div> <!-- Info Alert --> <div class="alert alert-info mb-4"> <i class="fas fa-info-circle me-2"></i> <strong>{{ t('ui.admin.insecure_nodes.about_insecure_sessions', {}, locale, ['common']) }}</strong> {{ t('ui.admin.insecure_nodes.info_text_1', {}, locale, ['common']) }} {{ t('ui.admin.insecure_nodes.info_text_2', {}, locale, ['common']) }} </div> <!-- Nodes Table --> <div class="card shadow mb-4"> <div class="card-header py-3 d-flex justify-content-between align-items-center"> <h6 class="m-0 font-weight-bold text-primary">{{ t('ui.admin.insecure_nodes.allowed_nodes', {}, locale, ['common']) }}</h6> <button class="btn btn-sm btn-outline-primary" id="refreshNodes"> <i class="fas fa-sync-alt"></i> </button> </div> <div class="card-body"> <div class="table-responsive"> <table class="table table-striped table-hover" id="nodesTable"> <thead> <tr> <th>{{ t('ui.admin.insecure_nodes.address', {}, locale, ['common']) }}</th> <th>{{ t('ui.common.description', {}, locale, ['common']) }}</th> <th>{{ t('ui.admin.insecure_nodes.receive', {}, locale, ['common']) }}</th> <th>{{ t('ui.admin.insecure_nodes.send', {}, locale, ['common']) }}</th> <th>{{ t('ui.admin.insecure_nodes.max_msgs', {}, locale, ['common']) }}</th> <th>{{ t('ui.admin.insecure_nodes.last_session', {}, locale, ['common']) }}</th> <th>{{ t('ui.admin.insecure_nodes.active', {}, locale, ['common']) }}</th> <th>{{ t('ui.admin.insecure_nodes.actions', {}, locale, ['common']) }}</th> </tr> </thead> <tbody id="nodesTableBody"> <tr> <td colspan="8" class="text-center">{{ t('ui.common.loading', {}, locale, ['common']) }}</td> </tr> </tbody> </table> </div> </div> </div> </div> <!-- Add Node Modal --> <div class="modal fade" id="addNodeModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">{{ t('ui.admin.insecure_nodes.add_node_to_allowlist', {}, locale, ['common']) }}</h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <form id="addNodeForm"> <div class="mb-3"> <label class="form-label">{{ t('ui.admin.insecure_nodes.ftn_address', {}, locale, ['common']) }} <span class="text-danger">*</span></label> <input type="text" class="form-control" name="address" placeholder="{{ t('ui.admin.insecure_nodes.address_placeholder', {}, locale, ['common']) }}" required> <div class="form-text">{{ t('ui.admin.insecure_nodes.ftn_address_help', {}, locale, ['common']) }}</div> </div> <div class="mb-3"> <label class="form-label">{{ t('ui.common.description', {}, locale, ['common']) }}</label> <input type="text" class="form-control" name="description" placeholder="{{ t('ui.admin.insecure_nodes.description_placeholder', {}, locale, ['common']) }}"> </div> <div class="mb-3"> <label class="form-label">{{ t('ui.admin.insecure_nodes.max_messages_per_session', {}, locale, ['common']) }}</label> <input type="number" class="form-control" name="max_messages_per_session" value="100" min="1" max="10000"> </div> <div class="mb-3"> <div class="form-check"> <input type="checkbox" class="form-check-input" name="allow_receive" id="allowReceive" checked> <label class="form-check-label" for="allowReceive">{{ t('ui.admin.insecure_nodes.allow_receive', {}, locale, ['common']) }}</label> <div class="form-text">{{ t('ui.admin.insecure_nodes.allow_receive_help', {}, locale, ['common']) }}</div> </div> </div> <div class="mb-3"> <div class="form-check"> <input type="checkbox" class="form-check-input" name="allow_send" id="allowSend"> <label class="form-check-label" for="allowSend">{{ t('ui.admin.insecure_nodes.allow_send_pickup', {}, locale, ['common']) }}</label> <div class="form-text">{{ t('ui.admin.insecure_nodes.allow_send_help', {}, locale, ['common']) }}</div> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t('ui.common.cancel', {}, locale, ['common']) }}</button> <button type="button" class="btn btn-primary" id="saveNodeBtn">{{ t('ui.admin.insecure_nodes.add_node', {}, locale, ['common']) }}</button> </div> </div> </div> </div> <!-- Edit Node Modal --> <div class="modal fade" id="editNodeModal" tabindex="-1"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">{{ t('ui.admin.insecure_nodes.edit_node', {}, locale, ['common']) }}</h5> <button type="button" class="btn-close" data-bs-dismiss="modal"></button> </div> <div class="modal-body"> <form id="editNodeForm"> <input type="hidden" name="id" id="editNodeId"> <div class="mb-3"> <label class="form-label">{{ t('ui.admin.insecure_nodes.ftn_address', {}, locale, ['common']) }}</label> <input type="text" class="form-control" name="address" id="editAddress" readonly> </div> <div class="mb-3"> <label class="form-label">{{ t('ui.common.description', {}, locale, ['common']) }}</label> <input type="text" class="form-control" name="description" id="editDescription"> </div> <div class="mb-3"> <label class="form-label">{{ t('ui.admin.insecure_nodes.max_messages_per_session', {}, locale, ['common']) }}</label> <input type="number" class="form-control" name="max_messages_per_session" id="editMaxMessages" min="1" max="10000"> </div> <div class="mb-3"> <div class="form-check"> <input type="checkbox" class="form-check-input" name="allow_receive" id="editAllowReceive"> <label class="form-check-label" for="editAllowReceive">{{ t('ui.admin.insecure_nodes.allow_receive', {}, locale, ['common']) }}</label> </div> </div> <div class="mb-3"> <div class="form-check"> <input type="checkbox" class="form-check-input" name="allow_send" id="editAllowSend"> <label class="form-check-label" for="editAllowSend">{{ t('ui.admin.insecure_nodes.allow_send_pickup', {}, locale, ['common']) }}</label> </div> </div> <div class="mb-3"> <div class="form-check"> <input type="checkbox" class="form-check-input" name="is_active" id="editIsActive"> <label class="form-check-label" for="editIsActive">{{ t('ui.admin.insecure_nodes.active', {}, locale, ['common']) }}</label> </div> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t('ui.common.cancel', {}, locale, ['common']) }}</button> <button type="button" class="btn btn-primary" id="updateNodeBtn">{{ t('ui.admin.insecure_nodes.save_changes', {}, locale, ['common']) }}</button> </div> </div> </div> </div> <script> function apiMessage(payload, fallback) { if (window.getApiMessage) { return window.getApiMessage(payload, fallback); } return payload && payload.message ? payload.message : fallback; } function apiError(payload, fallback) { if (window.getApiErrorMessage) { return window.getApiErrorMessage(payload, fallback); } return payload && payload.error ? payload.error : fallback; } function uiT(key, fallback, params = {}) { if (window.t) { return window.t(key, params, fallback); } return fallback; } document.addEventListener('DOMContentLoaded', function() { loadI18nNamespaces(['common', 'errors']).then(function() { loadNodes(); }); document.getElementById('refreshNodes').addEventListener('click', loadNodes); document.getElementById('saveNodeBtn').addEventListener('click', addNode); document.getElementById('updateNodeBtn').addEventListener('click', updateNode); }); function loadNodes() { fetch('/admin/api/insecure-nodes') .then(response => response.json()) .then(data => { const tbody = document.getElementById('nodesTableBody'); if (!data.nodes || data.nodes.length === 0) { tbody.innerHTML = '<tr><td colspan="8" class="text-center text-muted">' + uiT('ui.admin.insecure_nodes.no_nodes', 'No nodes in allowlist') + '</td></tr>'; return; } tbody.innerHTML = data.nodes.map(node => ` <tr> <td><code>${escapeHtml(node.address)}</code></td> <td>${escapeHtml(node.description || '-')}</td> <td>${node.allow_receive ? '<i class="fas fa-check text-success"></i>' : '<i class="fas fa-times text-danger"></i>'}</td> <td>${node.allow_send ? '<i class="fas fa-check text-success"></i>' : '<i class="fas fa-times text-danger"></i>'}</td> <td>${node.max_messages_per_session}</td> <td>${node.last_session_at ? formatDate(node.last_session_at) : '<em>' + uiT('ui.common.never', 'Never') + '</em>'}</td> <td> ${node.is_active ? '<span class="badge bg-success">' + uiT('ui.admin.insecure_nodes.active', 'Active') + '</span>' : '<span class="badge bg-secondary">' + uiT('ui.admin.insecure_nodes.inactive', 'Inactive') + '</span>'} </td> <td> <button class="btn btn-sm btn-outline-primary" onclick="editNode(${node.id}, '${escapeHtml(node.address)}', '${escapeHtml(node.description || '')}', ${node.max_messages_per_session}, ${node.allow_receive}, ${node.allow_send}, ${node.is_active})"> <i class="fas fa-edit"></i> </button> <button class="btn btn-sm btn-outline-danger" onclick="deleteNode(${node.id}, '${escapeHtml(node.address)}')"> <i class="fas fa-trash"></i> </button> </td> </tr> `).join(''); }) .catch(error => { console.error(uiT('ui.admin.insecure_nodes.load_nodes_failed', 'Error loading nodes') + ':', error); document.getElementById('nodesTableBody').innerHTML = '<tr><td colspan="8" class="text-center text-danger">' + uiT('ui.admin.insecure_nodes.load_nodes_failed', 'Error loading nodes') + '</td></tr>'; }); } function addNode() { const form = document.getElementById('addNodeForm'); const formData = new FormData(form); const data = { address: formData.get('address'), description: formData.get('description'), max_messages_per_session: parseInt(formData.get('max_messages_per_session')) || 100, allow_receive: form.querySelector('[name="allow_receive"]').checked, allow_send: form.querySelector('[name="allow_send"]').checked, is_active: true }; fetch('/admin/api/insecure-nodes', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }) .then(response => response.json()) .then(result => { if (result.success) { alert(apiMessage(result, uiT('ui.admin.insecure_nodes.added_success', 'Node added successfully'))); bootstrap.Modal.getInstance(document.getElementById('addNodeModal')).hide(); form.reset(); loadNodes(); } else { alert(uiT('ui.admin.insecure_nodes.error_prefix', 'Error: ') + apiError(result, uiT('ui.admin.insecure_nodes.add_failed', 'Failed to add node'))); } }) .catch(error => { alert(uiT('ui.admin.insecure_nodes.error_prefix', 'Error: ') + error.message); }); } function editNode(id, address, description, maxMessages, allowReceive, allowSend, isActive) { document.getElementById('editNodeId').value = id; document.getElementById('editAddress').value = address; document.getElementById('editDescription').value = description; document.getElementById('editMaxMessages').value = maxMessages; document.getElementById('editAllowReceive').checked = allowReceive; document.getElementById('editAllowSend').checked = allowSend; document.getElementById('editIsActive').checked = isActive; new bootstrap.Modal(document.getElementById('editNodeModal')).show(); } function updateNode() { const id = document.getElementById('editNodeId').value; const form = document.getElementById('editNodeForm'); const data = { description: document.getElementById('editDescription').value, max_messages_per_session: parseInt(document.getElementById('editMaxMessages').value) || 100, allow_receive: document.getElementById('editAllowReceive').checked, allow_send: document.getElementById('editAllowSend').checked, is_active: document.getElementById('editIsActive').checked }; fetch(`/admin/api/insecure-nodes/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }) .then(response => response.json()) .then(result => { if (result.success) { alert(apiMessage(result, uiT('ui.admin.insecure_nodes.updated_success', 'Node updated successfully'))); bootstrap.Modal.getInstance(document.getElementById('editNodeModal')).hide(); loadNodes(); } else { alert(uiT('ui.admin.insecure_nodes.error_prefix', 'Error: ') + apiError(result, uiT('ui.admin.insecure_nodes.update_failed', 'Failed to update node'))); } }) .catch(error => { alert(uiT('ui.admin.insecure_nodes.error_prefix', 'Error: ') + error.message); }); } function deleteNode(id, address) { if (!confirm(uiT('ui.admin.insecure_nodes.delete_confirm', `Delete ${address} from the allowlist?`, { address }))) return; fetch(`/admin/api/insecure-nodes/${id}`, { method: 'DELETE' }) .then(response => response.json()) .then(result => { if (result.success) { alert(apiMessage(result, uiT('ui.admin.insecure_nodes.deleted_success', 'Node deleted successfully'))); loadNodes(); } else { alert(uiT('ui.admin.insecure_nodes.error_prefix', 'Error: ') + apiError(result, uiT('ui.admin.insecure_nodes.delete_failed', 'Failed to delete node'))); } }) .catch(error => { alert(uiT('ui.admin.insecure_nodes.error_prefix', 'Error: ') + error.message); }); } function formatDate(dateStr) { const date = new Date(dateStr); return date.toLocaleString(); } function escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } </script> {% endblock %}