comments added
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
from flask import current_app
|
from flask import current_app, request, redirect, url_for, flash
|
||||||
import mysql.connector
|
import mysql.connector
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
import requests
|
import requests
|
||||||
@@ -7,8 +7,8 @@ import os
|
|||||||
import pytz
|
import pytz
|
||||||
from db_connection import get_connection
|
from db_connection import get_connection
|
||||||
|
|
||||||
|
|
||||||
def get_all_users():
|
def get_all_users():
|
||||||
|
"""Retrieve all users with associated group and vendor information."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
@@ -26,10 +26,8 @@ def get_all_users():
|
|||||||
conn.close()
|
conn.close()
|
||||||
return users
|
return users
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_all_groups():
|
def get_all_groups():
|
||||||
|
"""Retrieve all groups along with user count for each group."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
@@ -44,19 +42,8 @@ def get_all_groups():
|
|||||||
conn.close()
|
conn.close()
|
||||||
return available_groups
|
return available_groups
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_group_by_name(name):
|
|
||||||
conn = get_connection()
|
|
||||||
cursor = conn.cursor(dictionary=True)
|
|
||||||
cursor.execute("SELECT * FROM groups WHERE name = %s", (name,))
|
|
||||||
group = cursor.fetchone()
|
|
||||||
cursor.close()
|
|
||||||
conn.close()
|
|
||||||
return group
|
|
||||||
|
|
||||||
|
|
||||||
def add_group(vlan_id, description):
|
def add_group(vlan_id, description):
|
||||||
|
"""Insert a new group with a specified VLAN ID and description."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("INSERT INTO groups (vlan_id, description) VALUES (%s, %s)", (vlan_id, description))
|
cursor.execute("INSERT INTO groups (vlan_id, description) VALUES (%s, %s)", (vlan_id, description))
|
||||||
@@ -64,8 +51,8 @@ def add_group(vlan_id, description):
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def update_group_description(vlan_id, description):
|
def update_group_description(vlan_id, description):
|
||||||
|
"""Update the description for a given MAC address in the users table."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("UPDATE groups SET description = %s WHERE vlan_id = %s", (description, vlan_id))
|
cursor.execute("UPDATE groups SET description = %s WHERE vlan_id = %s", (description, vlan_id))
|
||||||
@@ -73,17 +60,24 @@ def update_group_description(vlan_id, description):
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
def delete_group(vlan_id, force_delete=False):
|
||||||
def delete_group(vlan_id):
|
"""Delete a group, and optionally its associated users if force_delete=True."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("DELETE FROM groups WHERE vlan_id = %s", (vlan_id,))
|
try:
|
||||||
conn.commit()
|
if force_delete:
|
||||||
cursor.close()
|
cursor.execute("DELETE FROM users WHERE vlan_id = %s", (vlan_id,))
|
||||||
conn.close()
|
cursor.execute("DELETE FROM groups WHERE vlan_id = %s", (vlan_id,))
|
||||||
|
conn.commit()
|
||||||
|
except mysql.connector.IntegrityError as e:
|
||||||
|
print(f"❌ Cannot delete group '{vlan_id}': it is still in use. Error: {e}")
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
def duplicate_group(vlan_id):
|
def duplicate_group(vlan_id):
|
||||||
|
"""Create a duplicate of a group with an incremented VLAN ID."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
cursor.execute("SELECT vlan_id, description FROM groups WHERE vlan_id = %s", (vlan_id,))
|
cursor.execute("SELECT vlan_id, description FROM groups WHERE vlan_id = %s", (vlan_id,))
|
||||||
@@ -98,8 +92,8 @@ def duplicate_group(vlan_id):
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def add_user(mac_address, description, vlan_id):
|
def add_user(mac_address, description, vlan_id):
|
||||||
|
"""Insert a new user with MAC address, description, and VLAN assignment."""
|
||||||
print(f"→ Adding to DB: mac={mac_address}, desc={description}, vlan={vlan_id}")
|
print(f"→ Adding to DB: mac={mac_address}, desc={description}, vlan={vlan_id}")
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
@@ -111,8 +105,8 @@ def add_user(mac_address, description, vlan_id):
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def update_user_description(mac_address, description):
|
def update_user_description(mac_address, description):
|
||||||
|
"""Update the description field of a user identified by MAC address."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("UPDATE users SET description = %s WHERE mac_address = %s", (description, mac_address.lower()))
|
cursor.execute("UPDATE users SET description = %s WHERE mac_address = %s", (description, mac_address.lower()))
|
||||||
@@ -120,8 +114,8 @@ def update_user_description(mac_address, description):
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def update_user_vlan(mac_address, vlan_id):
|
def update_user_vlan(mac_address, vlan_id):
|
||||||
|
"""Update the VLAN ID for a given MAC address in the users table."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("UPDATE users SET vlan_id = %s WHERE mac_address = %s", (vlan_id, mac_address.lower()))
|
cursor.execute("UPDATE users SET vlan_id = %s WHERE mac_address = %s", (vlan_id, mac_address.lower()))
|
||||||
@@ -129,8 +123,8 @@ def update_user_vlan(mac_address, vlan_id):
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def delete_user(mac_address):
|
def delete_user(mac_address):
|
||||||
|
"""Remove a user from the database by their MAC address."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("DELETE FROM users WHERE mac_address = %s", (mac_address.lower(),))
|
cursor.execute("DELETE FROM users WHERE mac_address = %s", (mac_address.lower(),))
|
||||||
@@ -138,8 +132,8 @@ def delete_user(mac_address):
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
def get_latest_auth_logs(reply_type=None, limit=5, time_range=None, offset=0):
|
def get_latest_auth_logs(reply_type=None, limit=5, time_range=None, offset=0):
|
||||||
|
"""Retrieve recent authentication logs filtered by reply type and time range."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
|
||||||
@@ -181,6 +175,7 @@ def get_latest_auth_logs(reply_type=None, limit=5, time_range=None, offset=0):
|
|||||||
return logs
|
return logs
|
||||||
|
|
||||||
def count_auth_logs(reply_type=None, time_range=None):
|
def count_auth_logs(reply_type=None, time_range=None):
|
||||||
|
"""Count the number of authentication logs matching a reply type and time."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
@@ -218,6 +213,7 @@ def count_auth_logs(reply_type=None, time_range=None):
|
|||||||
return count
|
return count
|
||||||
|
|
||||||
def get_summary_counts():
|
def get_summary_counts():
|
||||||
|
"""Return total counts of users and groups from the database."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
|
||||||
@@ -232,6 +228,7 @@ def get_summary_counts():
|
|||||||
return total_users, total_groups
|
return total_users, total_groups
|
||||||
|
|
||||||
def update_description(mac_address, description):
|
def update_description(mac_address, description):
|
||||||
|
"""Update the description for a given MAC address in the users table."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
@@ -243,6 +240,7 @@ def update_description(mac_address, description):
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def update_vlan(mac_address, vlan_id):
|
def update_vlan(mac_address, vlan_id):
|
||||||
|
"""Update the VLAN ID for a given MAC address in the users table."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
@@ -254,6 +252,7 @@ def update_vlan(mac_address, vlan_id):
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def refresh_vendors():
|
def refresh_vendors():
|
||||||
|
"""Fetch and cache vendor info for unknown MAC prefixes using the API."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
|
||||||
@@ -328,6 +327,7 @@ def refresh_vendors():
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def lookup_mac_verbose(mac):
|
def lookup_mac_verbose(mac):
|
||||||
|
"""Look up vendor info for a MAC with verbose output, querying API if needed."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
output = []
|
output = []
|
||||||
@@ -382,6 +382,7 @@ def lookup_mac_verbose(mac):
|
|||||||
return "\n".join(output)
|
return "\n".join(output)
|
||||||
|
|
||||||
def get_user_by_mac(mac_address):
|
def get_user_by_mac(mac_address):
|
||||||
|
"""Retrieve a user record from the database by MAC address."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
|
||||||
@@ -394,6 +395,7 @@ def get_user_by_mac(mac_address):
|
|||||||
return user
|
return user
|
||||||
|
|
||||||
def get_known_mac_vendors():
|
def get_known_mac_vendors():
|
||||||
|
"""Fetch all known MAC prefixes and their vendor info from the local database."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
cursor.execute("SELECT mac_prefix, vendor_name, status FROM mac_vendors")
|
cursor.execute("SELECT mac_prefix, vendor_name, status FROM mac_vendors")
|
||||||
@@ -410,6 +412,7 @@ def get_known_mac_vendors():
|
|||||||
}
|
}
|
||||||
|
|
||||||
def get_vendor_info(mac, insert_if_found=True):
|
def get_vendor_info(mac, insert_if_found=True):
|
||||||
|
"""Get vendor info for a MAC address, optionally inserting into the database."""
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
cursor = conn.cursor(dictionary=True)
|
cursor = conn.cursor(dictionary=True)
|
||||||
prefix = mac.lower().replace(":", "").replace("-", "")[:6]
|
prefix = mac.lower().replace(":", "").replace("-", "")[:6]
|
||||||
@@ -522,3 +525,45 @@ def get_vendor_info(mac, insert_if_found=True):
|
|||||||
cursor.close()
|
cursor.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
def delete_group_route():
|
||||||
|
"""Handle deletion of a group and optionally its users via form POST."""
|
||||||
|
vlan_id = request.form.get("group_id")
|
||||||
|
force = request.form.get("force_delete") == "true"
|
||||||
|
|
||||||
|
conn = get_connection()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
cursor.execute("SELECT COUNT(*) FROM users WHERE vlan_id = %s", (vlan_id,))
|
||||||
|
user_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
if user_count > 0 and not force:
|
||||||
|
conn.close()
|
||||||
|
flash("Group has users. Please confirm deletion or reassign users.", "error")
|
||||||
|
return redirect(url_for("group.group_list"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if force:
|
||||||
|
cursor.execute("DELETE FROM users WHERE vlan_id = %s", (vlan_id,))
|
||||||
|
|
||||||
|
cursor.execute("DELETE FROM groups WHERE vlan_id = %s", (vlan_id,))
|
||||||
|
conn.commit()
|
||||||
|
flash(f"Group {vlan_id} and associated users deleted." if force else f"Group {vlan_id} deleted.", "success")
|
||||||
|
except mysql.connector.IntegrityError as e:
|
||||||
|
flash(f"Cannot delete group {vlan_id}: it is still in use. Error: {e}", "error")
|
||||||
|
except Exception as e:
|
||||||
|
flash(f"Error deleting group: {e}", "error")
|
||||||
|
finally:
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
return redirect(url_for("group.group_list"))
|
||||||
|
|
||||||
|
def get_users_by_vlan_id(vlan_id):
|
||||||
|
"""Fetch users assigned to a specific VLAN ID."""
|
||||||
|
conn = get_connection()
|
||||||
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
cursor.execute("SELECT mac_address, description FROM users WHERE vlan_id = %s", (vlan_id,))
|
||||||
|
users = cursor.fetchall()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
return users
|
||||||
@@ -317,3 +317,88 @@ form.inline-form {
|
|||||||
background-color: var(--accent);
|
background-color: var(--accent);
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
z-index: 10000;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-card {
|
||||||
|
background: var(--card-bg);
|
||||||
|
color: var(--fg);
|
||||||
|
padding: 2rem;
|
||||||
|
border-radius: 10px;
|
||||||
|
max-width: 500px;
|
||||||
|
width: 90%;
|
||||||
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions button,
|
||||||
|
.modal-actions form button {
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions button {
|
||||||
|
background-color: #ccc;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions button.danger {
|
||||||
|
background-color: var(--error);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 10000;
|
||||||
|
left: 0; top: 0;
|
||||||
|
width: 100%; height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background: var(--card-bg);
|
||||||
|
padding: 1.5rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--fg);
|
||||||
|
width: 500px;
|
||||||
|
max-height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
box-shadow: 0 0 15px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-actions {
|
||||||
|
margin-top: 1rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-list {
|
||||||
|
margin-top: 1rem;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #555;
|
||||||
|
padding: 0.5rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
background: var(--cell-bg);
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<input type="hidden" name="description" value="{{ group.description }}">
|
<input type="hidden" name="description" value="{{ group.description }}">
|
||||||
<button type="submit" title="Save">💾</button>
|
<button type="submit" title="Save">💾</button>
|
||||||
</form>
|
</form>
|
||||||
<form method="POST" action="{{ url_for('group.delete_group_route') }}" class="preserve-scroll" style="display:inline;" onsubmit="return confirm('Delete this group?');">
|
<form method="POST" action="{{ url_for('group.delete_group_route_handler') }}" class="preserve-scroll delete-group-form" data-user-count="{{ group.user_count }}" style="display:inline;">
|
||||||
<input type="hidden" name="group_id" value="{{ group.vlan_id }}">
|
<input type="hidden" name="group_id" value="{{ group.vlan_id }}">
|
||||||
<button type="submit">❌</button>
|
<button type="submit">❌</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -46,6 +46,22 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<!-- Modal for confirm delete -->
|
||||||
|
<div id="confirmModal" class="modal" style="display: none;">
|
||||||
|
<div class="modal-content">
|
||||||
|
<p>This group has users assigned. What would you like to do?</p>
|
||||||
|
<div id="userList" class="user-list"></div>
|
||||||
|
<div class="modal-actions">
|
||||||
|
<button onclick="closeModal()">Cancel</button>
|
||||||
|
<form id="confirmDeleteForm" method="POST" action="{{ url_for('group.delete_group_route_handler') }}">
|
||||||
|
<input type="hidden" name="group_id" id="modalGroupId">
|
||||||
|
<input type="hidden" name="force_delete" value="true">
|
||||||
|
<button type="submit" class="danger">Delete Group and Users</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.querySelectorAll('form.preserve-scroll').forEach(form => {
|
document.querySelectorAll('form.preserve-scroll').forEach(form => {
|
||||||
form.addEventListener('submit', () => {
|
form.addEventListener('submit', () => {
|
||||||
@@ -59,5 +75,47 @@
|
|||||||
localStorage.removeItem('scrollY');
|
localStorage.removeItem('scrollY');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.delete-group-form').forEach(form => {
|
||||||
|
form.addEventListener('submit', function (e) {
|
||||||
|
const userCount = parseInt(this.dataset.userCount);
|
||||||
|
const groupId = this.querySelector('[name="group_id"]').value;
|
||||||
|
|
||||||
|
if (userCount > 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
fetch('{{ url_for("group.get_users_for_group") }}', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||||
|
body: new URLSearchParams({ vlan_id: groupId })
|
||||||
|
})
|
||||||
|
.then(resp => resp.json())
|
||||||
|
.then(users => {
|
||||||
|
const userListDiv = document.getElementById('userList');
|
||||||
|
userListDiv.innerHTML = '';
|
||||||
|
|
||||||
|
if (users.length > 0) {
|
||||||
|
const list = document.createElement('ul');
|
||||||
|
users.forEach(user => {
|
||||||
|
const item = document.createElement('li');
|
||||||
|
item.textContent = `${user.mac_address} — ${user.description || 'No description'}`;
|
||||||
|
list.appendChild(item);
|
||||||
|
});
|
||||||
|
userListDiv.appendChild(list);
|
||||||
|
} else {
|
||||||
|
userListDiv.textContent = 'No users found in this group.';
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('modalGroupId').value = groupId;
|
||||||
|
document.getElementById('confirmModal').style.display = 'flex';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!confirm('Delete this group?')) e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function closeModal() {
|
||||||
|
document.getElementById('confirmModal').style.display = 'none';
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -128,9 +128,11 @@
|
|||||||
<select name="group_id" required>
|
<select name="group_id" required>
|
||||||
<option value="">Assign to VLAN</option>
|
<option value="">Assign to VLAN</option>
|
||||||
{% for group in available_groups %}
|
{% for group in available_groups %}
|
||||||
<option value="{{ group.vlan_id }}">VLAN {{ group.vlan_id }}</option>
|
<option value="{{ group.vlan_id }}">
|
||||||
|
VLAN {{ group.vlan_id }}{% if group.description %} - {{ group.description }}{% endif %}
|
||||||
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<button type="submit" title="Add">💾</button>
|
<button type="submit" title="Add">💾</button>
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<select name="group_id" required>
|
<select name="group_id" required>
|
||||||
<option value="">Assign to VLAN</option>
|
<option value="">Assign to VLAN</option>
|
||||||
{% for group in available_groups %}
|
{% for group in available_groups %}
|
||||||
<option value="{{ group.vlan_id }}">VLAN {{ group.vlan_id }}</option>
|
<option value="{{ group.vlan_id }}">VLAN {{ group.vlan_id }}{% if group.description %} - {{ group.description }}{% endif %}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<button type="submit">➕ Add</button>
|
<button type="submit">➕ Add</button>
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
<select name="group_id" onchange="this.form.submit()">
|
<select name="group_id" onchange="this.form.submit()">
|
||||||
{% for group in available_groups %}
|
{% for group in available_groups %}
|
||||||
<option value="{{ group.vlan_id }}" {% if group.vlan_id == entry.vlan_id %}selected{% endif %}>
|
<option value="{{ group.vlan_id }}" {% if group.vlan_id == entry.vlan_id %}selected{% endif %}>
|
||||||
VLAN {{ group.vlan_id }}
|
VLAN {{ group.vlan_id }}{% if group.description %} - {{ group.description }}{% endif %}
|
||||||
</option>
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
from flask import Blueprint, render_template, request, redirect, url_for
|
from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify
|
||||||
from db_interface import get_all_groups, add_group, update_group_description, delete_group
|
from db_interface import get_all_groups, add_group, update_group_description, delete_group_route, get_users_by_vlan_id
|
||||||
|
|
||||||
group = Blueprint('group', __name__, url_prefix='/group')
|
group = Blueprint('group', __name__, url_prefix='/group')
|
||||||
|
|
||||||
@@ -27,7 +27,11 @@ def update_description_route():
|
|||||||
|
|
||||||
|
|
||||||
@group.route('/delete', methods=['POST'])
|
@group.route('/delete', methods=['POST'])
|
||||||
def delete_group_route():
|
def delete_group_route_handler():
|
||||||
group_id = request.form['group_id']
|
return delete_group_route()
|
||||||
delete_group(group_id)
|
|
||||||
return redirect(url_for('group.group_list'))
|
@group.route('/get_users_for_group', methods=['POST'])
|
||||||
|
def get_users_for_group():
|
||||||
|
vlan_id = request.form.get('vlan_id')
|
||||||
|
users = get_users_by_vlan_id(vlan_id)
|
||||||
|
return jsonify(users)
|
||||||
@@ -5,6 +5,7 @@ from db_interface import (
|
|||||||
get_vendor_info,
|
get_vendor_info,
|
||||||
get_latest_auth_logs,
|
get_latest_auth_logs,
|
||||||
get_all_groups,
|
get_all_groups,
|
||||||
|
lookup_mac_verbose,
|
||||||
)
|
)
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user