more changes

This commit is contained in:
2025-03-30 16:30:50 -04:00
parent a7679663cc
commit f370666d79
2 changed files with 161 additions and 124 deletions

View File

@@ -563,6 +563,56 @@ def add_user():
except Exception as e: except Exception as e:
return jsonify({'success': False, 'message': 'Unknown error'}), 500 return jsonify({'success': False, 'message': 'Unknown error'}), 500
@app.route('/duplicate_user', methods=['POST'])
def duplicate_user():
"""
Retrieves user data (MAC address, description, VLAN ID) from the database
based on the provided MAC address. This data is intended to be used to
pre-populate a "duplicate user" form in the frontend.
"""
mac_address = request.form['mac_address'] # Get the MAC address from the POST request.
db = get_db() # Get a database connection.
if db:
cursor = db.cursor(dictionary=True) # Create a cursor that returns results as dictionaries.
try:
# Construct the SQL query. This query retrieves the MAC address,
# description, and VLAN ID for the specified user.
cursor.execute("""
SELECT
rc.username AS mac_address,
IFNULL((SELECT value FROM radgroupreply rgr
WHERE rgr.groupname = (SELECT groupname FROM radusergroup rug WHERE rug.username = rc.username LIMIT 1)
AND rgr.attribute = 'Tunnel-Private-Group-Id' LIMIT 1), 'N/A') AS vlan_id,
IFNULL((SELECT value FROM radcheck rch
WHERE rch.username = rc.username AND rch.attribute = 'User-Description' LIMIT 1), 'N/A') AS description
FROM radcheck rc
WHERE rc.username = %s /* %s is a placeholder for the MAC address */
GROUP BY rc.username;
""", (mac_address,)) # Execute the query with the MAC address as a parameter.
user_data = cursor.fetchone() # Fetch the first (and should be only) result.
cursor.close() # Close the cursor.
db.close() # Close the database connection.
if user_data:
# If user data was found, return it as a JSON response.
return jsonify(user_data)
else:
# If no user data was found (e.g., invalid MAC address), return an empty JSON object.
return jsonify({})
except mysql.connector.Error as err:
# Handle database errors. Log the error and return an error message.
print(f"Database Error: {err}")
cursor.close()
db.close()
return jsonify({}) # Return an empty JSON object on error, to avoid crashing.
else:
# Handle the case where the database connection could not be established.
return jsonify({}) # Return empty JSON object
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=8080) app.run(debug=True, host='0.0.0.0', port=8080)

View File

@@ -78,9 +78,36 @@
</dialog> </dialog>
<dialog id="duplicate-dialog"> <dialog id="duplicate-dialog">
<div id="duplicate-dialog-content"></div> <div id="duplicate-dialog-content">
<button id="close-dialog"></button> <table border="1">
<thead>
<tr>
<th>MAC Address</th>
<th>Description</th>
<th>VLAN ID</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" id="dup-mac"></td>
<td><input type="text" id="dup-description"></td>
<td>
<select id="dup-vlan_id">
{% for group in groups %}
<option value="{{ group.groupname }}">
{{ group.groupname }}
</option>
{% endfor %}
</select>
</td>
</tr>
</tbody>
</table>
</div>
<div style="display: flex; justify-content: flex-end; margin-top: 10px;">
<button id="close-duplicate-dialog">Cancel</button>
<button id="save-duplicated-user">Save</button> <button id="save-duplicated-user">Save</button>
</div>
</dialog> </dialog>
<style> <style>
@@ -160,6 +187,7 @@
function duplicateUser(mac_address) { function duplicateUser(mac_address) {
console.log("duplicateUser called with mac_address:", mac_address);
fetch('/duplicate_user', { fetch('/duplicate_user', {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -167,46 +195,39 @@
}, },
body: `mac_address=${mac_address}` body: `mac_address=${mac_address}`
}) })
.then(response => response.json()) .then(response => {
console.log("Response status:", response.status);
console.log("Response text:", response.text());
return response.json()
})
.then(data => { .then(data => {
console.log("Response data:", data);
const userData = data; const userData = data;
let newTable = `<table border="1"> if (userData) {
<thead> document.getElementById('dup-mac').value = userData.mac_address;
<tr> document.getElementById('dup-description').value = userData.description;
<th>MAC Address</th>
<th>Description</th> const vlanSelect = document.getElementById('dup-vlan_id');
<th>VLAN ID</th> vlanSelect.innerHTML = '';
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" id="new-mac" value="${userData.mac_address}"></td>
<td><input type="text" class="new-description" value="${userData.description}"></td>
<td>
<select id="new-vlan_id">
{% for group in groups %} {% for group in groups %}
<option value="{{ group.groupname }}" ${userData.vlan_id === group.groupname ? 'selected' : ''}> let option = document.createElement('option');
{{ group.groupname }} option.value = "{{ group.groupname }}";
</option> option.textContent = "{{ group.groupname }}";
if ("{{ group.groupname }}" === userData.vlan_id) {
option.selected = true;
}
vlanSelect.appendChild(option);
{% endfor %} {% endfor %}
</select>
</td>
</tr>`;
newTable += `<tr>
<td colspan="3" class="merged-cell">
<button onclick="addDuplicatedUserRow(this)"></button>
</td>
</tr></tbody></table>`;
document.getElementById('duplicate-dialog-content').innerHTML = newTable;
document.getElementById('duplicate-dialog').showModal(); document.getElementById('duplicate-dialog').showModal();
} else {
alert("Failed to retrieve user data for duplication.");
}
}); });
}
} }
document.getElementById('close-dialog').addEventListener('click', () => { document.getElementById('close-duplicate-dialog').addEventListener('click', () => {
document.getElementById('duplicate-dialog').close(); document.getElementById('duplicate-dialog').close();
}); });
@@ -215,74 +236,40 @@
}); });
function saveDuplicatedUser() { function saveDuplicatedUser() {
let rows = document.querySelectorAll('#duplicate-dialog-content table tbody tr'); let mac = document.getElementById('dup-mac').value;
let new_mac_address = rows[0].querySelector('#new-mac').value; //changed let description = document.getElementById('dup-description').value;
let attributes = []; let vlan_id = document.getElementById('dup-vlan_id').value;
for (let i = 1; i < rows.length - 1; i++) {
const descriptionInput = rows[i].querySelector(`.new-description`);
const vlanIdInput = rows[i].querySelector(`.new-vlan_id`);
fetch('/add_user', {
if (descriptionInput && vlanIdInput) {
attributes.push({
description: descriptionInput.value,
vlan_id: vlanIdInput.value,
});
} else {
console.warn(`Input elements not found for row ${i}`);
return;
}
}
fetch('/save_duplicated_user', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ mac_address: new_mac_address, attributes: attributes }) //changed body: JSON.stringify({ mac_address: mac, description: description, vlan_id: vlan_id }),
}) })
.then(response => response.text()) .then((response) => {
.then(data => { if (!response.ok) {
if (data === 'success') { return response.text().then((text) => {
throw new Error(`HTTP error! status: ${response.status}, body: ${text}`);
});
}
return response.json();
})
.then((data) => {
console.log("Server response:", data);
if (data && data.success) {
document.getElementById('duplicate-dialog').close(); document.getElementById('duplicate-dialog').close();
location.reload(); location.reload();
} else { } else {
alert('Error saving duplicated user: ' + data); alert("Error adding user: " + (data && data.message ? data.message : "Unknown error"));
} }
})
.catch((error) => {
console.error("Fetch error:", error);
alert("Error adding user: " + error.message);
}); });
} }
function addDuplicatedUserRow(button) {
const table = button.parentNode.parentNode.parentNode; //get the table
const newRow = table.insertRow(table.rows.length - 1);
const cell1 = newRow.insertCell(0);
const cell2 = newRow.insertCell(1);
const cell3 = newRow.insertCell(2);
const cell4 = newRow.insertCell(3);
cell1.classList.add('merged-cell');
cell2.innerHTML = `<input type="text" class="new-description" value="">`;
cell3.innerHTML = `<select class="new-vlan_id">
{% for group in groups %}
<option value="{{ group.groupname }}">
{{ group.groupname }}
</option>
{% endfor %}
</select>`;
cell4.innerHTML = `<button onclick="removeDuplicatedUserRow(this)">🗑️</button>`;
}
function removeDuplicatedUserRow(button) {
const row = button.parentNode.parentNode;
row.parentNode.removeChild(row);
}
function addNewUserRow() { function addNewUserRow() {
document.getElementById('add-user-dialog').showModal(); document.getElementById('add-user-dialog').showModal();
} }