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">
<button id="save-duplicated-user">Save</button> <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>
</div>
</dialog> </dialog>
<style> <style>
@@ -160,53 +187,47 @@
function duplicateUser(mac_address) { function duplicateUser(mac_address) {
fetch('/duplicate_user', { console.log("duplicateUser called with mac_address:", mac_address);
method: 'POST', fetch('/duplicate_user', {
headers: { method: 'POST',
'Content-Type': 'application/x-www-form-urlencoded', headers: {
}, 'Content-Type': 'application/x-www-form-urlencoded',
body: `mac_address=${mac_address}` },
}) body: `mac_address=${mac_address}`
.then(response => response.json()) })
.then(data => { .then(response => {
const userData = data; console.log("Response status:", response.status);
let newTable = `<table border="1"> console.log("Response text:", response.text());
<thead> return response.json()
<tr> })
<th>MAC Address</th> .then(data => {
<th>Description</th> console.log("Response data:", data);
<th>VLAN ID</th> const userData = data;
</tr> if (userData) {
</thead> document.getElementById('dup-mac').value = userData.mac_address;
<tbody> document.getElementById('dup-description').value = userData.description;
<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 %}
<option value="{{ group.groupname }}" ${userData.vlan_id === group.groupname ? 'selected' : ''}>
{{ group.groupname }}
</option>
{% endfor %}
</select>
</td>
</tr>`;
const vlanSelect = document.getElementById('dup-vlan_id');
vlanSelect.innerHTML = '';
{% for group in groups %}
let option = document.createElement('option');
option.value = "{{ group.groupname }}";
option.textContent = "{{ group.groupname }}";
if ("{{ group.groupname }}" === userData.vlan_id) {
option.selected = true;
}
vlanSelect.appendChild(option);
{% endfor %}
document.getElementById('duplicate-dialog').showModal();
newTable += `<tr> } else {
<td colspan="3" class="merged-cell"> alert("Failed to retrieve user data for duplication.");
<button onclick="addDuplicatedUserRow(this)"></button> }
</td> });
</tr></tbody></table>`; }
document.getElementById('duplicate-dialog-content').innerHTML = newTable;
document.getElementById('duplicate-dialog').showModal();
});
} }
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();
} }
@@ -295,7 +282,7 @@
saveNewUser(); saveNewUser();
}); });
function saveNewUser() { function saveNewUser() {
const mac = document.getElementById('new-mac').value; const mac = document.getElementById('new-mac').value;
const description = document.getElementById('new-description').value; const description = document.getElementById('new-description').value;
const vlan_id = document.getElementById('new-vlan_id').value; const vlan_id = document.getElementById('new-vlan_id').value;
@@ -321,28 +308,28 @@
}, },
body: JSON.stringify(userData), // Send the data as a JSON string body: JSON.stringify(userData), // Send the data as a JSON string
}) })
.then(response => { .then(response => {
if (!response.ok) { if (!response.ok) {
// Handle HTTP errors (e.g., 400, 500) // Handle HTTP errors (e.g., 400, 500)
return response.text().then(text => { return response.text().then(text => {
throw new Error(`HTTP error! status: ${response.status}, body: ${text}`); throw new Error(`HTTP error! status: ${response.status}, body: ${text}`);
}); });
} }
return response.json(); // Expect JSON response from server return response.json(); // Expect JSON response from server
}) })
.then(data => { .then(data => {
console.log("Server response:", data); console.log("Server response:", data);
if (data && data.success) { // Check for success property in JSON response if (data && data.success) { // Check for success property in JSON response
document.getElementById('add-user-dialog').close(); document.getElementById('add-user-dialog').close();
location.reload(); location.reload();
} else { } else {
alert('Error adding user: ' + (data && data.message ? data.message : 'Unknown error')); // Show error from server or a generic message alert('Error adding user: ' + (data && data.message ? data.message : 'Unknown error')); // Show error from server or a generic message
} }
}) })
.catch(error => { .catch(error => {
console.error('Fetch error:', error); // Log the error for debugging console.error('Fetch error:', error); // Log the error for debugging
alert('Error adding user: ' + error.message); // Show a user-friendly error message alert('Error adding user: ' + error.message); // Show a user-friendly error message
}); });
} }
</script> </script>
{% endblock %} {% endblock %}